source: gsdl/trunk/src/w32server/cgiwrapper.cpp@ 14407

Last change on this file since 14407 was 14407, checked in by qq6, 17 years ago

fixed a bug of defining userdbclass and keydbclass

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