source: trunk/gsdl/src/recpt/receptionist.cpp@ 1282

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

Receptionist now caches collection information to avoid making multiple
get_collectinfo calls to collection server

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