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

Last change on this file since 28758 was 27220, checked in by kjdon, 11 years ago

cross coll search authentication. Need to make the same cgiwrapper mod in w32server for local library

  • 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_userdb(udb);
594 aqueryaction->set_receptionist (&recpt);
595 recpt.add_action (aqueryaction);
596 }
597
598#if defined(USE_SQLITE)
599 if (asqlqueryaction == NULL) {
600 asqlqueryaction = new sqlqueryaction();
601 asqlqueryaction->set_receptionist (&recpt);
602 recpt.add_action (asqlqueryaction);
603 }
604#endif
605
606 if (adocumentaction == NULL) {
607 adocumentaction = new documentaction();
608 adocumentaction->set_receptionist (&recpt);
609 recpt.add_action (adocumentaction);
610 }
611
612 if (ausersaction == NULL) {
613 ausersaction = new usersaction();
614 ausersaction->set_userdb(udb);
615 recpt.add_action (ausersaction);
616 }
617
618 if (anextlinkaction == NULL) {
619 anextlinkaction = new extlinkaction();
620 recpt.add_action (anextlinkaction);
621 }
622
623 if (acollectoraction == NULL) {
624 acollectoraction = new collectoraction();
625 acollectoraction->set_receptionist (&recpt);
626 recpt.add_action (acollectoraction);
627 }
628
629 if (aauthenaction == NULL) {
630 aauthenaction = new authenaction();
631 aauthenaction->set_userdb(udb);
632 aauthenaction->set_keydb(kdb);
633 aauthenaction->set_receptionist(&recpt);
634 recpt.add_action (aauthenaction);
635 }
636
637#ifdef ENABLE_MGPP
638 if (aphindaction == NULL) {
639 aphindaction = new phindaction();
640 recpt.add_action (aphindaction);
641 }
642#endif
643
644 if (aconfigaction == NULL) {
645 aconfigaction = new configaction();
646 aconfigaction->set_receptionist(&recpt);
647 recpt.add_action (aconfigaction);
648 }
649
650 if (adynamicclassifieraction == NULL) {
651 adynamicclassifieraction = new dynamicclassifieraction();
652 adynamicclassifieraction->set_receptionist(&recpt);
653 recpt.add_action (adynamicclassifieraction);
654 }
655
656
657 // list of browsers
658 if (avlistbrowserclass == NULL) {
659 avlistbrowserclass = new vlistbrowserclass();
660 recpt.add_browser (avlistbrowserclass);
661 recpt.setdefaultbrowser ("VList");
662 }
663
664 if (ahlistbrowserclass == NULL) {
665 ahlistbrowserclass = new hlistbrowserclass();
666 recpt.add_browser (ahlistbrowserclass);
667 }
668
669 if (adatelistbrowserclass == NULL) {
670 adatelistbrowserclass = new datelistbrowserclass();
671 recpt.add_browser (adatelistbrowserclass);
672 }
673
674 if (ainvbrowserclass == NULL) {
675 ainvbrowserclass = new invbrowserclass();
676 recpt.add_browser (ainvbrowserclass);
677 }
678
679 if (apagedbrowserclass == NULL) {
680 apagedbrowserclass = new pagedbrowserclass();
681 recpt.add_browser (apagedbrowserclass);
682 }
683
684 if (ahtmlbrowserclass == NULL) {
685 ahtmlbrowserclass = new htmlbrowserclass();
686 recpt.add_browser (ahtmlbrowserclass);
687 }
688
689 if (aphindbrowserclass == NULL) {
690 aphindbrowserclass = new phindbrowserclass();;
691 recpt.add_browser (aphindbrowserclass);
692 }
693
694 // set defaults
695 recpt.configure ("gsdlhome", gsdl_gsdlhome);
696 recpt.configure ("collecthome", gsdl_collecthome);
697 recpt.configure ("gdbmhome", gsdl_dbhome);
698 recpt.configure ("collection", collection);
699
700 int maxrequests = 1;
701
702 // configure collections (and receptionist) with collectinfo stuff
703 // different from the default
704 colinfo_tmap::const_iterator this_info = translated_collectinfo.begin();
705 colinfo_tmap::const_iterator end_info = translated_collectinfo.end();
706
707 while (this_info != end_info) {
708 text_tarray tmpconf;
709 tmpconf.push_back ((*this_info).first);
710 tmpconf.push_back ((*this_info).second.gsdl_gsdlhome);
711 tmpconf.push_back ((*this_info).second.gsdl_collecthome);
712 tmpconf.push_back ((*this_info).second.gsdl_dbhome);
713 recpt.configure ("collectinfo", tmpconf);
714 ++this_info;
715 }
716
717 // read in config files of each dbhome (in no particular order)
718 // those read in last will override those read earlier
719 // collections being used together in this way should be
720 // careful not to have main.cfg files that might
721 // interfere with each other.
722 text_tset::const_iterator thome = dbhomes.begin();
723 text_tset::const_iterator ehome = dbhomes.end();
724 text_tset::const_iterator tchome = clhomes.begin(); // collecthome companion for dbhome
725
726 while (thome != ehome) {
727 if (!main_cfg_read (recpt, *thome, *tchome, collection)) {
728 // couldn't find the main configuration file
729 page_errormaincfg (*thome, collection);
730 return 0;
731 }
732 ++thome;
733 ++tchome;
734 }
735
736 // w32server relies on gwcgi being set to "gsdl", and httpweb to web
737 recpt.configure ("gwcgi", "gsdl");
738 recpt.configure ("httpweb", "web");
739
740 // initialise the library software
741 if (!recpt.init(cerr)) {
742 // an error occurred during the initialisation
743 page_errorinit(gsdl_gsdlhome);
744 return 0;
745 }
746
747 // get memory information
748 MEMORYSTATUS memstatus;
749 memstatus.dwLength = sizeof(MEMORYSTATUS);
750 GlobalMemoryStatus(&memstatus);
751 baseavailvirtual = memstatus.dwAvailVirtual; // save for later comparison
752
753 return 1;
754}
755
756
757static void rememberpref (const text_t &tailstr) {
758 gsdl_enterlib = tailstr;
759}
760
761
762static void send_file_from_disk(text_t filename,
763 RequestInfoT *RInfo,
764 RequestFieldsT *RFields) {
765
766 // select appropriate mime type from file extension
767 text_t ext;
768 text_t::const_iterator end = filename.end();
769 text_t::const_iterator it = filename.begin();
770 text_t::const_iterator lastdot = end;
771 while ((it = findchar(it, end, '.')) != end) {
772 lastdot = it;
773 ++it;
774 }
775 if (lastdot < end) ext = substr(lastdot+1, end);
776
777 text_t mime = "unknown";
778 int len = ext.size();
779 if (len == 2) {
780 if ((ext[0] == 'p' || ext[0] == 'P') &&
781 (ext[1] == 's' || ext[1] == 'S'))
782 mime = "application/postscript";
783 } else if (len == 3) {
784 if((ext[0] == 'c' || ext[0] == 'C') &&
785 (ext[1] == 's' || ext[1] == 'S') &&
786 (ext[2] == 's' || ext[2] == 'S')){
787 mime = "text/css";
788 } else if ((ext[0] == 'g' || ext[0] == 'G') &&
789 (ext[1] == 'i' || ext[1] == 'I') &&
790 (ext[2] == 'f' || ext[2] == 'F')) {
791 mime = "image/gif";
792 } else if ((ext[0] == 'j' || ext[0] == 'J') &&
793 (ext[1] == 'p' || ext[1] == 'P') &&
794 (ext[2] == 'g' || ext[2] == 'G')) {
795 mime = "image/jpeg";
796 } else if ((ext[0] == 'h' || ext[0] == 'H') &&
797 (ext[1] == 't' || ext[1] == 'T') &&
798 (ext[2] == 'm' || ext[2] == 'M')) {
799 mime = "text/html";
800 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
801 (ext[1] == 'd' || ext[1] == 'D') &&
802 (ext[2] == 'f' || ext[2] == 'F')) {
803 mime = "application/pdf";
804 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
805 (ext[1] == 'n' || ext[1] == 'N') &&
806 (ext[2] == 'g' || ext[2] == 'G')) {
807 mime = "image/png";
808 } else if ((ext[0] == 'd' || ext[0] == 'D') &&
809 (ext[1] == 'o' || ext[1] == 'O') &&
810 (ext[2] == 'c' || ext[2] == 'C')) {
811 mime = "application/msword";
812 } else if ((ext[0] == 'r' || ext[0] == 'R') &&
813 (ext[1] == 't' || ext[1] == 'T') &&
814 (ext[2] == 'f' || ext[2] == 'F')) {
815 mime = "application/rtf";
816 } else if ((ext[0] == 'x' || ext[0] == 'X') &&
817 (ext[1] == 'l' || ext[1] == 'L') &&
818 (ext[2] == 's' || ext[2] == 'S')) {
819 mime = "application/vnd.ms-excel";
820 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
821 (ext[1] == 'p' || ext[1] == 'P') &&
822 (ext[2] == 'T' || ext[2] == 'T')) {
823 mime = "application/vnd.ms-powerpoint";
824 } else if ((ext[0] == 'm' || ext[0] == 'M') &&
825 (ext[1] == 'p' || ext[1] == 'P') &&
826 (ext[2] == '3')) {
827 mime = "audio/mpeg";
828 }
829 } else if (len == 4) {
830 if ((ext[0] == 'j' || ext[0] == 'J') &&
831 (ext[1] == 'p' || ext[1] == 'P') &&
832 (ext[2] == 'e' || ext[2] == 'E') &&
833 (ext[3] == 'g' || ext[3] == 'G')) {
834 mime = "image/jpeg";
835 } else if ((ext[0] == 'h' || ext[0] == 'H') &&
836 (ext[1] == 't' || ext[1] == 'T') &&
837 (ext[2] == 'm' || ext[2] == 'M') &&
838 (ext[3] == 'l' || ext[3] == 'L')) {
839 mime = "text/html";
840 }
841 }
842
843 // try to open the file
844 //cerr << "*** filename = " << filename.getcstr() << endl;
845 //cerr << "**** collect_home = " << current_collecthome.getcstr() << endl;
846
847 if (filename.size()>=9) {
848 text_t prefix = substr(filename.begin(),filename.begin()+9);
849 //cerr << "**** prefix = " << prefix.getcstr() << endl;
850
851 text_t tail = substr(filename.begin()+9,filename.end());
852 //cerr << "**** tail = " << tail.getcstr() << endl;
853
854 if (prefix == "/collect/") {
855 filename = filename_cat (current_collecthome, tail);
856 }
857 else {
858 filename = filename_cat (current_gsdlhome, filename);
859 }
860 }
861
862 cerr << "#### filename = " << filename.getcstr() << endl;
863
864 /* Feb 2002 - handle files with spaces in their name. */
865 text_t::iterator space_start;
866 space_start=findword(filename.begin(),filename.end(),"%20");
867 while (space_start != filename.end()) {
868 // we found a space...
869 text_t::iterator after_space=space_start+3;
870 text_t new_filename=substr(filename.begin(), space_start);
871 new_filename += " ";
872 new_filename += substr(after_space,filename.end());
873 filename=new_filename;
874 space_start=findword(filename.begin(),filename.end(),"%20");
875 }
876
877 char *filenamec = filename.getcstr();
878 TranslateEscapeString(filenamec); // Resolve any %xx values
879 FILE *thefile = fopen(filenamec, "rb");
880 delete []filenamec;
881 if (thefile == NULL) {
882 log_message("file not found\n");
883 send_retrieve_error(404, "File not found",
884 "Could not find the local file requested", RInfo);
885 return;
886 }
887 int nr;
888 char buffer[2048];
889 // send back required information
890 char *mimec = mime.getcstr();
891 if (send_header(mimec, RInfo) >= 0) {
892 if (RFields->MethodStr != "HEAD") {
893 for (;;) {
894 nr = fread(buffer, 1, 2048, thefile);
895 if (nr <= 0) break;
896 if (SendData(RInfo->ClientSocket,
897 (BYTE *)buffer, nr,
898 RInfo->ThreadNum) < 0) break;
899 }
900 }
901 }
902 delete []mimec;
903 fclose(thefile);
904}
905
906static void handle_library_request(const text_t &argstr, RequestInfoT *RInfo,
907 RequestFieldsT *RequestFields) {
908
909 // parse the cgi arguments and produce the resulting page if there
910 // have been no errors so far
911 cgiargsclass args;
912 fileupload_tmap fileuploads;
913 text_tmap empty; // don't use this (it's for fastcgi on unix)
914 if (!recpt.parse_cgi_args (argstr, fileuploads, args, cerr, empty)) {
915 page_errorparseargs(gsdl_gsdlhome);
916 return;
917 }
918
919 colinfo_tmap::const_iterator it = translated_collectinfo.find (args["c"]);
920 if (it != translated_collectinfo.end()) {
921 current_gsdlhome = (*it).second.gsdl_gsdlhome;
922 current_collecthome = (*it).second.gsdl_collecthome;
923 } else {
924 current_gsdlhome = gsdl_gsdlhome;
925 current_collecthome = gsdl_collecthome;
926 }
927
928 // produce cgi header
929 response_t response;
930 text_t response_data;
931
932 recpt.get_cgihead_info (args, response, response_data, cerr, empty);
933
934 if (response == location) {
935 // location response
936 response_data = "@" + recpt.expandmacros (response_data, args, cerr);
937 char *response_data_c = response_data.getcstr();
938 send_header(response_data_c, RInfo);
939 delete []response_data_c;
940 return;
941 } else if (response == content) {
942 // content response
943 char *response_data_c = response_data.getcstr();
944 if (send_header(response_data_c, RInfo) < 0) {
945 delete []response_data_c;
946 return;
947 }
948 delete []response_data_c;
949 }
950 else if (response == undecided_location) {
951 // We know this is a relocation request but at the moment we don't know exactly where to
952 // Just output the start of the header and wait until later to output the target location
953 // Used for the "I'm feeling lucky" functionality
954 cout << "HTTP/1.0 302 Relocation\r\n";
955 cout << "Server: GSDL\r\n";
956 cout << "Content-type: text/html \r\n";
957 }
958 else {
959 // unknown response
960 cerr << "Error: get_cgihead_info returned an unknown response type.\n";
961 return;
962 }
963
964 textstream.tsbreset();
965 textstream.setrequestinfo (RInfo);
966 if (!recpt.produce_content (args, cout, cerr)) {
967 page_errorcgipage(gsdl_gsdlhome);
968 return;
969 }
970 recpt.log_cgi_args (args, cerr, empty);
971
972 cout << flush;
973 cerr << flush;
974
975 ++libaccessnum;
976}
977
978static void handle_server_request(text_t &tailstr,
979 RequestInfoT *RequestInfo,
980 RequestFieldsT *RequestFields) {
981
982 text_t argstr;
983
984 // do any url adjustments necessary
985 if (tailstr.empty() || tailstr == "/") {
986 tailstr = "/gsdl";
987 }
988
989 text_t::const_iterator begin = tailstr.begin();
990 text_t::const_iterator end = tailstr.end();
991
992 // test to see if this is a library request or a local
993 // file request
994 if ((tailstr == "/gsdl") ||
995 ((tailstr.size() > 5) && (substr(begin, begin+6) == "/gsdl?"))) {
996
997 // library request
998
999 // argstr is the bit after the '?'
1000 if (tailstr != "/gsdl") {
1001 argstr = substr(begin+6, end);
1002 }
1003
1004 // log the difference in access times
1005 DWORD thislibaccesstime = GetTickCount();
1006 if (gsdl_keep_log || gsdl_show_console) {
1007 char logstr[256];
1008 sprintf(logstr, "DELTA LIB ACCESS TIME: %i\n", (int)(thislibaccesstime - lastlibaccesstime));
1009 log_message (logstr);
1010 }
1011 lastlibaccesstime = thislibaccesstime;
1012
1013 // log this request
1014 if (gsdl_keep_log || gsdl_show_console) {
1015 text_t logstr = "LOCAL LIB: " + tailstr + "\n";
1016 char *logstrc = logstr.getcstr();
1017 log_message (logstrc);
1018 delete []logstrc;
1019 }
1020
1021 handle_library_request (argstr, RequestInfo, RequestFields);
1022
1023 // remember the preferences
1024 // rememberpref (tailstr);
1025
1026 // log memory information
1027 if (gsdl_keep_log || gsdl_show_console) {
1028 MEMORYSTATUS memstatus;
1029 memstatus.dwLength = sizeof(MEMORYSTATUS);
1030 GlobalMemoryStatus(&memstatus);
1031 char logstr[256];
1032 sprintf (logstr, "BDELTA AVAIL VIRTUAL: %i K\n",
1033 (int)((baseavailvirtual - memstatus.dwAvailVirtual)/1024));
1034 log_message (logstr);
1035 }
1036
1037 } else {
1038 // local file
1039 if (gsdl_keep_log || gsdl_show_console) {
1040 text_t logstr = "LOCAL FILE: " + tailstr + "\n";
1041 char *logstrc = logstr.getcstr();
1042 log_message (logstrc);
1043 delete []logstrc;
1044 }
1045 send_file_from_disk (tailstr, RequestInfo, RequestFields);
1046 }
1047}
1048
1049int ExamineURIStr(text_t &URIStr, RequestInfoT *RequestInfo,
1050 RequestFieldsT *RequestFields)
1051{
1052 text_t protocol, machine, rest;
1053 int port;
1054
1055 if (RequestFields->ContentLength > 0) {
1056 // POST data
1057 URIStr.push_back('?');
1058 for (int i = 0; i < RequestFields->ContentLength; ++i) {
1059 URIStr.push_back(RequestFields->Content[i]);
1060 }
1061 }
1062
1063 if (parse_url(URIStr, protocol, machine, &port, rest)!=http_ok) {
1064 // Alter local file request to address 'gsdl'
1065 if (*(URIStr.begin()) != '/') URIStr = "http://gsdl/" + URIStr;
1066 else URIStr = "http://gsdl" + URIStr;
1067 parse_url(URIStr, protocol, machine, &port, rest);
1068 }
1069
1070 if (machine == "gsdl") {
1071 // a local file request
1072 handle_server_request(rest, RequestInfo, RequestFields);
1073
1074 } else {
1075 send_retrieve_error(404, "File not found",
1076 "Could not find the local file requested", RequestInfo);
1077 }
1078
1079 return 1;
1080}
Note: See TracBrowser for help on using the repository browser.