root/gsdl/trunk/src/w32server/cgiwrapper.cpp @ 16320

Revision 16320, 28.8 KB (checked in by davidb, 11 years ago)

Introduction of 'collecthome' to support collections outside of the gsdlhome area

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