source: main/trunk/greenstone2/runtime-src/src/w32server/cgiwrapper.cpp@ 27220

Last change on this file since 27220 was 27220, checked in by kjdon, 11 years ago

cross coll search authentication. Need to make the same cgiwrapper mod in w32server for local library

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