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

Revision 15625, 28.2 KB (checked in by mdewsnip, 11 years ago)

(Adding new DB support) Replaced a bunch of "gdbmhome" with "dbhome".

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