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

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

Dr Bainbridge fixed the bug on Windows whereby the Admin pages when accessed through the local library server/server.exe would not authenticate (but the authentication would work if the apache web server was run instead).

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 32.0 KB
Line 
1/**********************************************************************
2 *
3 * cgiwrapper.cpp -- windows local library cgiwrapper
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "text_t.h"
27
28#include <windows.h>
29#include <string.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <assert.h>
33#include <direct.h>
34#include "cgiwrapper.h"
35#include "netio.h"
36#include "wincgiutils.h"
37#include "settings.h"
38#include "fileutil.h"
39#include "parse.h"
40
41#include "gsdlconf.h"
42#include "maincfg.h"
43
44#if defined (GSDL_USE_OBJECTSPACE)
45#include <ospace\std\iostream>
46#include <ospace\std\fstream>
47#elif defined (GSDL_USE_IOS_H)
48#include <iostream.h>
49#include <fstream.h>
50#else
51#include <iostream>
52#include <fstream>
53#endif
54
55#include "receptionist.h"
56#include "nullproto.h"
57
58// actions
59#include "statusaction.h"
60#include "pageaction.h"
61#include "pingaction.h"
62#include "queryaction.h"
63#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;
372userdbclass *udb = NULL;
373keydbclass *kdb = NULL;
374
375
376// When (1) the "collecthome" collect dir is not the standard greenstone collect dir,
377// or when (2) this collecthome is specified in a section other than [gsdl] in the (lls/gli)site.cfg file,
378// this method gets called to load in that collect dir's collections into the server during gsdl_init
379static void load_collections_from_collectdir(
380 colinfo_tmap &translated_colinfo,
381 text_tset::const_iterator &colhere,
382 text_tset::const_iterator &colend,
383 text_tset &these_collections,
384 text_tset &dbhomes,
385 text_tset &clhomes,
386 text_tset &collections,
387 const text_t &my_gsdl_home,
388 const text_t &my_gsdl_collecthome,
389 const text_t &my_gsdl_dbhome)
390{
391 these_collections.erase (these_collections.begin(), these_collections.end());
392 read_dir (my_gsdl_collecthome, these_collections);
393 colhere = these_collections.begin();
394 colend = these_collections.end();
395 while (colhere != colend) {
396 if ((collections.find (*colhere)) == collections.end()) {
397 // make sure the build.cfg file is at gsdlhome (as it's possible that
398 // the collection appears at this gsdlhome only because it's gdbm
399 // file is installed here -- it's real gdbm will therefore be
400 // somewhere else).
401
402 // commenting out the following build_cfg test since the server won't know to load
403 // collection groups otherwise, as these don't have build_cfg files but ought to be loaded along
404 // with collections (the real test for whether something ought to be loaded--whether an item read
405 // in by read_dir is a collection or collection group--happens at a later time in the GS runtime code).
406
407 //text_t build_cfg = filename_cat (my_gsdl_collecthome,*colhere, "index", "build.cfg");
408 //if (file_exists (build_cfg)) {
409 collections.insert (*colhere);
410
411 // since gsdl_collectinfo keys will be stuff like collection#1
412 // for a multiple volume collection we want to translate it
413 // so that the keys are the actual collection names
414 collectioninfo_t tmp;
415 tmp.gsdl_gsdlhome = my_gsdl_home;
416 tmp.gsdl_collecthome = my_gsdl_collecthome;
417 tmp.gsdl_dbhome = my_gsdl_dbhome;
418 translated_colinfo[*colhere] = tmp;
419 //}
420 }
421 ++colhere;
422 }
423 dbhomes.insert (gsdl_dbhome);
424 clhomes.insert (gsdl_collecthome);
425}
426
427
428// returns 1 if successful, 0 if unsuccessful (note that as well as being
429// called when the server first starts up this function is called when the
430// "restart library" button is pressed)
431int gsdl_init (bool atStartup) {
432 if (atStartup) {
433#if defined (GSDL_USE_IOS_H)
434 cerr = &logstream;
435 cout = &textstream;
436#else
437 cerr.rdbuf(&logstream);
438 cout.rdbuf(&textstream);
439#endif
440 }
441
442 // collection should be set to "" unless in collection specific mode -
443 // changing this to the name of the collection should be all that's
444 // required to create a collection specific receptionist
445 text_t collection = "";
446 text_tset dbhomes;
447 text_tset clhomes; // collecthome companion for dbhome
448 text_tset collections;
449
450 if (atStartup) {
451 // note the current time
452 lastlibaccesstime = GetTickCount();
453
454 // before we do the init we should make sure
455 // that we can find the relevant directories
456 if (!checkdir (gsdl_gsdlhome + "\\")) return 0;
457 if (!checkdir (gsdl_collecthome + "\\")) return 0;
458 if (!checkdir (gsdl_gsdlhome + "\\macros\\")) return 0;
459 }
460
461 // deleting cservers clears all the collection servers
462 if (cservers != NULL) delete cservers;
463
464 cservers = new collectset();
465
466 // get all collections from each gsdlhome (this relies
467 // on there not being more than one collection with the same
468 // name)
469 if (!collection.empty()) {
470 // collection specific receptionist - one collection, one gsdlhome
471 collections.insert (collection);
472 dbhomes.insert (gsdl_dbhome);
473 clhomes.insert (gsdl_collecthome);
474 collectioninfo_t tmp;
475 tmp.gsdl_gsdlhome = gsdl_gsdlhome;
476 tmp.gsdl_collecthome = gsdl_collecthome;
477 tmp.gsdl_dbhome = gsdl_dbhome;
478 translated_collectinfo[collection] = tmp;
479
480 } else {
481 text_tset::const_iterator colhere;
482 text_tset::const_iterator colend;
483 text_tset these_collections;
484
485 // First volume gsdlhome's
486 // read in all the collections from sections other than [gsdl] in the site config file (llssite/glisite)
487 colinfo_tmap::const_iterator this_info = gsdl_collectinfo.begin();
488 colinfo_tmap::const_iterator end_info = gsdl_collectinfo.end();
489 while (this_info != end_info) {
490 if (dbhomes.find ((*this_info).second.gsdl_dbhome) == dbhomes.end()) {
491 load_collections_from_collectdir(translated_collectinfo,
492 colhere, colend, these_collections,
493 dbhomes, clhomes, collections,
494 (*this_info).second.gsdl_gsdlhome,
495 (*this_info).second.gsdl_collecthome,
496 (*this_info).second.gsdl_dbhome);
497 }
498 ++this_info;
499 }
500
501 // if non-standard collecthome under [gsdl] section of site config file (llssite or glisite),
502 // then need to read in all the collections from this collecthome
503 if(gsdl_collecthome != filename_cat(gsdl_gsdlhome,"collect")) {
504 load_collections_from_collectdir(translated_collectinfo,
505 colhere, colend, these_collections,
506 dbhomes, clhomes, collections,
507 gsdl_gsdlhome, gsdl_collecthome, gsdl_dbhome);
508 }
509
510 // But when the default greenstone collect dir (gsdlhome\collect) is used, the following is used to load the collections:
511
512 // then if necessary the main dbhome (this should only happen if the
513 // gsdl.ini is a little screwed up and no volume dbhomes occurred)
514 if (dbhomes.find (gsdl_dbhome) == dbhomes.end()) {
515 load_collections_from_collectdir(translated_collectinfo,
516 colhere, colend, these_collections,
517 dbhomes, clhomes, collections,
518 gsdl_gsdlhome, filename_cat (gsdl_dbhome, "collect"), gsdl_dbhome);
519 }
520 }
521
522 text_tset::const_iterator thiscol = collections.begin();
523 text_tset::const_iterator endcol = collections.end();
524
525 while (thiscol != endcol) {
526
527 // ignore the modelcol
528 if (*thiscol == "modelcol") {
529 ++thiscol;
530 continue;
531 }
532
533 // create collection server and add to null protocol
534 text_t this_gsdlhome = gsdl_gsdlhome;
535 text_t this_collecthome = gsdl_collecthome;
536 text_t this_dbhome = gsdl_dbhome;
537 colinfo_tmap::const_iterator it = translated_collectinfo.find (*thiscol);
538 assert (it != translated_collectinfo.end());
539 this_gsdlhome = (*it).second.gsdl_gsdlhome;
540 this_collecthome = (*it).second.gsdl_collecthome;
541 this_dbhome = (*it).second.gsdl_dbhome;
542
543 cservers->add_collection (*thiscol, this_gsdlhome, this_collecthome);
544 // in case it is a collection group
545 cservers->add_collection_group(*thiscol, this_gsdlhome, this_collecthome);
546
547 ++thiscol;
548 }
549
550 // set up the null protocol
551 nproto.set_collectset(cservers);
552
553 if ((ausersaction == NULL) && (aauthenaction == NULL)){
554 udb = new userdbclass(gsdl_gsdlhome);
555 kdb = new keydbclass(gsdl_gsdlhome);
556 }
557 // add the protocol to the receptionist
558 if (atStartup) recpt.add_protocol (&nproto);
559
560 // the list of actions.
561 if (astatusaction == NULL) {
562 astatusaction = new statusaction();
563 astatusaction->set_receptionist (&recpt);
564 recpt.add_action (astatusaction);
565 }
566
567 if (apageaction == NULL) {
568 apageaction = new pageaction();
569 apageaction->set_receptionist (&recpt);
570 recpt.add_action (apageaction);
571 }
572
573 if (apingaction == NULL) {
574 apingaction = new pingaction();
575 recpt.add_action (apingaction);
576 }
577
578 if (atipaction == NULL) {
579 atipaction = new tipaction();
580 recpt.add_action (atipaction);
581 }
582
583 if (aqueryaction == NULL) {
584 aqueryaction = new queryaction();
585 aqueryaction->set_receptionist (&recpt);
586 recpt.add_action (aqueryaction);
587 }
588
589#if defined(USE_SQLITE)
590 if (asqlqueryaction == NULL) {
591 asqlqueryaction = new sqlqueryaction();
592 asqlqueryaction->set_receptionist (&recpt);
593 recpt.add_action (asqlqueryaction);
594 }
595#endif
596
597 if (adocumentaction == NULL) {
598 adocumentaction = new documentaction();
599 adocumentaction->set_receptionist (&recpt);
600 recpt.add_action (adocumentaction);
601 }
602
603 if (ausersaction == NULL) {
604 ausersaction = new usersaction();
605 ausersaction->set_userdb(udb);
606 recpt.add_action (ausersaction);
607 }
608
609 if (anextlinkaction == NULL) {
610 anextlinkaction = new extlinkaction();
611 recpt.add_action (anextlinkaction);
612 }
613
614 if (acollectoraction == NULL) {
615 acollectoraction = new collectoraction();
616 acollectoraction->set_receptionist (&recpt);
617 recpt.add_action (acollectoraction);
618 }
619
620 if (aauthenaction == NULL) {
621 aauthenaction = new authenaction();
622 aauthenaction->set_userdb(udb);
623 aauthenaction->set_keydb(kdb);
624 aauthenaction->set_receptionist(&recpt);
625 recpt.add_action (aauthenaction);
626 }
627
628#ifdef ENABLE_MGPP
629 if (aphindaction == NULL) {
630 aphindaction = new phindaction();
631 recpt.add_action (aphindaction);
632 }
633#endif
634
635 if (aconfigaction == NULL) {
636 aconfigaction = new configaction();
637 aconfigaction->set_receptionist(&recpt);
638 recpt.add_action (aconfigaction);
639 }
640
641 if (adynamicclassifieraction == NULL) {
642 adynamicclassifieraction = new dynamicclassifieraction();
643 adynamicclassifieraction->set_receptionist(&recpt);
644 recpt.add_action (adynamicclassifieraction);
645 }
646
647
648 // list of browsers
649 if (avlistbrowserclass == NULL) {
650 avlistbrowserclass = new vlistbrowserclass();
651 recpt.add_browser (avlistbrowserclass);
652 recpt.setdefaultbrowser ("VList");
653 }
654
655 if (ahlistbrowserclass == NULL) {
656 ahlistbrowserclass = new hlistbrowserclass();
657 recpt.add_browser (ahlistbrowserclass);
658 }
659
660 if (adatelistbrowserclass == NULL) {
661 adatelistbrowserclass = new datelistbrowserclass();
662 recpt.add_browser (adatelistbrowserclass);
663 }
664
665 if (ainvbrowserclass == NULL) {
666 ainvbrowserclass = new invbrowserclass();
667 recpt.add_browser (ainvbrowserclass);
668 }
669
670 if (apagedbrowserclass == NULL) {
671 apagedbrowserclass = new pagedbrowserclass();
672 recpt.add_browser (apagedbrowserclass);
673 }
674
675 if (ahtmlbrowserclass == NULL) {
676 ahtmlbrowserclass = new htmlbrowserclass();
677 recpt.add_browser (ahtmlbrowserclass);
678 }
679
680 if (aphindbrowserclass == NULL) {
681 aphindbrowserclass = new phindbrowserclass();;
682 recpt.add_browser (aphindbrowserclass);
683 }
684
685 // set defaults
686 recpt.configure ("gsdlhome", gsdl_gsdlhome);
687 recpt.configure ("collecthome", gsdl_collecthome);
688 recpt.configure ("gdbmhome", gsdl_dbhome);
689 recpt.configure ("collection", collection);
690
691 int maxrequests = 1;
692
693 // configure collections (and receptionist) with collectinfo stuff
694 // different from the default
695 colinfo_tmap::const_iterator this_info = translated_collectinfo.begin();
696 colinfo_tmap::const_iterator end_info = translated_collectinfo.end();
697
698 while (this_info != end_info) {
699 text_tarray tmpconf;
700 tmpconf.push_back ((*this_info).first);
701 tmpconf.push_back ((*this_info).second.gsdl_gsdlhome);
702 tmpconf.push_back ((*this_info).second.gsdl_collecthome);
703 tmpconf.push_back ((*this_info).second.gsdl_dbhome);
704 recpt.configure ("collectinfo", tmpconf);
705 ++this_info;
706 }
707
708 // read in config files of each dbhome (in no particular order)
709 // those read in last will override those read earlier
710 // collections being used together in this way should be
711 // careful not to have main.cfg files that might
712 // interfere with each other.
713 text_tset::const_iterator thome = dbhomes.begin();
714 text_tset::const_iterator ehome = dbhomes.end();
715 text_tset::const_iterator tchome = clhomes.begin(); // collecthome companion for dbhome
716
717 while (thome != ehome) {
718 if (!main_cfg_read (recpt, *thome, *tchome, collection)) {
719 // couldn't find the main configuration file
720 page_errormaincfg (*thome, collection);
721 return 0;
722 }
723 ++thome;
724 ++tchome;
725 }
726
727 // w32server relies on gwcgi being set to "gsdl", and httpweb to web
728 recpt.configure ("gwcgi", "gsdl");
729 recpt.configure ("httpweb", "web");
730
731 // initialise the library software
732 if (!recpt.init(cerr)) {
733 // an error occurred during the initialisation
734 page_errorinit(gsdl_gsdlhome);
735 return 0;
736 }
737
738 // get memory information
739 MEMORYSTATUS memstatus;
740 memstatus.dwLength = sizeof(MEMORYSTATUS);
741 GlobalMemoryStatus(&memstatus);
742 baseavailvirtual = memstatus.dwAvailVirtual; // save for later comparison
743
744 return 1;
745}
746
747
748static void rememberpref (const text_t &tailstr) {
749 gsdl_enterlib = tailstr;
750}
751
752
753static void send_file_from_disk(text_t filename,
754 RequestInfoT *RInfo,
755 RequestFieldsT *RFields) {
756
757 // select appropriate mime type from file extension
758 text_t ext;
759 text_t::const_iterator end = filename.end();
760 text_t::const_iterator it = filename.begin();
761 text_t::const_iterator lastdot = end;
762 while ((it = findchar(it, end, '.')) != end) {
763 lastdot = it;
764 ++it;
765 }
766 if (lastdot < end) ext = substr(lastdot+1, end);
767
768 text_t mime = "unknown";
769 int len = ext.size();
770 if (len == 2) {
771 if ((ext[0] == 'p' || ext[0] == 'P') &&
772 (ext[1] == 's' || ext[1] == 'S'))
773 mime = "application/postscript";
774 } else if (len == 3) {
775 if((ext[0] == 'c' || ext[0] == 'C') &&
776 (ext[1] == 's' || ext[1] == 'S') &&
777 (ext[2] == 's' || ext[2] == 'S')){
778 mime = "text/css";
779 } else if ((ext[0] == 'g' || ext[0] == 'G') &&
780 (ext[1] == 'i' || ext[1] == 'I') &&
781 (ext[2] == 'f' || ext[2] == 'F')) {
782 mime = "image/gif";
783 } else if ((ext[0] == 'j' || ext[0] == 'J') &&
784 (ext[1] == 'p' || ext[1] == 'P') &&
785 (ext[2] == 'g' || ext[2] == 'G')) {
786 mime = "image/jpeg";
787 } else if ((ext[0] == 'h' || ext[0] == 'H') &&
788 (ext[1] == 't' || ext[1] == 'T') &&
789 (ext[2] == 'm' || ext[2] == 'M')) {
790 mime = "text/html";
791 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
792 (ext[1] == 'd' || ext[1] == 'D') &&
793 (ext[2] == 'f' || ext[2] == 'F')) {
794 mime = "application/pdf";
795 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
796 (ext[1] == 'n' || ext[1] == 'N') &&
797 (ext[2] == 'g' || ext[2] == 'G')) {
798 mime = "image/png";
799 } else if ((ext[0] == 'd' || ext[0] == 'D') &&
800 (ext[1] == 'o' || ext[1] == 'O') &&
801 (ext[2] == 'c' || ext[2] == 'C')) {
802 mime = "application/msword";
803 } else if ((ext[0] == 'r' || ext[0] == 'R') &&
804 (ext[1] == 't' || ext[1] == 'T') &&
805 (ext[2] == 'f' || ext[2] == 'F')) {
806 mime = "application/rtf";
807 } else if ((ext[0] == 'x' || ext[0] == 'X') &&
808 (ext[1] == 'l' || ext[1] == 'L') &&
809 (ext[2] == 's' || ext[2] == 'S')) {
810 mime = "application/vnd.ms-excel";
811 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
812 (ext[1] == 'p' || ext[1] == 'P') &&
813 (ext[2] == 'T' || ext[2] == 'T')) {
814 mime = "application/vnd.ms-powerpoint";
815 } else if ((ext[0] == 'm' || ext[0] == 'M') &&
816 (ext[1] == 'p' || ext[1] == 'P') &&
817 (ext[2] == '3')) {
818 mime = "audio/mpeg";
819 }
820 } else if (len == 4) {
821 if ((ext[0] == 'j' || ext[0] == 'J') &&
822 (ext[1] == 'p' || ext[1] == 'P') &&
823 (ext[2] == 'e' || ext[2] == 'E') &&
824 (ext[3] == 'g' || ext[3] == 'G')) {
825 mime = "image/jpeg";
826 } else if ((ext[0] == 'h' || ext[0] == 'H') &&
827 (ext[1] == 't' || ext[1] == 'T') &&
828 (ext[2] == 'm' || ext[2] == 'M') &&
829 (ext[3] == 'l' || ext[3] == 'L')) {
830 mime = "text/html";
831 }
832 }
833
834 // try to open the file
835 //cerr << "*** filename = " << filename.getcstr() << endl;
836 //cerr << "**** collect_home = " << current_collecthome.getcstr() << endl;
837
838 if (filename.size()>=9) {
839 text_t prefix = substr(filename.begin(),filename.begin()+9);
840 //cerr << "**** prefix = " << prefix.getcstr() << endl;
841
842 text_t tail = substr(filename.begin()+9,filename.end());
843 //cerr << "**** tail = " << tail.getcstr() << endl;
844
845 if (prefix == "/collect/") {
846 filename = filename_cat (current_collecthome, tail);
847 }
848 else {
849 filename = filename_cat (current_gsdlhome, filename);
850 }
851 }
852
853 cerr << "#### filename = " << filename.getcstr() << endl;
854
855 /* Feb 2002 - handle files with spaces in their name. */
856 text_t::iterator space_start;
857 space_start=findword(filename.begin(),filename.end(),"%20");
858 while (space_start != filename.end()) {
859 // we found a space...
860 text_t::iterator after_space=space_start+3;
861 text_t new_filename=substr(filename.begin(), space_start);
862 new_filename += " ";
863 new_filename += substr(after_space,filename.end());
864 filename=new_filename;
865 space_start=findword(filename.begin(),filename.end(),"%20");
866 }
867
868 char *filenamec = filename.getcstr();
869 TranslateEscapeString(filenamec); // Resolve any %xx values
870 FILE *thefile = fopen(filenamec, "rb");
871 delete []filenamec;
872 if (thefile == NULL) {
873 log_message("file not found\n");
874 send_retrieve_error(404, "File not found",
875 "Could not find the local file requested", RInfo);
876 return;
877 }
878 int nr;
879 char buffer[2048];
880 // send back required information
881 char *mimec = mime.getcstr();
882 if (send_header(mimec, RInfo) >= 0) {
883 if (RFields->MethodStr != "HEAD") {
884 for (;;) {
885 nr = fread(buffer, 1, 2048, thefile);
886 if (nr <= 0) break;
887 if (SendData(RInfo->ClientSocket,
888 (BYTE *)buffer, nr,
889 RInfo->ThreadNum) < 0) break;
890 }
891 }
892 }
893 delete []mimec;
894 fclose(thefile);
895}
896
897static void handle_library_request(const text_t &argstr, RequestInfoT *RInfo,
898 RequestFieldsT *RequestFields) {
899
900 // parse the cgi arguments and produce the resulting page if there
901 // have been no errors so far
902 cgiargsclass args;
903 fileupload_tmap fileuploads;
904 text_tmap empty; // don't use this (it's for fastcgi on unix)
905 if (!recpt.parse_cgi_args (argstr, fileuploads, args, cerr, empty)) {
906 page_errorparseargs(gsdl_gsdlhome);
907 return;
908 }
909
910 colinfo_tmap::const_iterator it = translated_collectinfo.find (args["c"]);
911 if (it != translated_collectinfo.end()) {
912 current_gsdlhome = (*it).second.gsdl_gsdlhome;
913 current_collecthome = (*it).second.gsdl_collecthome;
914 } else {
915 current_gsdlhome = gsdl_gsdlhome;
916 current_collecthome = gsdl_collecthome;
917 }
918
919 // produce cgi header
920 response_t response;
921 text_t response_data;
922
923 recpt.get_cgihead_info (args, response, response_data, cerr, empty);
924
925 if (response == location) {
926 // location response
927 response_data = "@" + recpt.expandmacros (response_data, args, cerr);
928 char *response_data_c = response_data.getcstr();
929 send_header(response_data_c, RInfo);
930 delete []response_data_c;
931 return;
932 } else if (response == content) {
933 // content response
934 char *response_data_c = response_data.getcstr();
935 if (send_header(response_data_c, RInfo) < 0) {
936 delete []response_data_c;
937 return;
938 }
939 delete []response_data_c;
940 }
941 else if (response == undecided_location) {
942 // We know this is a relocation request but at the moment we don't know exactly where to
943 // Just output the start of the header and wait until later to output the target location
944 // Used for the "I'm feeling lucky" functionality
945 cout << "HTTP/1.0 302 Relocation\r\n";
946 cout << "Server: GSDL\r\n";
947 cout << "Content-type: text/html \r\n";
948 }
949 else {
950 // unknown response
951 cerr << "Error: get_cgihead_info returned an unknown response type.\n";
952 return;
953 }
954
955 textstream.tsbreset();
956 textstream.setrequestinfo (RInfo);
957 if (!recpt.produce_content (args, cout, cerr)) {
958 page_errorcgipage(gsdl_gsdlhome);
959 return;
960 }
961 recpt.log_cgi_args (args, cerr, empty);
962
963 cout << flush;
964 cerr << flush;
965
966 ++libaccessnum;
967}
968
969static void handle_server_request(text_t &tailstr,
970 RequestInfoT *RequestInfo,
971 RequestFieldsT *RequestFields) {
972
973 text_t argstr;
974
975 // do any url adjustments necessary
976 if (tailstr.empty() || tailstr == "/") {
977 tailstr = "/gsdl";
978 }
979
980 text_t::const_iterator begin = tailstr.begin();
981 text_t::const_iterator end = tailstr.end();
982
983 // test to see if this is a library request or a local
984 // file request
985 if ((tailstr == "/gsdl") ||
986 ((tailstr.size() > 5) && (substr(begin, begin+6) == "/gsdl?"))) {
987
988 // library request
989
990 // argstr is the bit after the '?'
991 if (tailstr != "/gsdl") {
992 argstr = substr(begin+6, end);
993 }
994
995 // log the difference in access times
996 DWORD thislibaccesstime = GetTickCount();
997 if (gsdl_keep_log || gsdl_show_console) {
998 char logstr[256];
999 sprintf(logstr, "DELTA LIB ACCESS TIME: %i\n", (int)(thislibaccesstime - lastlibaccesstime));
1000 log_message (logstr);
1001 }
1002 lastlibaccesstime = thislibaccesstime;
1003
1004 // log this request
1005 if (gsdl_keep_log || gsdl_show_console) {
1006 text_t logstr = "LOCAL LIB: " + tailstr + "\n";
1007 char *logstrc = logstr.getcstr();
1008 log_message (logstrc);
1009 delete []logstrc;
1010 }
1011
1012 handle_library_request (argstr, RequestInfo, RequestFields);
1013
1014 // remember the preferences
1015 // rememberpref (tailstr);
1016
1017 // log memory information
1018 if (gsdl_keep_log || gsdl_show_console) {
1019 MEMORYSTATUS memstatus;
1020 memstatus.dwLength = sizeof(MEMORYSTATUS);
1021 GlobalMemoryStatus(&memstatus);
1022 char logstr[256];
1023 sprintf (logstr, "BDELTA AVAIL VIRTUAL: %i K\n",
1024 (int)((baseavailvirtual - memstatus.dwAvailVirtual)/1024));
1025 log_message (logstr);
1026 }
1027
1028 } else {
1029 // local file
1030 if (gsdl_keep_log || gsdl_show_console) {
1031 text_t logstr = "LOCAL FILE: " + tailstr + "\n";
1032 char *logstrc = logstr.getcstr();
1033 log_message (logstrc);
1034 delete []logstrc;
1035 }
1036 send_file_from_disk (tailstr, RequestInfo, RequestFields);
1037 }
1038}
1039
1040int ExamineURIStr(text_t &URIStr, RequestInfoT *RequestInfo,
1041 RequestFieldsT *RequestFields)
1042{
1043 text_t protocol, machine, rest;
1044 int port;
1045
1046 if (RequestFields->ContentLength > 0) {
1047 // POST data
1048 URIStr.push_back('?');
1049 for (int i = 0; i < RequestFields->ContentLength; ++i) {
1050 URIStr.push_back(RequestFields->Content[i]);
1051 }
1052 }
1053
1054 if (parse_url(URIStr, protocol, machine, &port, rest)!=http_ok) {
1055 // Alter local file request to address 'gsdl'
1056 if (*(URIStr.begin()) != '/') URIStr = "http://gsdl/" + URIStr;
1057 else URIStr = "http://gsdl" + URIStr;
1058 parse_url(URIStr, protocol, machine, &port, rest);
1059 }
1060
1061 if (machine == "gsdl") {
1062 // a local file request
1063 handle_server_request(rest, RequestInfo, RequestFields);
1064
1065 } else {
1066 send_retrieve_error(404, "File not found",
1067 "Could not find the local file requested", RequestInfo);
1068 }
1069
1070 return 1;
1071}
Note: See TracBrowser for help on using the repository browser.