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

Revision 22822, 31.9 KB (checked in by ak19, 10 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
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 browser.