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

Revision 25560, 32.3 KB (checked in by ak19, 8 years ago)

Dr Bainbridge has introduced the isPersistentAction (add the a=is-persistent to the library url). It is true for server.exe and when using mod_gsdl, but false for library.cgi which uses the apache web server (when not using mod_gsdl).

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