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

Revision 27220, 32.3 KB (checked in by kjdon, 8 years ago)

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

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