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

Last change on this file since 22822 was 22822, checked in by ak19, 14 years ago

Further changes for ticket 152 (movable collectdir), to get server.exe to load all the collections in a non-standard collectdirectory. Previously the code read in collections in any collecthome property listed in a section OTHER THAN the default [gsdl] section of gli/llssite.cfg. Adjusted the code to handle a non-standard collecthome value specified in the [gsdl] section itself.

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