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

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

fixed a couple of minor bugs that were introduced with the corba stuff

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