source: branches/New_Config_Format-branch/gsdl/src/recpt/receptionist.cpp@ 1279

Last change on this file since 1279 was 1279, checked in by sjboddie, 24 years ago

merged changes to trunk into New_Config_Format branch

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 44.5 KB
Line 
1/**********************************************************************
2 *
3 * receptionist.cpp -- a web interface for the gsdl
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 * $Id: receptionist.cpp 1279 2000-07-12 22:21:53Z sjboddie $
25 *
26 *********************************************************************/
27
28/*
29 $Log$
30 Revision 1.47.4.1 2000/07/12 22:21:44 sjboddie
31 merged changes to trunk into New_Config_Format branch
32
33 Revision 1.53 2000/07/05 21:49:34 sjboddie
34 Receptionist now caches collection information to avoid making multiple
35 get_collectinfo calls to collection server
36
37 Revision 1.52 2000/07/04 02:15:22 sjboddie
38 fixed bug causing segmentation fault when an invalid collection
39 was supplied as the "c" cgi argument
40
41 Revision 1.51 2000/05/28 09:15:34 sjboddie
42 a few small changes to get an initial release of the local library
43
44 Revision 1.50 2000/05/12 03:09:25 sjboddie
45 minor modifications to get web library compiling under VC++ 6.0
46
47 Revision 1.49 2000/05/04 05:18:46 sjboddie
48 attempting to get end-user collection building to work under windows
49
50 Revision 1.48 2000/04/14 02:52:06 sjboddie
51 tidied up error messaging and set up some debugging info to be output
52 when running library from command line
53
54 Revision 1.47 2000/02/17 22:26:17 sjboddie
55 set macros for displaying macrons in utf8
56
57 Revision 1.46 2000/02/17 02:34:09 sjboddie
58 made compressedoptions macro dm_safe - added SCRIPT_NAME to log string
59
60 Revision 1.45 2000/02/03 01:48:52 sjboddie
61 fixed potential bug in ccscols stuff
62
63 Revision 1.44 2000/01/24 22:53:09 sjboddie
64 a few small changes to get fastcgi working properly here at Waikato -
65 hopefully changes will work everywhere ...
66
67 Revision 1.43 1999/12/06 01:14:16 sjboddie
68 added arabic encoding
69
70 Revision 1.42 1999/12/05 21:21:04 sjboddie
71 added support for multiple gsdlhomes and gdbmhomes
72
73 Revision 1.41 1999/11/25 21:44:16 sjboddie
74 fixed bug in logout
75
76 Revision 1.40 1999/11/08 20:26:37 sjboddie
77 added multiplevalue option to cgiarginfo
78
79 Revision 1.39 1999/11/03 22:49:10 sjboddie
80 A location url may now contain macros
81
82 Revision 1.38 1999/11/01 21:49:34 sjboddie
83 changes to arguments of many functions
84
85 Revision 1.37 1999/10/20 03:55:03 sjboddie
86 yet another problem with calling browserclass
87 processOID functions correctly
88
89 Revision 1.36 1999/10/19 03:23:44 davidb
90 Collection building support through web pages
91 and internal and external link handling for collection documents
92
93 Revision 1.35 1999/10/18 20:07:05 sjboddie
94 tidied up a few things - moved processing of "hp" argument
95 to htmlbrowserclass
96
97 Revision 1.34 1999/10/14 23:00:52 sjboddie
98 finished changes to browsing support
99
100 Revision 1.33 1999/10/10 08:14:10 sjboddie
101 - metadata now returns mp rather than array
102 - redesigned browsing support (although it's not finished so
103 won't currently work ;-)
104
105 Revision 1.32 1999/09/21 11:28:45 sjboddie
106 tidied up file locking
107
108 Revision 1.31 1999/09/16 21:38:17 sjboddie
109 added some file locking stuff for logging. Windows still needs to
110 be done.
111
112 Revision 1.30 1999/09/07 04:56:58 sjboddie
113 added GPL notice
114
115 Revision 1.29 1999/09/03 10:02:30 rjmcnab
116 Made the page parameters configurable. Now the page parameters must
117 correspond to cgi arguments in name and value (ie language=zh should now
118 be l=zh) which makes things more consistent anyway. Removed a couple of
119 specialised NZDL page parameters.
120
121 Moved the combining of the cgi arguments so that the receptionist does
122 all the configuration now.
123
124 Made the macro precedence configurable.
125
126 Made cgi arguments totally configurable. Now any piece of information about
127 a cgi argument can be configured meaning that cgi arguments can be declared
128 from the configuration file.
129
130 Removed the argdefault configuration argument. This should now be done
131 using cgiarg.
132
133 Revision 1.28 1999/09/03 04:39:46 rjmcnab
134 Made cookies and logs optional (they are turned off by default). To
135 turn them on put
136
137 usecookies true
138 logcgiargs true
139
140 in your configuration file.
141
142 Revision 1.27 1999/09/02 00:27:21 rjmcnab
143 A few small things.
144
145 Revision 1.26 1999/08/25 04:43:06 sjboddie
146 made FilterRequest_t::docSet an array rather than a set
147
148 Revision 1.25 1999/08/20 00:59:01 sjboddie
149 -fixed up location redirection
150 -added some usage logging, also now set a GSDL_UID cookie. Logging
151 does NOT presently lock the log file while it's in use. That has yet
152 to be done.
153
154 Revision 1.24 1999/08/13 04:16:42 sjboddie
155 added some collection-level metadata stuff
156
157 Revision 1.23 1999/08/11 23:28:59 sjboddie
158 added support for html classifier (i.e. the hp argumant now must be
159 translated too).
160
161 Revision 1.22 1999/08/10 22:45:21 sjboddie
162 format option ShowTopPages is now called DocumentTopPages
163
164 Revision 1.21 1999/08/09 04:25:17 sjboddie
165 moved OID translation stuff from documentaction::define_external_macros
166 to receptionist
167
168 Revision 1.20 1999/07/30 02:13:09 sjboddie
169 -added collectinfo argument to some functions
170 -made some function prototypes virtual
171
172 Revision 1.19 1999/07/15 06:02:05 rjmcnab
173 Moved the setting of argsinfo into the constructor. Added the configuration
174 command argdefault (as used by the actions). Added code to output the
175 correct charset based on the page encoding so that the user does not need
176 to specify the encoding used for a particular page.
177
178 Revision 1.18 1999/07/11 01:05:20 rjmcnab
179 Stored origin of cgiarg with argument.
180
181 Revision 1.17 1999/07/10 22:18:26 rjmcnab
182 Added calls to define_external_cgiargs.
183
184 Revision 1.16 1999/06/27 21:49:03 sjboddie
185 fixed a couple of version conflicts - tidied up some small things
186
187 Revision 1.15 1999/06/26 01:14:32 rjmcnab
188 Made a couple of changes to handle different encodings.
189
190 Revision 1.14 1999/06/09 00:08:36 sjboddie
191 query string macro (_cgiargq_) is now made html safe before being set
192
193 Revision 1.13 1999/06/08 04:29:31 sjboddie
194 added argsinfo to the call to check_cgiargs to make it easy to set
195 args to their default if they're found to be screwed up
196
197 Revision 1.12 1999/04/30 01:59:42 sjboddie
198 lots of stuff - getting documentaction working (documentaction replaces
199 old browseaction)
200
201 Revision 1.11 1999/03/25 03:06:43 sjboddie
202
203 altered receptionist slightly so it now passes *collectproto to
204 define_internal_macros and define_external_macros - need it
205 for browseaction
206
207 Revision 1.10 1999/03/05 03:53:54 sjboddie
208
209 fixed some bugs
210
211 Revision 1.9 1999/02/28 20:00:16 rjmcnab
212
213
214 Fixed a few things.
215
216 Revision 1.8 1999/02/25 21:58:59 rjmcnab
217
218 Merged sources.
219
220 Revision 1.7 1999/02/21 22:33:55 rjmcnab
221
222 Lots of stuff :-)
223
224 Revision 1.6 1999/02/11 01:24:05 rjmcnab
225
226 Fixed a few compiler warnings.
227
228 Revision 1.5 1999/02/08 01:28:02 rjmcnab
229
230 Got the receptionist producing something using the statusaction.
231
232 Revision 1.4 1999/02/05 10:42:46 rjmcnab
233
234 Continued working on receptionist
235
236 Revision 1.3 1999/02/04 10:00:56 rjmcnab
237
238 Developed the idea of an "action" and having them define the cgi arguments
239 which they need and how those cgi arguments function.
240
241 Revision 1.2 1999/02/04 01:17:27 rjmcnab
242
243 Got it outputing something.
244
245
246 */
247
248
249#include "receptionist.h"
250#include "fileutil.h"
251#include "cgiutils.h"
252#include "htmlutils.h"
253#include "gsdltools.h"
254#include "OIDtools.h"
255#include <assert.h>
256#include <time.h>
257#include <stdio.h>
258#if defined (GSDL_USE_IOS_H)
259#include <fstream.h>
260#else
261#include <fstream>
262#endif
263
264#if defined (__WIN32_)
265#include "wincgiutils.h"
266#endif
267
268void recptconf::clear () {
269 gsdlhome.clear();
270 gdbmhome.clear();
271 collectinfo.erase(collectinfo.begin(), collectinfo.end());
272 collection.clear();
273 collectdir.clear();
274 httpprefix.clear();
275 httpimg = "/images";
276 gwcgi.clear();
277 macrofiles.erase(macrofiles.begin(), macrofiles.end());
278 saveconf.clear();
279 usecookies = false;
280 logcgiargs = false;
281
282 // these default page parameters can always be overriden
283 // in the configuration file
284 pageparams.erase(pageparams.begin(), pageparams.end());
285 pageparams["c"] = "";
286 pageparams["l"] = "en";
287
288#ifdef MACROPRECEDENCE
289 macroprecedence = MACROPRECEDENCE;
290#else
291 macroprecedence.clear();
292#endif
293}
294
295void collectioninfo_t::clear () {
296 gsdl_gsdlhome.clear();
297 gsdl_gdbmhome.clear();
298
299 info_loaded = false;
300 info.clear();
301}
302
303receptionist::receptionist () {
304 // create a list of cgi arguments
305 // this must be done before the configuration
306
307 cgiarginfo ainfo;
308
309 ainfo.shortname = "e";
310 ainfo.longname = "compressed arguments";
311 ainfo.multiplechar = true;
312 ainfo.defaultstatus = cgiarginfo::good;
313 ainfo.argdefault = "";
314 ainfo.savedarginfo = cgiarginfo::mustnot;
315 argsinfo.addarginfo (NULL, ainfo);
316
317 ainfo.shortname = "a";
318 ainfo.longname = "action";
319 ainfo.multiplechar = true;
320 ainfo.defaultstatus = cgiarginfo::none;
321 ainfo.argdefault = "";
322 ainfo.savedarginfo = cgiarginfo::must;
323 argsinfo.addarginfo (NULL, ainfo);
324
325 // w=western
326 ainfo.shortname = "w";
327 ainfo.longname = "encoding";
328 ainfo.multiplechar = true;
329 ainfo.defaultstatus = cgiarginfo::weak;
330 ainfo.argdefault = "w";
331 ainfo.savedarginfo = cgiarginfo::must;
332 argsinfo.addarginfo (NULL, ainfo);
333
334 ainfo.shortname = "nw";
335 ainfo.longname = "new encoding";
336 ainfo.multiplechar = true;
337 ainfo.defaultstatus = cgiarginfo::none;
338 ainfo.argdefault = "";
339 ainfo.savedarginfo = cgiarginfo::mustnot;
340 argsinfo.addarginfo (NULL, ainfo);
341
342 ainfo.shortname = "c";
343 ainfo.longname = "collection";
344 ainfo.multiplechar = true;
345 ainfo.defaultstatus = cgiarginfo::none;
346 ainfo.argdefault = "";
347 ainfo.savedarginfo = cgiarginfo::must;
348 argsinfo.addarginfo (NULL, ainfo);
349
350 // the interface language name should use the ISO 639
351 // standard
352 ainfo.shortname = "l";
353 ainfo.longname = "interface language";
354 ainfo.multiplechar = true;
355 ainfo.defaultstatus = cgiarginfo::weak;
356 ainfo.argdefault = "en";
357 ainfo.savedarginfo = cgiarginfo::must;
358 argsinfo.addarginfo (NULL, ainfo);
359
360 // the GSDL_UID (cookie)
361 ainfo.shortname = "z";
362 ainfo.longname = "gsdl uid";
363 ainfo.multiplechar = true;
364 ainfo.defaultstatus = cgiarginfo::none;
365 ainfo.argdefault = "";
366 ainfo.savedarginfo = cgiarginfo::mustnot;
367 argsinfo.addarginfo (NULL, ainfo);
368}
369
370
371void receptionist::add_action (action *theaction) {
372 // make sure we have an action to add
373 if (theaction == NULL) return;
374
375 // add this action to the list of actions
376 actions.addaction(theaction);
377
378 // add the cgi arguments from this action
379 argsinfo.addarginfo (NULL, theaction->getargsinfo());
380}
381
382
383void receptionist::add_browser (browserclass *thebrowser) {
384 // make sure we have a browser to add
385 if (thebrowser == NULL) return;
386
387 // add this browser to the list of browsers
388 browsers.addbrowser(thebrowser);
389}
390
391
392void receptionist::setdefaultbrowser (const text_t &browsername) {
393 browsers.setdefaultbrowser (browsername);
394}
395
396
397// configure should be called for each line in the
398// configuration files to configure the receptionist and everything
399// it contains. The configuration should take place after everything
400// has been added but before the initialisation.
401void receptionist::configure (const text_t &key, const text_tarray &cfgline) {
402 // configure the receptionist
403 if (cfgline.size() >= 1) {
404 cgiarginfo *info = NULL;
405 if (key == "gsdlhome") configinfo.gsdlhome = cfgline[0];
406 else if (key == "collection") {
407 configinfo.collection = cfgline[0];
408 // also need to set the default arg to this collection
409 if ((info = argsinfo.getarginfo("c")) != NULL) {
410 info->defaultstatus = cgiarginfo::good;
411 info->argdefault = cfgline[0];
412 }
413
414 } else if (key == "collectdir") configinfo.collectdir = cfgline[0];
415 else if (key == "httpprefix") configinfo.httpprefix = cfgline[0];
416 else if (key == "httpimg") configinfo.httpimg = cfgline[0];
417 else if (key == "gwcgi") configinfo.gwcgi = cfgline[0];
418 else if (key == "macrofiles") {
419 // want to append to macrofiles (i.e. may be several config files
420 // contributing, maybe from several collections).
421 text_tarray::const_iterator here = cfgline.begin();
422 text_tarray::const_iterator end = cfgline.end();
423 while (here != end) {
424 configinfo.macrofiles.insert (*here);
425 here ++;
426 }
427 }
428 else if (key == "saveconf") configinfo.saveconf = cfgline[0];
429 else if (key == "usecookies") configinfo.usecookies = (cfgline[0] == "true");
430 else if (key == "logcgiargs") configinfo.logcgiargs = (cfgline[0] == "true");
431 else if (key == "pageparam") {
432 if (cfgline.size() >= 2) configinfo.pageparams[cfgline[0]] = cfgline[1];
433 else configinfo.pageparams[cfgline[0]] = "";
434 }
435 else if (key == "macroprecedence") configinfo.macroprecedence = cfgline[0];
436 else if (key == "collectinfo") {
437 if (cfgline.size() >= 3) {
438 collectioninfo_t cinfo;
439 cinfo.gsdl_gsdlhome = cfgline[1];
440 cinfo.gsdl_gdbmhome = cfgline[2];
441 configinfo.collectinfo[cfgline[0]] = cinfo;
442 }
443 }
444
445 else if (key == "cgiarg") {
446 // get shortname
447 bool seen_defaultstatus = false;
448 text_t subkey, subvalue;
449 text_t shortname;
450 text_t::const_iterator cfglinesub_here;
451 text_tarray::const_iterator cfgline_here = cfgline.begin();
452 text_tarray::const_iterator cfgline_end = cfgline.end();
453 while (cfgline_here != cfgline_end) {
454 cfglinesub_here = getdelimitstr((*cfgline_here).begin(),
455 (*cfgline_here).end(), '=', subkey);
456 if (subkey == "shortname") {
457 shortname = substr (cfglinesub_here, (*cfgline_here).end());
458 }
459 cfgline_here++;
460 }
461
462 // if we found the shortname process the line again filling in values
463 if (!shortname.empty()) {
464 cgiarginfo &chinfo = argsinfo[shortname];
465 chinfo.shortname = shortname; // in case this is a new argument
466
467 cfgline_here = cfgline.begin();
468 while (cfgline_here != cfgline_end) {
469 cfglinesub_here = getdelimitstr((*cfgline_here).begin(),
470 (*cfgline_here).end(), '=', subkey);
471 subvalue = substr (cfglinesub_here, (*cfgline_here).end());
472
473 if (subkey == "longname") chinfo.longname = subvalue;
474 else if (subkey == "multiplechar") chinfo.multiplechar = (subvalue == "true");
475 else if (subkey == "defaultstatus") {
476 seen_defaultstatus = true;
477 if (subvalue == "none") chinfo.defaultstatus = cgiarginfo::none;
478 else if (subvalue == "weak") chinfo.defaultstatus = cgiarginfo::weak;
479 else if (subvalue == "good") chinfo.defaultstatus = cgiarginfo::good;
480 else if (subvalue == "config") chinfo.defaultstatus = cgiarginfo::config;
481 else if (subvalue == "imperative") chinfo.defaultstatus = cgiarginfo::imperative;
482 }
483 else if (subkey == "argdefault") {
484 chinfo.argdefault = subvalue;
485 if (!seen_defaultstatus) chinfo.defaultstatus = cgiarginfo::config;
486 }
487 else if (subkey == "savedarginfo") {
488 if (subvalue == "mustnot") chinfo.savedarginfo = cgiarginfo::mustnot;
489 else if (subvalue == "can") chinfo.savedarginfo = cgiarginfo::can;
490 else if (subvalue == "must") chinfo.savedarginfo = cgiarginfo::must;
491 }
492
493 cfgline_here++;
494 }
495 }
496 }
497 }
498
499 // configure the actions
500 actionptrmap::iterator actionhere = actions.begin ();
501 actionptrmap::iterator actionend = actions.end ();
502
503 while (actionhere != actionend) {
504 assert ((*actionhere).second.a != NULL);
505 if ((*actionhere).second.a != NULL)
506 (*actionhere).second.a->configure(key, cfgline);
507
508 actionhere++;
509 }
510
511 // configure the protocols
512 recptprotolistclass::iterator protohere = protocols.begin ();
513 recptprotolistclass::iterator protoend = protocols.end ();
514
515 while (protohere != protoend) {
516 assert ((*protohere).p != NULL);
517 if ((*protohere).p != NULL)
518 (*protohere).p->configure(key, cfgline);
519
520 protohere++;
521 }
522
523 // configure the browsers
524 browserptrmap::iterator browserhere = browsers.begin ();
525 browserptrmap::iterator browserend = browsers.end ();
526
527 while (browserhere != browserend) {
528 assert ((*browserhere).second.b != NULL);
529 if ((*browserhere).second.b != NULL)
530 (*browserhere).second.b->configure(key, cfgline);
531
532 browserhere++;
533 }
534}
535
536
537void receptionist::configure (const text_t &key, const text_t &value) {
538 text_tarray cfgline;
539 cfgline.push_back (value);
540 configure(key, cfgline);
541}
542
543
544// init should be called after all the actions, protocols, and
545// converters have been added to the receptionist and after everything
546// has been configured but before any pages are created.
547// It returns true on success and false on failure. If false is
548// returned getpage should not be called (without producing
549// meaningless output), instead an error page should be
550// produced by the calling code.
551bool receptionist::init (ostream &logout) {
552 // first configure collectdir
553 text_t thecollectdir = configinfo.gsdlhome;
554 if (!configinfo.collection.empty()) {
555 // collection specific mode
556 if (!configinfo.collectdir.empty()) {
557 // has already been configured
558 thecollectdir = configinfo.collectdir;
559 } else {
560 // decide where collectdir is by searching for collect.cfg
561 // look in $GSDLHOME/collect/collection-name/etc/collect.cfg and
562 // then $GSDLHOME/etc/collect.cfg
563 thecollectdir = filename_cat (configinfo.gsdlhome, "collect");
564 thecollectdir = filename_cat (thecollectdir, configinfo.collection);
565 text_t filename = filename_cat (thecollectdir, "etc");
566 filename = filename_cat (filename, "collect.cfg");
567
568 if (!file_exists(filename)) thecollectdir = configinfo.gsdlhome;
569 }
570 }
571 configure("collectdir", thecollectdir);
572
573 // read in the macro files
574 if (!read_macrofiles (logout)) return false;
575
576 // there must be at least one action defined
577 if (actions.empty()) {
578 logout << "Error: no actions have been added to the receptionist\n";
579 return false;
580 }
581
582 // there must be at least one browser defined
583 if (browsers.empty()) {
584 logout << "Error: no browsers have been added to the receptionist\n";
585 return false;
586 }
587
588 // create a saveconf string if there isn't one already
589 if (configinfo.saveconf.empty())
590 configinfo.saveconf = create_save_conf_str (argsinfo, logout);
591
592 // check the saveconf string
593 if (!check_save_conf_str (configinfo.saveconf, argsinfo, logout))
594 return false;
595
596 // set a random seed
597 srand (time(NULL));
598
599 // make the output converters remove all the zero-width spaces
600 convertinfoclass::iterator converthere = converters.begin ();
601 convertinfoclass::iterator convertend = converters.end ();
602 text_t defaultconvertname;
603 while (converthere != convertend) {
604 assert ((*converthere).second.outconverter != NULL);
605 if ((*converthere).second.outconverter != NULL) {
606 (*converthere).second.outconverter->set_rzws(1);
607 if (defaultconvertname.empty())
608 defaultconvertname = (*converthere).second.name;
609 }
610 converthere++;
611 }
612
613 // set default converter if no good one has been defined
614 if (!defaultconvertname.empty()) {
615 cgiarginfo *ainfo = argsinfo.getarginfo ("w");
616 if (ainfo->argdefault != "w") {
617 if ((ainfo != NULL) && (converters.get_outconverter(ainfo->argdefault) == NULL)) {
618 ainfo->defaultstatus = cgiarginfo::good;
619 ainfo->argdefault = defaultconvertname;
620 }
621 }
622 }
623
624 // init the actions
625 actionptrmap::iterator actionhere = actions.begin ();
626 actionptrmap::iterator actionend = actions.end ();
627 while (actionhere != actionend) {
628 if (((*actionhere).second.a == NULL) ||
629 !(*actionhere).second.a->init(logout)) return false;
630 actionhere++;
631 }
632
633 // init the protocols
634 recptprotolistclass::iterator protohere = protocols.begin ();
635 recptprotolistclass::iterator protoend = protocols.end ();
636 while (protohere != protoend) {
637 if (((*protohere).p == NULL) ||
638 !(*protohere).p->init(logout)) return false;
639 protohere++;
640 }
641
642 // init the browsers
643 browserptrmap::iterator browserhere = browsers.begin ();
644 browserptrmap::iterator browserend = browsers.end ();
645 while (browserhere != browserend) {
646 if (((*browserhere).second.b == NULL) ||
647 !(*browserhere).second.b->init(logout)) return false;
648 browserhere++;
649 }
650
651 return true;
652}
653
654
655// parse_cgi_args parses cgi arguments into an argument class.
656// This function should be called for each page request. It returns false
657// if there was a major problem with the cgi arguments.
658bool receptionist::parse_cgi_args (const text_t &argstr, cgiargsclass &args,
659 ostream &logout, text_tmap &fcgienv) {
660 outconvertclass text_t2ascii;
661
662 // get an initial list of cgi arguments
663 args.clear();
664 split_cgi_args (argsinfo, argstr, args);
665
666 // expand the compressed argument (if there was one)
667 if (!expand_save_args (argsinfo, configinfo.saveconf, args, logout)) return false;
668
669 // add the defaults
670 add_default_args (argsinfo, args, logout);
671
672 // get the cookie
673 if (configinfo.usecookies) get_cookie(args["z"], fcgienv);
674
675 // get the input encoding
676 text_t &arg_w = args["w"];
677 inconvertclass defaultinconvert;
678 inconvertclass *inconvert = converters.get_inconverter (arg_w);
679 if (inconvert == NULL) inconvert = &defaultinconvert;
680
681 // see if the next page will have a different encoding
682 if (args.getarg("nw") != NULL) arg_w = args["nw"];
683
684 // convert arguments which aren't in unicode to unicode
685 args_tounicode (args, *inconvert);
686
687
688 // decide on the output conversion class (needed for checking the external
689 // cgi arguments)
690 rzwsoutconvertclass defaultoutconverter;
691 rzwsoutconvertclass *outconverter = converters.get_outconverter (arg_w);
692 if (outconverter == NULL) outconverter = &defaultoutconverter;
693 outconverter->reset();
694
695 // check the main cgi arguments
696 if (!check_mainargs (args, logout)) return false;
697
698 // check the arguments for the action
699 action *a = actions.getaction (args["a"]);
700 if (a != NULL) {
701 if (!a->check_cgiargs (argsinfo, args, logout)) return false;
702 } else {
703 // the action was not found!!
704 logout << text_t2ascii << "Error: the action \"" << args["a"]
705 << "\" could not be found.\n";
706 return false;
707 }
708
709 // check external cgi arguments for each action
710 actionptrmap::iterator actionhere = actions.begin ();
711 actionptrmap::iterator actionend = actions.end ();
712 while (actionhere != actionend) {
713 assert ((*actionhere).second.a != NULL);
714 if ((*actionhere).second.a != NULL) {
715 if (!(*actionhere).second.a->check_external_cgiargs (argsinfo, args, *outconverter,
716 configinfo.saveconf, logout))
717 return false;
718 }
719 actionhere++;
720 }
721
722 // the action might have changed but we will assume that
723 // the cgiargs were checked properly when the change was made
724
725 return true;
726}
727
728// returns true if cookie already existed, false
729// if it was generated
730bool receptionist::get_cookie (text_t &cookie, text_tmap &fcgienv) {
731
732 text_t cookiestring = gsdl_getenv ("HTTP_COOKIE", fcgienv);
733
734 text_t::const_iterator end = cookiestring.end();
735 text_t::const_iterator here = findchar (cookiestring.begin(), end, 'G');
736
737 while (here+9 < end) {
738
739 if (substr(here, here+8) == "GSDL_UID") {
740 cookie = substr (here+9, findchar (here+9, end, ';'));
741 return true;
742 }
743 here = findchar (cookiestring.begin(), end, 'G');
744 }
745
746 cookie.clear();
747 text_t host = gsdl_getenv("REMOTE_ADDR", fcgienv);
748 time_t ttime = time(NULL);
749 if (!host.empty()) {
750 cookie += host;
751 cookie.push_back ('-');
752 }
753 cookie += text_t(ttime);
754
755 return false;
756}
757
758// as above but just tests if cookie exists
759bool receptionist::get_cookie (text_tmap &fcgienv) {
760
761 text_t c = gsdl_getenv("HTTP_COOKIE", fcgienv);
762 if (!c.empty()) {
763 text_t cookiestring = c;
764
765 text_t::const_iterator end = cookiestring.end();
766 text_t::const_iterator here = findchar (cookiestring.begin(), end, 'G');
767
768 while (here+9 < end) {
769 if (substr(here, here+8) == "GSDL_UID") return true;
770 here = findchar (cookiestring.begin(), end, 'G');
771 }
772 }
773 return false;
774}
775
776bool receptionist::log_cgi_args (cgiargsclass &args, ostream &logout, text_tmap &fcgienv) {
777
778 // see if we want to log the cgi arguments
779 if (!configinfo.logcgiargs) return true;
780
781 text_t host = gsdl_getenv ("REMOTE_HOST", fcgienv);
782 text_t script_name = gsdl_getenv ("SCRIPT_NAME", fcgienv);
783 if (host.empty()) host = gsdl_getenv ("REMOTE_ADDR", fcgienv);
784 text_t browser = gsdl_getenv ("HTTP_USER_AGENT", fcgienv);
785 time_t ttime = time(NULL);
786
787 cgiargsclass::const_iterator args_here = args.begin();
788 cgiargsclass::const_iterator args_end = args.end();
789
790 text_t argstr;
791 bool first = true;
792 while (args_here != args_end) {
793 if (!first) argstr += ", ";
794 argstr += (*args_here).first + "=" + (*args_here).second.value;
795 first = false;
796 args_here ++;
797 }
798
799 text_t logfile = filename_cat (configinfo.gsdlhome, "etc");
800 logfile = filename_cat (logfile, "usage.txt");
801
802 text_t logstr = script_name;
803 logstr += " " + host;
804 logstr += " [";
805 logstr += ttime;
806 logstr += "] (" + argstr + ") \"";
807 logstr += browser;
808 logstr += "\"\n";
809
810 return append_logstr (logfile, logstr, logout);
811}
812
813bool receptionist::append_logstr (const text_t &filename, const text_t &logstr,
814 ostream &logout) {
815
816 utf8outconvertclass text_t2utf8;
817 char *lfile = filename.getcstr();
818
819 ofstream log (lfile, ios::app);
820
821 if (!log) {
822 logout << "Error: Couldn't open file " << lfile << "\n";
823 delete lfile;
824 return false;
825 }
826
827 int fd = GSDL_GET_FILEDESC(log);
828
829 // lock_val is set to 0 if file is locked successfully
830 int lock_val = 1;
831 GSDL_LOCK_FILE (fd);
832 if (lock_val == 0) {
833 log << text_t2utf8 << logstr;
834 GSDL_UNLOCK_FILE (fd);
835 } else {
836 logout << "Error: Couldn't lock file " << lfile << "\n";
837 log.close();
838 delete lfile;
839 return false;
840 }
841
842 log.close();
843
844 delete lfile;
845 return true;
846}
847
848text_t receptionist::expandmacros (const text_t &astring, cgiargsclass &args,
849 ostream &logout) {
850 text_t outstring;
851 outconvertclass text_t2ascii;
852
853 action *a = actions.getaction (args["a"]);
854 prepare_page (a, args, text_t2ascii, logout);
855 disp.expandstring ("Global", astring, outstring);
856 return outstring;
857}
858
859// produce_cgi_page will call get_cgihead_info and
860// produce_content in the appropriate way to output a cgi header and
861// the page content (if needed). If a page could not be created it
862// will return false
863bool receptionist::produce_cgi_page (cgiargsclass &args, ostream &contentout,
864 ostream &logout, text_tmap &fcgienv) {
865 outconvertclass text_t2ascii;
866
867 response_t response;
868 text_t response_data;
869
870 // produce cgi header
871 get_cgihead_info (args, response, response_data, logout, fcgienv);
872 if (response == location) {
873 // location response (url may contain macros!!)
874 response_data = expandmacros (response_data, args, logout);
875 contentout << text_t2ascii << "Location: " << response_data << "\n\n";
876 contentout << flush;
877 return true;
878 } else if (response == content) {
879 // content response
880 contentout << text_t2ascii << "Content-type: " << response_data << "\n\n";
881 } else {
882 // unknown response
883 logout << "Error: get_cgihead_info returned an unknown response type.\n";
884 return false;
885 }
886
887 // produce cgi page
888 if (!produce_content (args, contentout, logout)) return false;
889
890 // flush contentout
891 contentout << flush;
892 return true;
893}
894
895
896// get_cgihead_info determines the cgi header information for
897// a set of cgi arguments. If response contains location then
898// response_data contains the redirect address. If reponse
899// contains content then reponse_data contains the content-type.
900// Note that images can now be produced by the receptionist.
901void receptionist::get_cgihead_info (cgiargsclass &args, response_t &response,
902 text_t &response_data, ostream &logout,
903 text_tmap &fcgienv) {
904 outconvertclass text_t2ascii;
905
906 // get the action
907 action *a = actions.getaction (args["a"]);
908 if (a != NULL) {
909 a->get_cgihead_info (args, &protocols, response, response_data, logout);
910
911 } else {
912 // the action was not found!!
913 logout << text_t2ascii << "Error receptionist::get_cgihead_info: the action \""
914 << args["a"] << "\" could not be found.\n";
915 response = content;
916 response_data = "text/html";
917 }
918
919 // add the encoding information
920 if (response == content) {
921 if (args["w"] == "u") {
922 response_data += "; charset=UTF-8";
923 } else if (args["w"] == "g") {
924 response_data += "; charset=GBK";
925 } else if (args["w"] == "a") {
926 response_data += "; charset=windows-1256";
927 } else {
928 response_data += "; charset=ISO-8859-1";
929 }
930
931 // add cookie if required
932 if (configinfo.usecookies && !get_cookie(fcgienv))
933 response_data += "\nSet-Cookie: GSDL_UID=" + args["z"]
934 + "; expires=25-Dec-37 00:00:00 GMT";
935 }
936}
937
938
939// produce the page content
940bool receptionist::produce_content (cgiargsclass &args, ostream &contentout,
941 ostream &logout) {
942
943 // decide on the output conversion class
944 text_t &arg_w = args["w"];
945 rzwsoutconvertclass defaultoutconverter;
946 rzwsoutconvertclass *outconverter = converters.get_outconverter (arg_w);
947 if (outconverter == NULL) outconverter = &defaultoutconverter;
948 outconverter->reset();
949
950
951 recptproto *collectproto = protocols.getrecptproto (args["c"], logout);
952 if (collectproto != NULL) {
953 // get browsers to process OID
954 text_t OID = args["d"];
955 if (OID.empty()) OID = args["cl"];
956 if (!OID.empty()) {
957 text_tset metadata;
958 text_tarray OIDs;
959 OIDs.push_back (OID);
960 if (!is_top(OID)) OIDs.push_back (OID + ".pr");
961 FilterResponse_t response;
962 metadata.insert ("childtype");
963 if (get_info (OIDs, args["c"], metadata, false, collectproto, response, logout)) {
964 text_t classifytype;
965 if (!response.docInfo[0].metadata["childtype"].values[0].empty())
966 classifytype = response.docInfo[0].metadata["childtype"].values[0];
967 else if (!is_top (OID)) {
968 if (!response.docInfo[1].metadata["childtype"].values[0].empty())
969 classifytype = response.docInfo[1].metadata["childtype"].values[0];
970 }
971 browserclass *b = browsers.getbrowser (classifytype);
972 b->processOID (args, collectproto, logout);
973 }
974 }
975
976 // translate "d" and "cl" arguments if required
977 translate_OIDs (args, collectproto, logout);
978 }
979
980 // produce the page using the desired action
981 action *a = actions.getaction (args["a"]);
982 if (a != NULL) {
983 if (a->uses_display(args)) prepare_page (a, args, (*outconverter), logout);
984 if (!a->do_action (args, &protocols, &browsers, disp, (*outconverter), contentout, logout))
985 return false;
986
987 } else {
988 // the action was not found!!
989 outconvertclass text_t2ascii;
990
991 logout << text_t2ascii << "Error receptionist::produce_content: the action \""
992 << args["a"] << "\" could not be found.\n";
993
994 contentout << (*outconverter)
995 << "<html>\n"
996 << "<head>\n"
997 << "<title>Error</title>\n"
998 << "</head>\n"
999 << "<body>\n"
1000 << "<h2>Oops!</h2>\n"
1001 << "Undefined Page. The action \""
1002 << args["a"] << "\" could not be found.\n"
1003 << "</body>\n"
1004 << "</html>\n";
1005 }
1006 return true;
1007}
1008
1009
1010// returns the compressed argument ("e") corresponding to the argument
1011// list. This can be used to save preferences between sessions.
1012text_t receptionist::get_compressed_arg (cgiargsclass &args, ostream &logout) {
1013 // decide on the output conversion class
1014 text_t &arg_w = args["w"];
1015 rzwsoutconvertclass defaultoutconverter;
1016 rzwsoutconvertclass *outconverter = converters.get_outconverter (arg_w);
1017 if (outconverter == NULL) outconverter = &defaultoutconverter;
1018 outconverter->reset();
1019
1020 text_t compressed_args;
1021 if (compress_save_args (argsinfo, configinfo.saveconf, args,
1022 compressed_args, *outconverter, logout))
1023 return compressed_args;
1024
1025 return "";
1026}
1027
1028
1029// will read in all the macro files. If one is not found an
1030// error message will be written to logout and the method will
1031// return false.
1032bool receptionist::read_macrofiles (ostream &logout) {
1033 outconvertclass text_t2ascii;
1034
1035 // redirect the error output to logout
1036 ostream *savedlogout = disp.setlogout (&logout);
1037
1038 // load up the default macro files, the collection directory
1039 // is searched first for the file (if this is being used in
1040 // collection specific mode) and then the main directory(s)
1041 text_t colmacrodir = filename_cat (configinfo.collectdir, "macros");
1042
1043 text_tset maindirs;
1044 text_t gsdlmacrodir = filename_cat (configinfo.gsdlhome, "macros");
1045 maindirs.insert (gsdlmacrodir);
1046 colinfo_tmap::iterator colhere = configinfo.collectinfo.begin();
1047 colinfo_tmap::iterator colend = configinfo.collectinfo.end();
1048 while (colhere != colend) {
1049 if (!((*colhere).second.gsdl_gsdlhome).empty()) {
1050 gsdlmacrodir = filename_cat ((*colhere).second.gsdl_gsdlhome, "macros");
1051 maindirs.insert (gsdlmacrodir);
1052 }
1053 colhere ++;
1054 }
1055
1056 text_tset::iterator arrhere = configinfo.macrofiles.begin();
1057 text_tset::iterator arrend = configinfo.macrofiles.end();
1058 text_t filename;
1059 while (arrhere != arrend) {
1060 bool foundfile = false;
1061
1062 // try in the collection directory if this is being
1063 // run in collection specific mode
1064 if (!configinfo.collection.empty()) {
1065 filename = filename_cat (colmacrodir, *arrhere);
1066 if (file_exists (filename)) {
1067 disp.loaddefaultmacros(filename);
1068 foundfile = true;
1069 }
1070 }
1071
1072 // if we haven't found the macro file yet try in
1073 // the main macro directory(s)
1074 // if file is found in more than one main directory
1075 // we'll load all copies
1076 if (!foundfile) {
1077 text_tset::const_iterator dirhere = maindirs.begin();
1078 text_tset::const_iterator dirend = maindirs.end();
1079 while (dirhere != dirend) {
1080 filename = filename_cat (*dirhere, *arrhere);
1081 if (file_exists (filename)) {
1082 disp.loaddefaultmacros(filename);
1083 foundfile = true;
1084 }
1085 dirhere ++;
1086 }
1087 }
1088
1089 // see if we found the file or not
1090 if (!foundfile) {
1091 logout << text_t2ascii
1092 << "Error: the macro file \"" << *arrhere << "\" could not be found.\n";
1093 if (configinfo.collection.empty()) {
1094 text_t dirs;
1095 joinchar (maindirs, ", ", dirs);
1096 logout << text_t2ascii
1097 << "It should be in either of the following directories ("
1098 << dirs << ").\n\n";
1099
1100 } else {
1101 logout << text_t2ascii
1102 << "It should be in either " << colmacrodir << " or in "
1103 << gsdlmacrodir << ".\n\n";
1104 }
1105 // reset logout to what it was
1106 disp.setlogout (savedlogout);
1107 return false;
1108 }
1109 arrhere++;
1110 }
1111
1112 // success
1113
1114 // reset logout to what it was
1115 disp.setlogout (savedlogout);
1116 return true;
1117}
1118
1119
1120// check_mainargs will check all the main arguments. If a major
1121// error is found it will return false and no cgi page should
1122// be created using the arguments.
1123bool receptionist::check_mainargs (cgiargsclass &args, ostream &logout) {
1124 // if this receptionist is running in collection dependant mode
1125 // then it should always set the collection argument to the
1126 // collection
1127 if (!configinfo.collection.empty()) args["c"] = configinfo.collection;
1128
1129 // if current collection uses ccscols make sure
1130 // "ccs" argument is set and make "cc" default to
1131 // all collections in "ccs"
1132 if (!args["c"].empty()) {
1133
1134 text_t &arg_c = args["c"];
1135 recptproto *collectproto = protocols.getrecptproto (arg_c, logout);
1136 if (collectproto == NULL) {
1137 // oops, this collection isn't valid
1138 outconvertclass text_t2ascii;
1139 logout << text_t2ascii << "ERROR: Invalid collection: " << arg_c << "\n";
1140 args["c"].clear();
1141
1142 } else {
1143
1144 ColInfoResponse_t *cinfo = get_collectinfo_ptr (collectproto, arg_c, logout);
1145
1146 if (cinfo != NULL) {
1147 if (!cinfo->ccsCols.empty()) {
1148 args["ccs"] = 1;
1149 if (args["cc"].empty()) {
1150 text_tarray::const_iterator col_here = cinfo->ccsCols.begin();
1151 text_tarray::const_iterator col_end = cinfo->ccsCols.end();
1152 bool first = true;
1153 while (col_here != col_end) {
1154 // make sure it's a valid collection
1155 if (protocols.getrecptproto (*col_here, logout) != NULL) {
1156 if (!first) args["cc"].push_back (',');
1157 args["cc"] += *col_here;
1158 first = false;
1159 }
1160 col_here ++;
1161 }
1162 }
1163 }
1164 } else {
1165 logout << "ERROR (receptionist::check_mainargs): get_collectinfo_ptr returned NULL\n";
1166 }
1167 }
1168 }
1169
1170 // argument "v" can only be 0 or 1. Use the default value
1171 // if it is out of range
1172 int arg_v = args.getintarg ("v");
1173 if (arg_v != 0 && arg_v != 1) {
1174 cgiarginfo *vinfo = argsinfo.getarginfo ("v");
1175 if (vinfo != NULL) args["v"] = vinfo->argdefault;
1176 }
1177
1178 // argument "f" can only be 0 or 1. Use the default value
1179 // if it is out of range
1180 int arg_f = args.getintarg ("f");
1181 if (arg_f != 0 && arg_f != 1) {
1182 cgiarginfo *finfo = argsinfo.getarginfo ("f");
1183 if (finfo != NULL) args["f"] = finfo->argdefault;
1184 }
1185
1186 return true;
1187}
1188
1189// translate_OIDs translates the "d" and "cl" arguments to their correct values
1190// if they use the tricky ".fc", ".lc" type syntax.
1191void receptionist::translate_OIDs (cgiargsclass &args, recptproto *collectproto,
1192 ostream &logout) {
1193
1194 FilterResponse_t response;
1195 FilterRequest_t request;
1196 comerror_t err;
1197 text_t &arg_d = args["d"];
1198 text_t &arg_cl = args["cl"];
1199 text_t &collection = args["c"];
1200
1201 // do a call to translate OIDs if required
1202 request.filterName = "NullFilter";
1203 request.filterResultOptions = FROID;
1204 if (!arg_d.empty() && needs_translating (arg_d)) {
1205 request.docSet.push_back (arg_d);
1206 collectproto->filter (collection, request, response, err, logout);
1207 arg_d = response.docInfo[0].OID;
1208 request.clear();
1209 }
1210 // we'll also check here that the "cl" argument has a "classify" doctype
1211 // (in case ".fc" or ".lc" have screwed up)
1212 if (needs_translating (arg_cl)) {
1213 request.fields.insert ("doctype");
1214 request.docSet.push_back (arg_cl);
1215 request.filterResultOptions = FRmetadata;
1216 collectproto->filter (collection, request, response, err, logout);
1217 // set to original value (without .xx stuff) if doctype isn't "classify"
1218 if (response.docInfo[0].metadata["doctype"].values[0] != "classify")
1219 strip_suffix (arg_cl);
1220 else
1221 arg_cl = response.docInfo[0].OID;
1222 }
1223}
1224
1225// prepare_page sets up page parameters, sets display macros
1226// and opens the page ready for output
1227void receptionist::prepare_page (action *a, cgiargsclass &args,
1228 outconvertclass &outconvert,
1229 ostream &logout) {
1230 // set up page parameters
1231 text_t pageparams;
1232 bool first = true;
1233
1234 text_tmap::iterator params_here = configinfo.pageparams.begin();
1235 text_tmap::iterator params_end = configinfo.pageparams.end();
1236 while (params_here != params_end) {
1237 if (args[(*params_here).first] != (*params_here).second) {
1238 if (!first) pageparams += ",";
1239 first = false;
1240 pageparams += (*params_here).first;
1241 pageparams += "=";
1242 pageparams += args[(*params_here).first];
1243 }
1244
1245 params_here++;
1246 }
1247
1248
1249 // open the page
1250 disp.openpage(pageparams, configinfo.macroprecedence);
1251
1252
1253 // define external macros for each action
1254 actionptrmap::iterator actionhere = actions.begin ();
1255 actionptrmap::iterator actionend = actions.end ();
1256
1257 while (actionhere != actionend) {
1258 assert ((*actionhere).second.a != NULL);
1259 if ((*actionhere).second.a != NULL)
1260 (*actionhere).second.a->define_external_macros (disp, args, &protocols, logout);
1261 actionhere++;
1262 }
1263
1264 // define internal macros for the current action
1265 a->define_internal_macros (disp, args, &protocols, logout);
1266
1267 // define general macros. the defining of general macros is done here so that
1268 // the last possible version of the cgi arguments are used
1269 define_general_macros (args, outconvert, logout);
1270}
1271
1272void receptionist::define_general_macros (cgiargsclass &args, outconvertclass &/*outconvert*/,
1273 ostream &logout) {
1274
1275 text_t &collection = args["c"];
1276
1277 disp.setmacro ("gsdlhome", "Global", dm_safe(configinfo.gsdlhome));
1278 disp.setmacro ("gwcgi", "Global", configinfo.gwcgi);
1279 disp.setmacro ("httpimg", "Global", configinfo.httpimg);
1280 disp.setmacro ("httpprefix", "Global", configinfo.httpprefix);
1281 text_t compressedoptions = get_compressed_arg(args, logout);
1282 disp.setmacro ("compressedoptions", "Global", dm_safe(compressedoptions));
1283 // need a decoded version of compressedoptions for use within forms
1284 // as browsers encode values from forms before sending to server
1285 // (e.g. %25 becomes %2525)
1286 decode_cgi_arg (compressedoptions);
1287 disp.setmacro ("decodedcompressedoptions", "Global", dm_safe(compressedoptions));
1288
1289 // set macron macros if encoding is utf8
1290 if (args["w"] == "u") {
1291 disp.setmacro ("Amn", "Global", "&#256;");
1292 disp.setmacro ("amn", "Global", "&#257;");
1293 disp.setmacro ("Emn", "Global", "&#274;");
1294 disp.setmacro ("emn", "Global", "&#275;");
1295 disp.setmacro ("Imn", "Global", "&#298;");
1296 disp.setmacro ("imn", "Global", "&#299;");
1297 disp.setmacro ("Omn", "Global", "&#332;");
1298 disp.setmacro ("omn", "Global", "&#333;");
1299 disp.setmacro ("Umn", "Global", "&#362;");
1300 disp.setmacro ("umn", "Global", "&#363;");
1301 }
1302
1303 // set _cgiargX_ macros for each cgi argument
1304 cgiargsclass::const_iterator argshere = args.begin();
1305 cgiargsclass::const_iterator argsend = args.end();
1306 while (argshere != argsend) {
1307 if (((*argshere).first == "q") ||
1308 ((*argshere).first == "qa") ||
1309 ((*argshere).first == "qtt") ||
1310 ((*argshere).first == "qty") ||
1311 ((*argshere).first == "qp") ||
1312 ((*argshere).first == "qpl") ||
1313 ((*argshere).first == "qr") ||
1314 ((*argshere).first == "q2"))
1315 // need to escape special characters from query string
1316 disp.setmacro ("cgiarg" + (*argshere).first,
1317 "Global", html_safe((*argshere).second.value));
1318 else
1319 disp.setmacro ("cgiarg" + (*argshere).first, "Global", dm_safe((*argshere).second.value));
1320 argshere ++;
1321 }
1322
1323 // display text right to left if language is arabic (and if browser can support it)
1324 if (args["l"] == "ar")
1325 disp.setmacro ("htmlextra", "Global", " dir=rtl");
1326
1327 // set collection specific macros
1328 if (!collection.empty()) {
1329 recptproto *collectproto = protocols.getrecptproto (collection, logout);
1330 if (collectproto != NULL) {
1331 FilterResponse_t response;
1332 text_tset metadata;
1333 get_info ("collection", collection, metadata, false,
1334 collectproto, response, logout);
1335
1336 if (!response.docInfo[0].metadata.empty()) {
1337 MetadataInfo_tmap::const_iterator here = response.docInfo[0].metadata.begin();
1338 MetadataInfo_tmap::const_iterator end = response.docInfo[0].metadata.end();
1339 while (here != end) {
1340 if (((*here).first != "haschildren") && ((*here).first != "hasnext") &&
1341 ((*here).first != "hasprevious")) {
1342 disp.setmacro ((*here).first, "Global", (*here).second.values[0]);
1343 }
1344 here ++;
1345 }
1346 }
1347 }
1348 }
1349}
1350
1351// gets collection info from cache if found or
1352// calls collection server (and updates cache)
1353// returns NULL if there's an error
1354ColInfoResponse_t *receptionist::get_collectinfo_ptr (recptproto *collectproto,
1355 const text_t &collection,
1356 ostream &logout) {
1357
1358 // check the cache
1359 colinfo_tmap::iterator it = configinfo.collectinfo.find (collection);
1360 if ((it != configinfo.collectinfo.end()) && ((*it).second.info_loaded)) {
1361 // found it
1362 return &((*it).second.info);
1363 }
1364
1365 // not cached, get info from collection server
1366 if (collectproto == NULL) {
1367 logout << "ERROR: receptionist::get_collectinfo_ptr passed null collectproto\n";
1368 return NULL;
1369 }
1370
1371 comerror_t err;
1372 if (it == configinfo.collectinfo.end()) {
1373 collectioninfo_t cinfo;
1374 collectproto->get_collectinfo (collection, cinfo.info, err, logout);
1375 if (err != noError) {
1376 outconvertclass text_t2ascii;
1377 logout << text_t2ascii << "ERROR (receptionist::getcollectinfo_ptr): \""
1378 << get_comerror_string (err) << "\"while getting collectinfo\n";
1379 return NULL;
1380 }
1381 cinfo.info_loaded = true;
1382 configinfo.collectinfo[collection] = cinfo;
1383 return &(configinfo.collectinfo[collection].info);
1384 } else {
1385 collectproto->get_collectinfo (collection, (*it).second.info, err, logout);
1386 if (err != noError) {
1387 outconvertclass text_t2ascii;
1388 logout << text_t2ascii << "ERROR (receptionist::getcollectinfo_ptr): \""
1389 << get_comerror_string (err) << "\"while getting collectinfo\n";
1390 return NULL;
1391 }
1392 (*it).second.info_loaded = true;
1393 return &((*it).second.info);
1394 }
1395}
Note: See TracBrowser for help on using the repository browser.