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

Last change on this file since 20999 was 19788, checked in by kjdon, 15 years ago

moved the text for existence of build.cfg out of w32server/cgiwrapper and into colserver/collectset. This was preventing collect groups from being loaded up as they are not built. Now, unbuilt collections will not be loaded up for linux either

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