source: gsdl/trunk/runtime-src/src/w32server/cgiwrapper.cpp@ 19062

Last change on this file since 19062 was 19062, checked in by kjdon, 15 years ago

all gdbm files (key, users, history, argdb) now use gdb extension instead of db

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 30.0 KB
Line 
1/**********************************************************************
2 *
3 * cgiwrapper.cpp -- windows local library cgiwrapper
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "text_t.h"
27
28#include <windows.h>
29#include <string.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <assert.h>
33#include <direct.h>
34#include "cgiwrapper.h"
35#include "netio.h"
36#include "wincgiutils.h"
37#include "settings.h"
38#include "fileutil.h"
39#include "parse.h"
40
41#include "gsdlconf.h"
42#include "maincfg.h"
43
44#if defined (GSDL_USE_OBJECTSPACE)
45#include <ospace\std\iostream>
46#include <ospace\std\fstream>
47#elif defined (GSDL_USE_IOS_H)
48#include <iostream.h>
49#include <fstream.h>
50#else
51#include <iostream>
52#include <fstream>
53#endif
54
55#include "receptionist.h"
56#include "nullproto.h"
57
58// actions
59#include "statusaction.h"
60#include "pageaction.h"
61#include "pingaction.h"
62#include "queryaction.h"
63#include "documentaction.h"
64#include "dynamicclassifieraction.h"
65#include "tipaction.h"
66#include "authenaction.h"
67#include "usersaction.h"
68#include "userdb.h"
69#include "extlinkaction.h"
70#include "collectoraction.h"
71#include "phindaction.h"
72#include "configaction.h"
73
74// browsers
75#include "vlistbrowserclass.h"
76#include "hlistbrowserclass.h"
77#include "datelistbrowserclass.h"
78#include "invbrowserclass.h"
79#include "pagedbrowserclass.h"
80#include "htmlbrowserclass.h"
81#include "phindbrowserclass.h"
82
83// the number of times the library has been accessed
84int libaccessnum = 0;
85
86// used to output the text from receptionist
87class textstreambuf : public streambuf
88{
89public:
90 textstreambuf ();
91 int sync ();
92 int overflow (int ch);
93 int underflow () {return EOF;}
94
95 void tsbreset() {RInfo=NULL;casostr=NULL;}
96 void setrequestinfo (RequestInfoT *theRInfo) {RInfo=theRInfo;}
97 void cascadeoutput (ostream *thecasostr) {casostr=thecasostr;}
98
99private:
100 RequestInfoT *RInfo;
101 ostream *casostr;
102#if !defined (GSDL_USE_IOS_H)
103 char buffer[256];
104#endif
105};
106
107textstreambuf::textstreambuf() {
108 tsbreset();
109#if !defined (GSDL_USE_IOS_H)
110 setp (&buffer[0], &buffer[255]);
111#else
112 if (base() == ebuf()) allocate();
113 setp (base(), ebuf());
114#endif
115};
116
117int textstreambuf::sync () {
118 if ((RInfo != NULL) &&
119 (Send_String_N(pbase(), pptr()-pbase(), RInfo) < 0)) {
120 RInfo = NULL;
121 }
122
123 if (casostr != NULL) {
124 char *thepbase=pbase();
125 for (int i=0;i<(pptr()-pbase());++i) (*casostr).put(thepbase[i]);
126 }
127
128 setp (pbase(), epptr());
129
130 return 0;
131}
132
133int textstreambuf::overflow (int ch) {
134 if (sync () == EOF) return EOF;
135 if (ch != EOF) sputc (ch);
136 return 0;
137}
138
139
140// used to output all the log and error messages
141// from receptionist
142class logstreambuf : public streambuf
143{
144public:
145 logstreambuf ();
146 int sync ();
147 int overflow (int ch);
148 int underflow () {return EOF;}
149
150#if !defined (GSDL_USE_IOS_H)
151private:
152 char buffer[256];
153#endif
154};
155
156logstreambuf::logstreambuf () {
157#if !defined (GSDL_USE_IOS_H)
158 setp (&buffer[0], &buffer[255]);
159#else
160 if (base() == ebuf()) allocate();
161 setp (base(), ebuf());
162#endif
163}
164
165int logstreambuf::sync () {
166 if (gsdl_keep_log || gsdl_show_console) {
167 log_message ("LOCAL LIB MESSAGE: ");
168 log_message_N (pbase(), pptr()-pbase());
169 }
170
171 setp (pbase(), epptr());
172 return 0;
173}
174
175int logstreambuf::overflow (int ch) {
176 if (sync () == EOF) return EOF;
177 if (ch != EOF) sputc (ch);
178 return 0;
179}
180
181static void page_errormaincfg (const text_t &gsdlhome, const text_t &collection) {
182
183 if (collection.empty()) {
184 text_t message = "Error\n\n"
185 "The main.cfg configuration file could not be found. This file\n"
186 "should contain configuration information relating to the\n"
187 "setup of the interface. As this program is not being run\n"
188 "in collection specific mode the file should reside at\n" +
189 gsdlhome + "\\etc\\main.cfg.\n";
190
191 MessageBox(NULL, message.getcstr(),
192 "Greenstone Digital Library Software"
193 ,MB_OK|MB_SYSTEMMODAL);
194 } else {
195 text_t message = "Neither the collect.cfg or main.cfg configuration files could\n"
196 "be found. This file should contain configuration information\n"
197 "relating to the setup of the interface. As this cgi script is\n"
198 "being run in collection specific mode the file should reside\n"
199 "at either " + gsdlhome + "\\collect\\" + collection + "\\etc\\collect.cfg,\n" +
200 gsdlhome + "\\etc\\collect.cfg or " + gsdlhome + "\\etc\\main.cfg.\n";
201
202 MessageBox(NULL, message.getcstr(),
203 "Greenstone Digital Library Software"
204 ,MB_OK|MB_SYSTEMMODAL);
205 }
206}
207
208static void page_errorinit (const text_t &/*gsdlhome*/) {
209
210 text_t message = "Error\n\n"
211 "An error occurred during the initialisation of the Greenstone Digital\n"
212 "Library software. It is likely that the software has not been setup\n"
213 "correctly.\n";
214
215 MessageBox(NULL, message.getcstr(),
216 "Greenstone Digital Library Software"
217 ,MB_OK|MB_SYSTEMMODAL);
218}
219
220static void page_errorparseargs (const text_t &/*gsdlhome*/) {
221
222 text_t message = "Error\n\n"
223 "An error occurred during the parsing of the cgi arguments.\n";
224
225 MessageBox(NULL, message.getcstr(),
226 "Greenstone Digital Library Software"
227 ,MB_OK|MB_SYSTEMMODAL);
228}
229
230static void page_errorcgipage (const text_t &/*gsdlhome*/) {
231
232 text_t message = "Error\n\n"
233 "An error occurred during the construction of the cgi page.\n";
234
235 MessageBox(NULL, message.getcstr(),
236 "Greenstone Digital Library Software"
237 ,MB_OK|MB_SYSTEMMODAL);
238}
239
240// returns 0 if the directories can't be found
241// and the user wants to quit (it returns 1
242// if everything is ok)
243int checkdir (const text_t &thedir) {
244 UINT curerrormode;
245 int drive = _getdrive();
246 char cwd[1024];
247 char rootpath[4];
248 UINT drivetype;
249 char *cstrthedir = thedir.getcstr();
250 int returnvalue = 1;
251
252 // make sure no rude error messages are presented to the user
253 curerrormode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
254
255 // get the drive name
256 if (thedir.size() >= 2 && thedir[1] == ':') {
257 if (thedir[0] >= 'a' && thedir[0] <= 'z') {
258 drive = thedir[0] - 'a' + 1;
259
260 } else if (thedir[0] >= 'A' && thedir[0] <= 'Z') {
261 drive = thedir[0] - 'A' + 1;
262 }
263 }
264
265 // find the drive type
266 rootpath[0] = drive + 'A' - 1;
267 rootpath[1] = ':';
268 rootpath[2] = '\\';
269 rootpath[3] = '\0';
270 drivetype = GetDriveType (rootpath);
271
272 // try and set this directory to be the current working
273 // directory
274 _getcwd(cwd, 1024);
275 while (_chdir(cstrthedir) != 0) {
276 // failed
277 if (drivetype == DRIVE_CDROM) {
278 // message to insert the cdrom
279 if (MessageBox (NULL,
280 "Please insert the Greenstone Digital Library\n"
281 "CD-ROM into the CD-ROM drive and press 'OK'.\n\n"
282 "If you don't have the CD-ROM press 'Cancel' to exit\n"
283 "this program.", "Greenstone Digital Library Software",
284 MB_OKCANCEL | MB_TASKMODAL) == IDCANCEL) {
285
286 returnvalue = 0;
287 break;
288 }
289
290 } else {
291 // message saying that the system was unable
292 // to find a certain directory
293 text_t message = "Failed to find the directory:\n\n" + thedir;
294 message += "\n\n"
295 "This directory is needed for the successful operation\n"
296 "of this software. Make sure it hasn't been deleted or\n"
297 "moved, and restart the software. You may need to\n"
298 "reinstall this software to correct the problem.";
299 char *cstrmessage = message.getcstr();
300
301 MessageBox (NULL, cstrmessage, "Greenstone Digital Library Software",
302 MB_OK | MB_TASKMODAL);
303
304 delete []cstrmessage;
305
306 returnvalue = 0;
307 break;
308 }
309 }
310
311 // revert to the previous error and cwd states
312 _chdir(cwd);
313 SetErrorMode(curerrormode);
314
315 // free the allocated C string
316 delete []cstrthedir;
317
318 return returnvalue;
319}
320
321
322// c-string version of checkdir for the outside
323// world
324int cstrcheckdir (char *cstrthedir) {
325 return checkdir (cstrthedir);
326}
327
328
329receptionist recpt;
330nullproto nproto;
331collectset *cservers = NULL;
332
333textstreambuf textstream;
334logstreambuf logstream;
335DWORD lastlibaccesstime;
336DWORD baseavailvirtual;
337text_t current_gsdlhome;
338text_t current_collecthome;
339colinfo_tmap translated_collectinfo;
340
341statusaction *astatusaction = NULL;
342pageaction *apageaction = NULL;
343pingaction *apingaction = NULL;
344tipaction *atipaction = NULL;
345queryaction *aqueryaction = NULL;
346documentaction *adocumentaction = NULL;
347dynamicclassifieraction *adynamicclassifieraction = NULL;
348usersaction *ausersaction = NULL;
349extlinkaction *anextlinkaction = NULL;
350collectoraction *acollectoraction = NULL;
351authenaction *aauthenaction = NULL;
352phindaction *aphindaction = NULL;
353configaction *aconfigaction = NULL;
354vlistbrowserclass *avlistbrowserclass = NULL;
355hlistbrowserclass *ahlistbrowserclass = NULL;
356datelistbrowserclass *adatelistbrowserclass = NULL;
357invbrowserclass *ainvbrowserclass = NULL;
358pagedbrowserclass *apagedbrowserclass = NULL;
359htmlbrowserclass *ahtmlbrowserclass = NULL;
360phindbrowserclass *aphindbrowserclass = NULL;
361text_t userdbfile = NULL;
362userdbclass *udb = NULL;
363text_t keydbfile = NULL;
364keydbclass *kdb = NULL;
365
366// returns 1 if successful, 0 if unsuccessful (note that as well as being
367// called when the server first starts up this function is called when the
368// "restart library" button is pressed)
369int gsdl_init (bool atStartup) {
370
371 if (atStartup) {
372#if defined (GSDL_USE_IOS_H)
373 cerr = &logstream;
374 cout = &textstream;
375#else
376 cerr.rdbuf(&logstream);
377 cout.rdbuf(&textstream);
378#endif
379 }
380
381 // collection should be set to "" unless in collection specific mode -
382 // changing this to the name of the collection should be all that's
383 // required to create a collection specific receptionist
384 text_t collection = "";
385 text_tset dbhomes;
386 text_tset clhomes; // collecthome companion for dbhome
387 text_tset collections;
388
389 if (atStartup) {
390 // note the current time
391 lastlibaccesstime = GetTickCount();
392
393 // before we do the init we should make sure
394 // that we can find the relevant directories
395 if (!checkdir (gsdl_gsdlhome + "\\")) return 0;
396 if (!checkdir (gsdl_collecthome + "\\")) return 0;
397 if (!checkdir (gsdl_gsdlhome + "\\macros\\")) return 0;
398 }
399
400 // deleting cservers clears all the collection servers
401 if (cservers != NULL) delete cservers;
402
403 cservers = new collectset();
404
405 // get all collections from each gsdlhome (this relies
406 // on there not being more than one collection with the same
407 // name)
408 if (!collection.empty()) {
409 // collection specific receptionist - one collection, one gsdlhome
410 collections.insert (collection);
411 dbhomes.insert (gsdl_dbhome);
412 clhomes.insert (gsdl_collecthome);
413 collectioninfo_t tmp;
414 tmp.gsdl_gsdlhome = gsdl_gsdlhome;
415 tmp.gsdl_collecthome = gsdl_collecthome;
416 tmp.gsdl_dbhome = gsdl_dbhome;
417 translated_collectinfo[collection] = tmp;
418
419 } else {
420
421 text_tset::const_iterator colhere;
422 text_tset::const_iterator colend;
423 text_tset these_collections;
424
425 // first volume gsdlhome's
426 colinfo_tmap::const_iterator this_info = gsdl_collectinfo.begin();
427 colinfo_tmap::const_iterator end_info = gsdl_collectinfo.end();
428 while (this_info != end_info) {
429 if (dbhomes.find ((*this_info).second.gsdl_dbhome) == dbhomes.end()) {
430 these_collections.erase (these_collections.begin(), these_collections.end());
431 read_dir ((*this_info).second.gsdl_collecthome, these_collections);
432 colhere = these_collections.begin();
433 colend = these_collections.end();
434 while (colhere != colend) {
435 if ((collections.find (*colhere)) == collections.end()) {
436 // make sure the build.cfg file is at gsdlhome (as it's possible that
437 // the collection appears at this gsdlhome only because it's gdbm
438 // file is installed here -- it's real gdbm will therefore be
439 // somewhere else).
440 text_t build_cfg = filename_cat ((*this_info).second.gsdl_collecthome,
441 *colhere, "index", "build.cfg");
442 if (file_exists (build_cfg)) {
443 collections.insert (*colhere);
444
445 // since gsdl_collectinfo keys will be stuff like collection#1
446 // for a multiple volume collection we want to translate it
447 // so that the keys are the actual collection names
448 translated_collectinfo[*colhere] = (*this_info).second;
449 }
450 }
451 ++colhere;
452 }
453 dbhomes.insert ((*this_info).second.gsdl_dbhome);
454 clhomes.insert ((*this_info).second.gsdl_collecthome);
455 }
456 ++this_info;
457 }
458
459 // then if necessary the main dbhome (this should only happen if the
460 // gsdl.ini is a little screwed up and no volume dbhomes occurred)
461 if (dbhomes.find (gsdl_dbhome) == dbhomes.end()) {
462 these_collections.erase (these_collections.begin(), these_collections.end());
463 read_dir (filename_cat (gsdl_dbhome, "collect"), these_collections);
464 colhere = these_collections.begin();
465 colend = these_collections.end();
466 while (colhere != colend) {
467 collections.insert (*colhere);
468 collectioninfo_t tmp;
469 tmp.gsdl_gsdlhome = gsdl_gsdlhome;
470 tmp.gsdl_collecthome = gsdl_collecthome;
471 tmp.gsdl_dbhome = gsdl_dbhome;
472 translated_collectinfo[*colhere] = tmp;
473 ++colhere;
474 }
475 dbhomes.insert (gsdl_dbhome);
476 clhomes.insert (gsdl_collecthome);
477 }
478 }
479
480 text_tset::const_iterator thiscol = collections.begin();
481 text_tset::const_iterator endcol = collections.end();
482
483 while (thiscol != endcol) {
484
485 // ignore the modelcol
486 if (*thiscol == "modelcol") {
487 ++thiscol;
488 continue;
489 }
490
491 // create collection server and add to null protocol
492 text_t this_gsdlhome = gsdl_gsdlhome;
493 text_t this_collecthome = gsdl_collecthome;
494 text_t this_dbhome = gsdl_dbhome;
495 colinfo_tmap::const_iterator it = translated_collectinfo.find (*thiscol);
496 assert (it != translated_collectinfo.end());
497 this_gsdlhome = (*it).second.gsdl_gsdlhome;
498 this_collecthome = (*it).second.gsdl_collecthome;
499 this_dbhome = (*it).second.gsdl_dbhome;
500
501 cservers->add_collection (*thiscol, this_gsdlhome, this_collecthome);
502 // in case it is a collection group
503 cservers->add_collection_group(*thiscol, this_gsdlhome, this_collecthome);
504
505 ++thiscol;
506 }
507
508 // set up the null protocol
509 nproto.set_collectset(cservers);
510
511 if ((ausersaction == NULL) && (aauthenaction == NULL)){
512 userdbfile = filename_cat(gsdl_gsdlhome, "etc", "users.gdb");
513 udb = new userdbclass(userdbfile);
514 keydbfile = filename_cat(gsdl_gsdlhome, "etc", "key.gdb");
515 kdb = new keydbclass(keydbfile);
516 }
517 // add the protocol to the receptionist
518 if (atStartup) recpt.add_protocol (&nproto);
519
520 // the list of actions.
521 if (astatusaction == NULL) {
522 astatusaction = new statusaction();
523 astatusaction->set_receptionist (&recpt);
524 recpt.add_action (astatusaction);
525 }
526
527 if (apageaction == NULL) {
528 apageaction = new pageaction();
529 apageaction->set_receptionist (&recpt);
530 recpt.add_action (apageaction);
531 }
532
533 if (apingaction == NULL) {
534 apingaction = new pingaction();
535 recpt.add_action (apingaction);
536 }
537
538 if (atipaction == NULL) {
539 atipaction = new tipaction();
540 recpt.add_action (atipaction);
541 }
542
543 if (aqueryaction == NULL) {
544 aqueryaction = new queryaction();
545 aqueryaction->set_receptionist (&recpt);
546 recpt.add_action (aqueryaction);
547 }
548
549 if (adocumentaction == NULL) {
550 adocumentaction = new documentaction();
551 adocumentaction->set_receptionist (&recpt);
552 recpt.add_action (adocumentaction);
553 }
554
555 if (ausersaction == NULL) {
556 ausersaction = new usersaction();
557 ausersaction->set_userdb(udb);
558 recpt.add_action (ausersaction);
559 }
560
561 if (anextlinkaction == NULL) {
562 anextlinkaction = new extlinkaction();
563 recpt.add_action (anextlinkaction);
564 }
565
566 if (acollectoraction == NULL) {
567 acollectoraction = new collectoraction();
568 acollectoraction->set_receptionist (&recpt);
569 recpt.add_action (acollectoraction);
570 }
571
572 if (aauthenaction == NULL) {
573 aauthenaction = new authenaction();
574 aauthenaction->set_userdb(udb);
575 aauthenaction->set_keydb(kdb);
576 aauthenaction->set_receptionist(&recpt);
577 recpt.add_action (aauthenaction);
578 }
579
580 if (aphindaction == NULL) {
581 aphindaction = new phindaction();
582 recpt.add_action (aphindaction);
583 }
584
585 if (aconfigaction == NULL) {
586 aconfigaction = new configaction();
587 aconfigaction->set_receptionist(&recpt);
588 recpt.add_action (aconfigaction);
589 }
590
591 if (adynamicclassifieraction == NULL) {
592 adynamicclassifieraction = new dynamicclassifieraction();
593 adynamicclassifieraction->set_receptionist(&recpt);
594 recpt.add_action (adynamicclassifieraction);
595 }
596
597
598 // list of browsers
599 if (avlistbrowserclass == NULL) {
600 avlistbrowserclass = new vlistbrowserclass();
601 recpt.add_browser (avlistbrowserclass);
602 recpt.setdefaultbrowser ("VList");
603 }
604
605 if (ahlistbrowserclass == NULL) {
606 ahlistbrowserclass = new hlistbrowserclass();
607 recpt.add_browser (ahlistbrowserclass);
608 }
609
610 if (adatelistbrowserclass == NULL) {
611 adatelistbrowserclass = new datelistbrowserclass();
612 recpt.add_browser (adatelistbrowserclass);
613 }
614
615 if (ainvbrowserclass == NULL) {
616 ainvbrowserclass = new invbrowserclass();
617 recpt.add_browser (ainvbrowserclass);
618 }
619
620 if (apagedbrowserclass == NULL) {
621 apagedbrowserclass = new pagedbrowserclass();
622 recpt.add_browser (apagedbrowserclass);
623 }
624
625 if (ahtmlbrowserclass == NULL) {
626 ahtmlbrowserclass = new htmlbrowserclass();
627 recpt.add_browser (ahtmlbrowserclass);
628 }
629
630 if (aphindbrowserclass == NULL) {
631 aphindbrowserclass = new phindbrowserclass();;
632 recpt.add_browser (aphindbrowserclass);
633 }
634
635 // set defaults
636 recpt.configure ("gsdlhome", gsdl_gsdlhome);
637 recpt.configure ("collecthome", gsdl_collecthome);
638 recpt.configure ("gdbmhome", gsdl_dbhome);
639 recpt.configure ("collection", collection);
640
641 int maxrequests = 1;
642
643 // configure collections (and receptionist) with collectinfo stuff
644 // different from the default
645 colinfo_tmap::const_iterator this_info = translated_collectinfo.begin();
646 colinfo_tmap::const_iterator end_info = translated_collectinfo.end();
647
648 while (this_info != end_info) {
649 text_tarray tmpconf;
650 tmpconf.push_back ((*this_info).first);
651 tmpconf.push_back ((*this_info).second.gsdl_gsdlhome);
652 tmpconf.push_back ((*this_info).second.gsdl_collecthome);
653 tmpconf.push_back ((*this_info).second.gsdl_dbhome);
654 recpt.configure ("collectinfo", tmpconf);
655 ++this_info;
656 }
657
658 // read in config files of each dbhome (in no particular order)
659 // those read in last will override those read earlier
660 // collections being used together in this way should be
661 // careful not to have main.cfg files that might
662 // interfere with each other.
663 text_tset::const_iterator thome = dbhomes.begin();
664 text_tset::const_iterator ehome = dbhomes.end();
665 text_tset::const_iterator tchome = clhomes.begin(); // collecthome companion for dbhome
666
667 while (thome != ehome) {
668 if (!main_cfg_read (recpt, *thome, *tchome, collection)) {
669 // couldn't find the main configuration file
670 page_errormaincfg (*thome, collection);
671 return 0;
672 }
673 ++thome;
674 ++tchome;
675 }
676
677 // w32server relies on gwcgi being set to "gsdl"
678 recpt.configure ("gwcgi", "gsdl");
679
680 // initialise the library software
681 if (!recpt.init(cerr)) {
682 // an error occurred during the initialisation
683 page_errorinit(gsdl_gsdlhome);
684 return 0;
685 }
686
687 // get memory information
688 MEMORYSTATUS memstatus;
689 memstatus.dwLength = sizeof(MEMORYSTATUS);
690 GlobalMemoryStatus(&memstatus);
691 baseavailvirtual = memstatus.dwAvailVirtual; // save for later comparison
692
693 return 1;
694}
695
696
697static void rememberpref (const text_t &tailstr) {
698 gsdl_enterlib = tailstr;
699}
700
701
702static void send_file_from_disk(text_t filename,
703 RequestInfoT *RInfo,
704 RequestFieldsT *RFields) {
705
706 // select appropriate mime type from file extension
707 text_t ext;
708 text_t::const_iterator end = filename.end();
709 text_t::const_iterator it = filename.begin();
710 text_t::const_iterator lastdot = end;
711 while ((it = findchar(it, end, '.')) != end) {
712 lastdot = it;
713 ++it;
714 }
715 if (lastdot < end) ext = substr(lastdot+1, end);
716
717 text_t mime = "unknown";
718 int len = ext.size();
719 if (len == 2) {
720 if ((ext[0] == 'p' || ext[0] == 'P') &&
721 (ext[1] == 's' || ext[1] == 'S'))
722 mime = "application/postscript";
723 } else if (len == 3) {
724 if ((ext[0] == 'g' || ext[0] == 'G') &&
725 (ext[1] == 'i' || ext[1] == 'I') &&
726 (ext[2] == 'f' || ext[2] == 'F')) {
727 mime = "image/gif";
728 } else if ((ext[0] == 'j' || ext[0] == 'J') &&
729 (ext[1] == 'p' || ext[1] == 'P') &&
730 (ext[2] == 'g' || ext[2] == 'G')) {
731 mime = "image/jpeg";
732 } else if ((ext[0] == 'h' || ext[0] == 'H') &&
733 (ext[1] == 't' || ext[1] == 'T') &&
734 (ext[2] == 'm' || ext[2] == 'M')) {
735 mime = "text/html";
736 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
737 (ext[1] == 'd' || ext[1] == 'D') &&
738 (ext[2] == 'f' || ext[2] == 'F')) {
739 mime = "application/pdf";
740 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
741 (ext[1] == 'n' || ext[1] == 'N') &&
742 (ext[2] == 'g' || ext[2] == 'G')) {
743 mime = "image/png";
744 } else if ((ext[0] == 'd' || ext[0] == 'D') &&
745 (ext[1] == 'o' || ext[1] == 'O') &&
746 (ext[2] == 'c' || ext[2] == 'C')) {
747 mime = "application/msword";
748 } else if ((ext[0] == 'r' || ext[0] == 'R') &&
749 (ext[1] == 't' || ext[1] == 'T') &&
750 (ext[2] == 'f' || ext[2] == 'F')) {
751 mime = "application/rtf";
752 } else if ((ext[0] == 'x' || ext[0] == 'X') &&
753 (ext[1] == 'l' || ext[1] == 'L') &&
754 (ext[2] == 's' || ext[2] == 'S')) {
755 mime = "application/vnd.ms-excel";
756 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
757 (ext[1] == 'p' || ext[1] == 'P') &&
758 (ext[2] == 'T' || ext[2] == 'T')) {
759 mime = "application/vnd.ms-powerpoint";
760 } else if ((ext[0] == 'm' || ext[0] == 'M') &&
761 (ext[1] == 'p' || ext[1] == 'P') &&
762 (ext[2] == '3')) {
763 mime = "audio/mpeg";
764 }
765 } else if (len == 4) {
766 if ((ext[0] == 'j' || ext[0] == 'J') &&
767 (ext[1] == 'p' || ext[1] == 'P') &&
768 (ext[2] == 'e' || ext[2] == 'E') &&
769 (ext[3] == 'g' || ext[3] == 'G')) {
770 mime = "image/jpeg";
771 } else if ((ext[0] == 'h' || ext[0] == 'H') &&
772 (ext[1] == 't' || ext[1] == 'T') &&
773 (ext[2] == 'm' || ext[2] == 'M') &&
774 (ext[3] == 'l' || ext[3] == 'L')) {
775 mime = "text/html";
776 }
777 }
778
779 // try to open the file
780 //cerr << "*** filename = " << filename.getcstr() << endl;
781 //cerr << "**** collect_home = " << current_collecthome.getcstr() << endl;
782
783 if (filename.size()>=9) {
784 text_t prefix = substr(filename.begin(),filename.begin()+9);
785 //cerr << "**** prefix = " << prefix.getcstr() << endl;
786
787 text_t tail = substr(filename.begin()+9,filename.end());
788 //cerr << "**** tail = " << tail.getcstr() << endl;
789
790 if (prefix == "/collect/") {
791 filename = filename_cat (current_collecthome, tail);
792 }
793 else {
794 filename = filename_cat (current_gsdlhome, filename);
795 }
796 }
797
798 cerr << "#### filename = " << filename.getcstr() << endl;
799
800 /* Feb 2002 - handle files with spaces in their name. */
801 text_t::iterator space_start;
802 space_start=findword(filename.begin(),filename.end(),"%20");
803 while (space_start != filename.end()) {
804 // we found a space...
805 text_t::iterator after_space=space_start+3;
806 text_t new_filename=substr(filename.begin(), space_start);
807 new_filename += " ";
808 new_filename += substr(after_space,filename.end());
809 filename=new_filename;
810 space_start=findword(filename.begin(),filename.end(),"%20");
811 }
812
813 char *filenamec = filename.getcstr();
814 TranslateEscapeString(filenamec); // Resolve any %xx values
815 FILE *thefile = fopen(filenamec, "rb");
816 delete []filenamec;
817 if (thefile == NULL) {
818 log_message("file not found\n");
819 send_retrieve_error(404, "File not found",
820 "Could not find the local file requested", RInfo);
821 return;
822 }
823 int nr;
824 char buffer[2048];
825 // send back required information
826 char *mimec = mime.getcstr();
827 if (send_header(mimec, RInfo) >= 0) {
828 if (RFields->MethodStr != "HEAD") {
829 for (;;) {
830 nr = fread(buffer, 1, 2048, thefile);
831 if (nr <= 0) break;
832 if (SendData(RInfo->ClientSocket,
833 (BYTE *)buffer, nr,
834 RInfo->ThreadNum) < 0) break;
835 }
836 }
837 }
838 delete []mimec;
839 fclose(thefile);
840}
841
842static void handle_library_request(const text_t &argstr, RequestInfoT *RInfo,
843 RequestFieldsT *RequestFields) {
844
845 // parse the cgi arguments and produce the resulting page if there
846 // have been no errors so far
847 cgiargsclass args;
848 fileupload_tmap fileuploads;
849 text_tmap empty; // don't use this (it's for fastcgi on unix)
850 if (!recpt.parse_cgi_args (argstr, fileuploads, args, cerr, empty)) {
851 page_errorparseargs(gsdl_gsdlhome);
852 return;
853 }
854
855 colinfo_tmap::const_iterator it = translated_collectinfo.find (args["c"]);
856 if (it != translated_collectinfo.end()) {
857 current_gsdlhome = (*it).second.gsdl_gsdlhome;
858 current_collecthome = (*it).second.gsdl_collecthome;
859 } else {
860 current_gsdlhome = gsdl_gsdlhome;
861 current_collecthome = gsdl_collecthome;
862 }
863
864 // produce cgi header
865 response_t response;
866 text_t response_data;
867
868 recpt.get_cgihead_info (args, response, response_data, cerr, empty);
869
870 if (response == location) {
871 // location response
872 response_data = "@" + recpt.expandmacros (response_data, args, cerr);
873 char *response_data_c = response_data.getcstr();
874 send_header(response_data_c, RInfo);
875 delete []response_data_c;
876 return;
877 } else if (response == content) {
878 // content response
879 char *response_data_c = response_data.getcstr();
880 if (send_header(response_data_c, RInfo) < 0) {
881 delete []response_data_c;
882 return;
883 }
884 delete []response_data_c;
885 }
886 else if (response == undecided_location) {
887 // We know this is a relocation request but at the moment we don't know exactly where to
888 // Just output the start of the header and wait until later to output the target location
889 // Used for the "I'm feeling lucky" functionality
890 cout << "HTTP/1.0 302 Relocation\r\n";
891 cout << "Server: GSDL\r\n";
892 cout << "Content-type: text/html \r\n";
893 }
894 else {
895 // unknown response
896 cerr << "Error: get_cgihead_info returned an unknown response type.\n";
897 return;
898 }
899
900 textstream.tsbreset();
901 textstream.setrequestinfo (RInfo);
902 if (!recpt.produce_content (args, cout, cerr)) {
903 page_errorcgipage(gsdl_gsdlhome);
904 return;
905 }
906 recpt.log_cgi_args (args, cerr, empty);
907
908 cout << flush;
909 cerr << flush;
910
911 ++libaccessnum;
912}
913
914static void handle_server_request(text_t &tailstr,
915 RequestInfoT *RequestInfo,
916 RequestFieldsT *RequestFields) {
917
918 text_t argstr;
919
920 // do any url adjustments necessary
921 if (tailstr.empty() || tailstr == "/") {
922 tailstr = "/gsdl";
923 }
924
925 text_t::const_iterator begin = tailstr.begin();
926 text_t::const_iterator end = tailstr.end();
927
928 // test to see if this is a library request or a local
929 // file request
930 if ((tailstr == "/gsdl") ||
931 ((tailstr.size() > 5) && (substr(begin, begin+6) == "/gsdl?"))) {
932
933 // library request
934
935 // argstr is the bit after the '?'
936 if (tailstr != "/gsdl") {
937 argstr = substr(begin+6, end);
938 }
939
940 // log the difference in access times
941 DWORD thislibaccesstime = GetTickCount();
942 if (gsdl_keep_log || gsdl_show_console) {
943 char logstr[256];
944 sprintf(logstr, "DELTA LIB ACCESS TIME: %i\n", (int)(thislibaccesstime - lastlibaccesstime));
945 log_message (logstr);
946 }
947 lastlibaccesstime = thislibaccesstime;
948
949 // log this request
950 if (gsdl_keep_log || gsdl_show_console) {
951 text_t logstr = "LOCAL LIB: " + tailstr + "\n";
952 char *logstrc = logstr.getcstr();
953 log_message (logstrc);
954 delete []logstrc;
955 }
956
957 handle_library_request (argstr, RequestInfo, RequestFields);
958
959 // remember the preferences
960 // rememberpref (tailstr);
961
962 // log memory information
963 if (gsdl_keep_log || gsdl_show_console) {
964 MEMORYSTATUS memstatus;
965 memstatus.dwLength = sizeof(MEMORYSTATUS);
966 GlobalMemoryStatus(&memstatus);
967 char logstr[256];
968 sprintf (logstr, "BDELTA AVAIL VIRTUAL: %i K\n",
969 (int)((baseavailvirtual - memstatus.dwAvailVirtual)/1024));
970 log_message (logstr);
971 }
972
973 } else {
974 // local file
975 if (gsdl_keep_log || gsdl_show_console) {
976 text_t logstr = "LOCAL FILE: " + tailstr + "\n";
977 char *logstrc = logstr.getcstr();
978 log_message (logstrc);
979 delete []logstrc;
980 }
981 send_file_from_disk (tailstr, RequestInfo, RequestFields);
982 }
983}
984
985int ExamineURIStr(text_t &URIStr, RequestInfoT *RequestInfo,
986 RequestFieldsT *RequestFields)
987{
988 text_t protocol, machine, rest;
989 int port;
990
991 if (RequestFields->ContentLength > 0) {
992 // POST data
993 URIStr.push_back('?');
994 for (int i = 0; i < RequestFields->ContentLength; ++i) {
995 URIStr.push_back(RequestFields->Content[i]);
996 }
997 }
998
999 if (parse_url(URIStr, protocol, machine, &port, rest)!=http_ok) {
1000 // Alter local file request to address 'gsdl'
1001 if (*(URIStr.begin()) != '/') URIStr = "http://gsdl/" + URIStr;
1002 else URIStr = "http://gsdl" + URIStr;
1003 parse_url(URIStr, protocol, machine, &port, rest);
1004 }
1005
1006 if (machine == "gsdl") {
1007 // a local file request
1008 handle_server_request(rest, RequestInfo, RequestFields);
1009
1010 } else {
1011 send_retrieve_error(404, "File not found",
1012 "Could not find the local file requested", RequestInfo);
1013 }
1014
1015 return 1;
1016}
Note: See TracBrowser for help on using the repository browser.