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

Revision 16975, 29.8 KB (checked in by davidb, 11 years ago)

support for /collect in URL pointing to area designated by 'collecthome'

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