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

Last change on this file since 9138 was 9138, checked in by mdewsnip, 19 years ago

Ooooops... the "I'm Feeling Lucky" functionality didn't work at all for the Local Library.

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