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

Last change on this file since 2218 was 2218, checked in by sjboddie, 23 years ago

Fixed a couple of little bugs in the collector - bugs only showed up
when using a persistent version of the library (i.e. the local library
or fastcgi)

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