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

Last change on this file since 22948 was 22948, checked in by ak19, 13 years ago

Dr Bainbridge fixed more bugs tangentially related to the advanced searching combined with fielded searching bug that was previously crashing the library.cgi and server.exe. This time around, there were no crashes but the recent corrections to the combined searching needed to work with SQL queries as well. When testing this last, it was discovered that 1. the SQL form wasn't displaying in preferences even when sqlite was set as the infodbtype in collect.cfg and its format Searchtypes line set to include sqlform next to plain and form. This was fixed by making CGIWrapper remember to instantiate sqlqueryaction and not just queryaction. 2. the RunQuery button would eat commas on submission (previously choosing to turn them into non-descript spaces), this has now been fixed in the query.dm macro.

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