source: main/trunk/greenstone2/runtime-src/src/w32server/cgiwrapper.cpp@ 25560

Last change on this file since 25560 was 25560, checked in by ak19, 12 years ago

Dr Bainbridge has introduced the isPersistentAction (add the a=is-persistent to the library url). It is true for server.exe and when using mod_gsdl, but false for library.cgi which uses the apache web server (when not using mod_gsdl).

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