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

Revision 19062, 30.0 KB (checked in by kjdon, 10 years ago)

all gdbm files (key, users, history, argdb) now use gdb extension instead of db

  • 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    collections.insert (*colhere);
468    collectioninfo_t tmp;
469    tmp.gsdl_gsdlhome = gsdl_gsdlhome;
470    tmp.gsdl_collecthome = gsdl_collecthome;
471    tmp.gsdl_dbhome = gsdl_dbhome;
472    translated_collectinfo[*colhere] = tmp;
473    ++colhere;
474      }
475      dbhomes.insert (gsdl_dbhome);
476      clhomes.insert (gsdl_collecthome);
477    }
478  }
479
480  text_tset::const_iterator thiscol = collections.begin();
481  text_tset::const_iterator endcol = collections.end();
482
483  while (thiscol != endcol) {
484   
485    // ignore the modelcol
486    if (*thiscol == "modelcol") {
487      ++thiscol;
488      continue;
489    }
490   
491    // create collection server and add to null protocol
492    text_t this_gsdlhome = gsdl_gsdlhome;
493    text_t this_collecthome = gsdl_collecthome;
494    text_t this_dbhome = gsdl_dbhome;
495    colinfo_tmap::const_iterator it = translated_collectinfo.find (*thiscol);
496    assert (it != translated_collectinfo.end());
497    this_gsdlhome = (*it).second.gsdl_gsdlhome;
498    this_collecthome = (*it).second.gsdl_collecthome;
499    this_dbhome = (*it).second.gsdl_dbhome;
500
501    cservers->add_collection (*thiscol, this_gsdlhome, this_collecthome);
502    // in case it is a collection group
503    cservers->add_collection_group(*thiscol, this_gsdlhome, this_collecthome);
504   
505    ++thiscol;
506  }
507 
508  // set up the null protocol
509  nproto.set_collectset(cservers);
510 
511  if ((ausersaction == NULL) && (aauthenaction == NULL)){
512    userdbfile = filename_cat(gsdl_gsdlhome, "etc", "users.gdb");
513    udb = new userdbclass(userdbfile);
514    keydbfile = filename_cat(gsdl_gsdlhome, "etc", "key.gdb");
515    kdb = new keydbclass(keydbfile);
516  }
517  // add the protocol to the receptionist
518  if (atStartup) recpt.add_protocol (&nproto);
519 
520  // the list of actions.
521  if (astatusaction == NULL) {
522    astatusaction = new statusaction();
523    astatusaction->set_receptionist (&recpt);
524    recpt.add_action (astatusaction);
525  }
526 
527  if (apageaction == NULL) {
528    apageaction = new pageaction();
529    apageaction->set_receptionist (&recpt);
530    recpt.add_action (apageaction);
531  }
532 
533  if (apingaction == NULL) {
534    apingaction = new pingaction();
535    recpt.add_action (apingaction);
536  }
537 
538  if (atipaction == NULL) {
539    atipaction = new tipaction();
540    recpt.add_action (atipaction);
541  }
542 
543  if (aqueryaction == NULL) {
544    aqueryaction = new queryaction();
545    aqueryaction->set_receptionist (&recpt);
546    recpt.add_action (aqueryaction);
547  }
548 
549  if (adocumentaction == NULL) {
550    adocumentaction = new documentaction();
551    adocumentaction->set_receptionist (&recpt);
552    recpt.add_action (adocumentaction);
553  }
554 
555  if (ausersaction == NULL) {
556    ausersaction = new usersaction();
557    ausersaction->set_userdb(udb);
558    recpt.add_action (ausersaction);
559  }
560
561  if (anextlinkaction == NULL) {
562    anextlinkaction = new extlinkaction();
563    recpt.add_action (anextlinkaction);
564  }
565
566  if (acollectoraction == NULL) {
567    acollectoraction = new collectoraction();
568    acollectoraction->set_receptionist (&recpt);
569    recpt.add_action (acollectoraction);
570  }
571 
572  if (aauthenaction == NULL) {
573    aauthenaction = new authenaction();
574    aauthenaction->set_userdb(udb);
575    aauthenaction->set_keydb(kdb);
576    aauthenaction->set_receptionist(&recpt);
577    recpt.add_action (aauthenaction);
578  }
579
580  if (aphindaction == NULL) {
581    aphindaction = new phindaction();
582    recpt.add_action (aphindaction);
583  }
584 
585  if (aconfigaction == NULL) {
586    aconfigaction = new configaction();
587    aconfigaction->set_receptionist(&recpt);
588    recpt.add_action (aconfigaction);
589  }
590 
591  if (adynamicclassifieraction == NULL) {
592    adynamicclassifieraction = new dynamicclassifieraction();
593    adynamicclassifieraction->set_receptionist(&recpt);
594    recpt.add_action (adynamicclassifieraction);
595  }
596
597
598  // list of browsers
599  if (avlistbrowserclass == NULL) {
600    avlistbrowserclass = new vlistbrowserclass();
601    recpt.add_browser (avlistbrowserclass);
602    recpt.setdefaultbrowser ("VList");
603  }
604
605  if (ahlistbrowserclass == NULL) {
606    ahlistbrowserclass = new hlistbrowserclass();
607    recpt.add_browser (ahlistbrowserclass);
608  }
609
610  if (adatelistbrowserclass == NULL) {
611    adatelistbrowserclass = new datelistbrowserclass();
612    recpt.add_browser (adatelistbrowserclass);
613  }
614
615  if (ainvbrowserclass == NULL) {
616    ainvbrowserclass = new invbrowserclass();
617    recpt.add_browser (ainvbrowserclass);
618  }
619
620  if (apagedbrowserclass == NULL) {
621    apagedbrowserclass = new pagedbrowserclass();
622    recpt.add_browser (apagedbrowserclass);
623  }
624
625  if (ahtmlbrowserclass == NULL) {
626    ahtmlbrowserclass = new htmlbrowserclass();
627    recpt.add_browser (ahtmlbrowserclass);
628  }
629
630  if (aphindbrowserclass == NULL) {
631    aphindbrowserclass = new phindbrowserclass();;
632    recpt.add_browser (aphindbrowserclass);
633  }
634 
635  // set defaults
636  recpt.configure ("gsdlhome", gsdl_gsdlhome);
637  recpt.configure ("collecthome", gsdl_collecthome);
638  recpt.configure ("gdbmhome", gsdl_dbhome);
639  recpt.configure ("collection", collection);
640
641  int maxrequests = 1;
642
643  // configure collections (and receptionist) with collectinfo stuff
644  // different from the default
645  colinfo_tmap::const_iterator this_info = translated_collectinfo.begin();
646  colinfo_tmap::const_iterator end_info = translated_collectinfo.end();
647
648  while (this_info != end_info) {
649    text_tarray tmpconf;
650    tmpconf.push_back ((*this_info).first);
651    tmpconf.push_back ((*this_info).second.gsdl_gsdlhome);
652    tmpconf.push_back ((*this_info).second.gsdl_collecthome);
653    tmpconf.push_back ((*this_info).second.gsdl_dbhome);
654    recpt.configure ("collectinfo", tmpconf);
655    ++this_info;
656  }
657
658  // read in config files of each dbhome (in no particular order)
659  // those read in last will override those read earlier
660  // collections being used together in this way should be
661  // careful not to have main.cfg files that might
662  // interfere with each other.
663  text_tset::const_iterator thome = dbhomes.begin();
664  text_tset::const_iterator ehome = dbhomes.end();
665  text_tset::const_iterator tchome = clhomes.begin(); // collecthome companion for dbhome
666
667  while (thome != ehome) {
668    if (!main_cfg_read (recpt, *thome, *tchome, collection)) {
669      // couldn't find the main configuration file
670      page_errormaincfg (*thome, collection);
671      return 0;
672    }
673    ++thome;
674    ++tchome;
675  }
676
677  // w32server relies on gwcgi being set to "gsdl"
678  recpt.configure ("gwcgi", "gsdl");
679   
680  // initialise the library software
681  if (!recpt.init(cerr)) {
682    // an error occurred during the initialisation
683    page_errorinit(gsdl_gsdlhome);
684    return 0;
685  }
686
687  // get memory information
688  MEMORYSTATUS memstatus;
689  memstatus.dwLength = sizeof(MEMORYSTATUS);
690  GlobalMemoryStatus(&memstatus);
691  baseavailvirtual = memstatus.dwAvailVirtual; // save for later comparison
692
693  return 1;
694}
695
696
697static void rememberpref (const text_t &tailstr) {
698  gsdl_enterlib = tailstr;
699}
700
701
702static void send_file_from_disk(text_t filename,
703                                RequestInfoT *RInfo,
704                                RequestFieldsT *RFields) {
705 
706  // select appropriate mime type from file extension
707  text_t ext;
708  text_t::const_iterator end = filename.end();
709  text_t::const_iterator it = filename.begin();
710  text_t::const_iterator lastdot = end;
711  while ((it = findchar(it, end, '.')) != end) {
712    lastdot = it;
713    ++it;
714  }
715  if (lastdot < end) ext = substr(lastdot+1, end);
716
717  text_t mime = "unknown";
718  int len = ext.size();
719  if (len == 2) {
720    if ((ext[0] == 'p' || ext[0] == 'P') &&
721    (ext[1] == 's' || ext[1] == 'S'))
722      mime = "application/postscript";
723  }  else if (len == 3) {
724    if ((ext[0] == 'g' || ext[0] == 'G') &&
725    (ext[1] == 'i' || ext[1] == 'I') &&
726    (ext[2] == 'f' || ext[2] == 'F')) {
727      mime = "image/gif";
728    } else if ((ext[0] == 'j' || ext[0] == 'J') &&
729           (ext[1] == 'p' || ext[1] == 'P') &&
730           (ext[2] == 'g' || ext[2] == 'G')) {
731      mime = "image/jpeg";
732    } else if ((ext[0] == 'h' || ext[0] == 'H') &&
733           (ext[1] == 't' || ext[1] == 'T') &&
734           (ext[2] == 'm' || ext[2] == 'M')) {
735      mime = "text/html";
736    } else if ((ext[0] == 'p' || ext[0] == 'P') &&
737           (ext[1] == 'd' || ext[1] == 'D') &&
738           (ext[2] == 'f' || ext[2] == 'F')) {
739      mime = "application/pdf";
740    } else if ((ext[0] == 'p' || ext[0] == 'P') &&
741           (ext[1] == 'n' || ext[1] == 'N') &&
742           (ext[2] == 'g' || ext[2] == 'G')) {
743      mime = "image/png";
744    } else if ((ext[0] == 'd' || ext[0] == 'D') &&
745           (ext[1] == 'o' || ext[1] == 'O') &&
746           (ext[2] == 'c' || ext[2] == 'C')) {
747      mime = "application/msword";
748    } else if ((ext[0] == 'r' || ext[0] == 'R') &&
749           (ext[1] == 't' || ext[1] == 'T') &&
750           (ext[2] == 'f' || ext[2] == 'F')) {
751      mime = "application/rtf";
752    } else if ((ext[0] == 'x' || ext[0] == 'X') &&
753           (ext[1] == 'l' || ext[1] == 'L') &&
754           (ext[2] == 's' || ext[2] == 'S')) {
755      mime = "application/vnd.ms-excel";
756    } else if ((ext[0] == 'p' || ext[0] == 'P') &&
757           (ext[1] == 'p' || ext[1] == 'P') &&
758           (ext[2] == 'T' || ext[2] == 'T')) {
759      mime = "application/vnd.ms-powerpoint";
760    } else if ((ext[0] == 'm' || ext[0] == 'M') &&
761           (ext[1] == 'p' || ext[1] == 'P') &&
762           (ext[2] == '3')) {
763      mime = "audio/mpeg";
764    }
765  } else if (len == 4) {
766    if ((ext[0] == 'j' || ext[0] == 'J') &&
767    (ext[1] == 'p' || ext[1] == 'P') &&
768    (ext[2] == 'e' || ext[2] == 'E') &&
769    (ext[3] == 'g' || ext[3] == 'G')) {
770      mime = "image/jpeg";
771    } else if ((ext[0] == 'h' || ext[0] == 'H') &&
772           (ext[1] == 't' || ext[1] == 'T') &&
773           (ext[2] == 'm' || ext[2] == 'M') &&
774           (ext[3] == 'l' || ext[3] == 'L')) {
775      mime = "text/html";
776    }
777  }
778   
779  // try to open the file
780  //cerr << "*** filename = " << filename.getcstr() << endl;
781  //cerr << "**** collect_home = " << current_collecthome.getcstr() << endl;
782
783  if (filename.size()>=9) {
784    text_t prefix = substr(filename.begin(),filename.begin()+9);
785    //cerr << "**** prefix = " << prefix.getcstr() << endl;
786
787    text_t tail = substr(filename.begin()+9,filename.end());
788    //cerr << "**** tail = " << tail.getcstr() << endl;
789
790    if (prefix == "/collect/") {
791      filename = filename_cat (current_collecthome, tail);
792    }
793    else {
794      filename = filename_cat (current_gsdlhome, filename);
795    }
796  }
797
798  cerr << "#### filename = " << filename.getcstr() << endl;
799
800  /* Feb 2002 - handle files with spaces in their name. */
801  text_t::iterator space_start;
802  space_start=findword(filename.begin(),filename.end(),"%20");
803  while (space_start != filename.end()) {
804    // we found a space...
805    text_t::iterator after_space=space_start+3;
806    text_t new_filename=substr(filename.begin(), space_start);
807    new_filename += " ";
808    new_filename += substr(after_space,filename.end());
809    filename=new_filename;
810    space_start=findword(filename.begin(),filename.end(),"%20");
811  }
812
813  char *filenamec = filename.getcstr();
814  TranslateEscapeString(filenamec);  // Resolve any %xx values
815  FILE *thefile = fopen(filenamec, "rb");
816  delete []filenamec;
817  if (thefile == NULL) {
818    log_message("file not found\n");
819    send_retrieve_error(404, "File not found",
820            "Could not find the local file requested", RInfo);
821    return;
822  }
823  int nr;
824  char buffer[2048];
825  // send back required information
826  char *mimec = mime.getcstr();
827  if (send_header(mimec, RInfo) >= 0) {
828    if (RFields->MethodStr != "HEAD") {
829      for (;;) {
830        nr = fread(buffer, 1, 2048, thefile);
831        if (nr <= 0) break;
832        if (SendData(RInfo->ClientSocket,
833                     (BYTE *)buffer, nr,
834             RInfo->ThreadNum) < 0) break;       
835      }
836    }
837  }
838  delete []mimec;
839  fclose(thefile);
840}
841
842static void handle_library_request(const text_t &argstr, RequestInfoT *RInfo,
843                   RequestFieldsT *RequestFields) {
844
845  // parse the cgi arguments and produce the resulting page if there
846  // have been no errors so far
847  cgiargsclass args;
848  fileupload_tmap fileuploads;
849  text_tmap empty; // don't use this (it's for fastcgi on unix)
850  if (!recpt.parse_cgi_args (argstr, fileuploads, args, cerr, empty)) {
851    page_errorparseargs(gsdl_gsdlhome);
852    return;
853  }
854
855  colinfo_tmap::const_iterator it = translated_collectinfo.find (args["c"]);
856  if (it != translated_collectinfo.end()) {
857    current_gsdlhome = (*it).second.gsdl_gsdlhome;
858    current_collecthome = (*it).second.gsdl_collecthome;
859  } else {
860    current_gsdlhome = gsdl_gsdlhome;
861    current_collecthome = gsdl_collecthome;
862  }
863
864  // produce cgi header
865  response_t response;
866  text_t response_data;
867
868  recpt.get_cgihead_info (args, response, response_data, cerr, empty);
869
870  if (response == location) {
871    // location response
872    response_data = "@" + recpt.expandmacros (response_data, args, cerr);
873    char *response_data_c = response_data.getcstr();
874    send_header(response_data_c, RInfo);
875    delete []response_data_c;
876    return;
877  } else if (response == content) {
878    // content response
879    char *response_data_c = response_data.getcstr();
880    if (send_header(response_data_c, RInfo) < 0) {
881      delete []response_data_c;
882      return;
883    }
884    delete []response_data_c;
885  }
886  else if (response == undecided_location) {
887    // We know this is a relocation request but at the moment we don't know exactly where to
888    // Just output the start of the header and wait until later to output the target location
889    // Used for the "I'm feeling lucky" functionality
890    cout << "HTTP/1.0 302 Relocation\r\n";
891    cout << "Server: GSDL\r\n";
892    cout << "Content-type: text/html \r\n";
893  }
894  else {
895    // unknown response
896    cerr << "Error: get_cgihead_info returned an unknown response type.\n";
897    return;
898  }
899
900  textstream.tsbreset();
901  textstream.setrequestinfo (RInfo);
902  if (!recpt.produce_content (args, cout, cerr)) {
903    page_errorcgipage(gsdl_gsdlhome);
904    return;
905  }
906  recpt.log_cgi_args (args, cerr, empty);
907
908  cout << flush;
909  cerr << flush;
910 
911  ++libaccessnum;
912}
913
914static void handle_server_request(text_t &tailstr,
915                  RequestInfoT *RequestInfo,
916                  RequestFieldsT *RequestFields) {
917 
918  text_t argstr;
919
920  // do any url adjustments necessary
921  if (tailstr.empty() || tailstr == "/") {
922    tailstr = "/gsdl";
923  }
924
925  text_t::const_iterator begin = tailstr.begin();
926  text_t::const_iterator end = tailstr.end();
927 
928  // test to see if this is a library request or a local
929  // file request
930  if ((tailstr == "/gsdl") ||
931      ((tailstr.size() > 5) && (substr(begin, begin+6) == "/gsdl?"))) {
932
933    // library request
934   
935    // argstr is the bit after the '?'
936    if (tailstr != "/gsdl") {
937      argstr = substr(begin+6, end);
938    }
939
940    // log the difference in access times
941    DWORD thislibaccesstime = GetTickCount();
942    if (gsdl_keep_log || gsdl_show_console) {
943      char logstr[256];
944      sprintf(logstr, "DELTA LIB ACCESS TIME: %i\n", (int)(thislibaccesstime - lastlibaccesstime));
945      log_message (logstr);
946    }
947    lastlibaccesstime = thislibaccesstime;
948   
949    // log this request
950    if (gsdl_keep_log || gsdl_show_console) {
951      text_t logstr = "LOCAL LIB: " + tailstr + "\n";
952      char *logstrc = logstr.getcstr();
953      log_message (logstrc);
954      delete []logstrc;
955    }
956   
957    handle_library_request (argstr, RequestInfo, RequestFields);
958   
959    // remember the preferences
960    // rememberpref (tailstr);
961   
962    // log memory information
963    if (gsdl_keep_log || gsdl_show_console) {
964      MEMORYSTATUS memstatus;
965      memstatus.dwLength = sizeof(MEMORYSTATUS);
966      GlobalMemoryStatus(&memstatus);
967      char logstr[256];
968      sprintf (logstr, "BDELTA AVAIL VIRTUAL: %i K\n",
969           (int)((baseavailvirtual - memstatus.dwAvailVirtual)/1024));
970      log_message (logstr);
971    }
972   
973  } else {
974    // local file
975    if (gsdl_keep_log || gsdl_show_console) {
976      text_t logstr = "LOCAL FILE: " + tailstr + "\n";
977      char *logstrc = logstr.getcstr();
978      log_message (logstrc);
979      delete []logstrc;
980    }
981    send_file_from_disk (tailstr, RequestInfo, RequestFields);
982  }
983}
984
985int ExamineURIStr(text_t &URIStr, RequestInfoT *RequestInfo,
986          RequestFieldsT *RequestFields)
987{
988  text_t protocol, machine, rest;
989  int port;
990
991  if (RequestFields->ContentLength > 0) {
992    // POST data
993    URIStr.push_back('?');
994    for (int i = 0; i < RequestFields->ContentLength; ++i) {
995      URIStr.push_back(RequestFields->Content[i]);
996    }
997  }
998 
999  if (parse_url(URIStr, protocol, machine, &port, rest)!=http_ok) {
1000    // Alter local file request to address 'gsdl'
1001    if (*(URIStr.begin()) != '/') URIStr = "http://gsdl/" + URIStr;
1002    else URIStr = "http://gsdl" + URIStr;
1003    parse_url(URIStr, protocol, machine, &port, rest);
1004  }
1005
1006  if (machine == "gsdl") {
1007    // a local file request
1008    handle_server_request(rest, RequestInfo, RequestFields);
1009   
1010  } else {
1011    send_retrieve_error(404, "File not found",
1012            "Could not find the local file requested", RequestInfo);
1013  }
1014 
1015  return 1;
1016}
Note: See TracBrowser for help on using the browser.