root/gsdl/trunk/runtime-src/src/w32server/cgiwrapper.cpp @ 19788

Revision 19788, 30.2 KB (checked in by kjdon, 10 years ago)

moved the text for existence of build.cfg out of w32server/cgiwrapper and into colserver/collectset. This was preventing collect groups from being loaded up as they are not built. Now, unbuilt collections will not be loaded up for linux either

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