1 | /**********************************************************************
|
---|
2 | *
|
---|
3 | * receptionist.cpp -- a web interface for the gsdl
|
---|
4 | * Copyright (C) 1999 The New Zealand Digital Library Project
|
---|
5 | *
|
---|
6 | * PUT COPYRIGHT NOTICE HERE
|
---|
7 | *
|
---|
8 | * $Id: receptionist.cpp 418 1999-07-30 02:13:10Z sjboddie $
|
---|
9 | *
|
---|
10 | *********************************************************************/
|
---|
11 |
|
---|
12 | /*
|
---|
13 | $Log$
|
---|
14 | Revision 1.20 1999/07/30 02:13:09 sjboddie
|
---|
15 | -added collectinfo argument to some functions
|
---|
16 | -made some function prototypes virtual
|
---|
17 |
|
---|
18 | Revision 1.19 1999/07/15 06:02:05 rjmcnab
|
---|
19 | Moved the setting of argsinfo into the constructor. Added the configuration
|
---|
20 | command argdefault (as used by the actions). Added code to output the
|
---|
21 | correct charset based on the page encoding so that the user does not need
|
---|
22 | to specify the encoding used for a particular page.
|
---|
23 |
|
---|
24 | Revision 1.18 1999/07/11 01:05:20 rjmcnab
|
---|
25 | Stored origin of cgiarg with argument.
|
---|
26 |
|
---|
27 | Revision 1.17 1999/07/10 22:18:26 rjmcnab
|
---|
28 | Added calls to define_external_cgiargs.
|
---|
29 |
|
---|
30 | Revision 1.16 1999/06/27 21:49:03 sjboddie
|
---|
31 | fixed a couple of version conflicts - tidied up some small things
|
---|
32 |
|
---|
33 | Revision 1.15 1999/06/26 01:14:32 rjmcnab
|
---|
34 | Made a couple of changes to handle different encodings.
|
---|
35 |
|
---|
36 | Revision 1.14 1999/06/09 00:08:36 sjboddie
|
---|
37 | query string macro (_cgiargq_) is now made html safe before being set
|
---|
38 |
|
---|
39 | Revision 1.13 1999/06/08 04:29:31 sjboddie
|
---|
40 | added argsinfo to the call to check_cgiargs to make it easy to set
|
---|
41 | args to their default if they're found to be screwed up
|
---|
42 |
|
---|
43 | Revision 1.12 1999/04/30 01:59:42 sjboddie
|
---|
44 | lots of stuff - getting documentaction working (documentaction replaces
|
---|
45 | old browseaction)
|
---|
46 |
|
---|
47 | Revision 1.11 1999/03/25 03:06:43 sjboddie
|
---|
48 |
|
---|
49 | altered receptionist slightly so it now passes *collectproto to
|
---|
50 | define_internal_macros and define_external_macros - need it
|
---|
51 | for browseaction
|
---|
52 |
|
---|
53 | Revision 1.10 1999/03/05 03:53:54 sjboddie
|
---|
54 |
|
---|
55 | fixed some bugs
|
---|
56 |
|
---|
57 | Revision 1.9 1999/02/28 20:00:16 rjmcnab
|
---|
58 |
|
---|
59 |
|
---|
60 | Fixed a few things.
|
---|
61 |
|
---|
62 | Revision 1.8 1999/02/25 21:58:59 rjmcnab
|
---|
63 |
|
---|
64 | Merged sources.
|
---|
65 |
|
---|
66 | Revision 1.7 1999/02/21 22:33:55 rjmcnab
|
---|
67 |
|
---|
68 | Lots of stuff :-)
|
---|
69 |
|
---|
70 | Revision 1.6 1999/02/11 01:24:05 rjmcnab
|
---|
71 |
|
---|
72 | Fixed a few compiler warnings.
|
---|
73 |
|
---|
74 | Revision 1.5 1999/02/08 01:28:02 rjmcnab
|
---|
75 |
|
---|
76 | Got the receptionist producing something using the statusaction.
|
---|
77 |
|
---|
78 | Revision 1.4 1999/02/05 10:42:46 rjmcnab
|
---|
79 |
|
---|
80 | Continued working on receptionist
|
---|
81 |
|
---|
82 | Revision 1.3 1999/02/04 10:00:56 rjmcnab
|
---|
83 |
|
---|
84 | Developed the idea of an "action" and having them define the cgi arguments
|
---|
85 | which they need and how those cgi arguments function.
|
---|
86 |
|
---|
87 | Revision 1.2 1999/02/04 01:17:27 rjmcnab
|
---|
88 |
|
---|
89 | Got it outputing something.
|
---|
90 |
|
---|
91 |
|
---|
92 | */
|
---|
93 |
|
---|
94 |
|
---|
95 | #include "receptionist.h"
|
---|
96 | #include "fileutil.h"
|
---|
97 | #include "cgiutils.h"
|
---|
98 | #include "htmlutils.h"
|
---|
99 | #include "OIDtools.h"
|
---|
100 | #include <assert.h>
|
---|
101 | #include <time.h>
|
---|
102 |
|
---|
103 |
|
---|
104 |
|
---|
105 | receptionist::receptionist () {
|
---|
106 | // create a list of cgi arguments
|
---|
107 | // this must be done before the configuration
|
---|
108 |
|
---|
109 | cgiarginfo ainfo;
|
---|
110 |
|
---|
111 | ainfo.shortname = "e";
|
---|
112 | ainfo.longname = "compressed arguments";
|
---|
113 | ainfo.multiplechar = true;
|
---|
114 | ainfo.defaultstatus = cgiarginfo::good;
|
---|
115 | ainfo.argdefault = "";
|
---|
116 | ainfo.savedarginfo = cgiarginfo::mustnot;
|
---|
117 | argsinfo.addarginfo (NULL, ainfo);
|
---|
118 |
|
---|
119 | ainfo.shortname = "a";
|
---|
120 | ainfo.longname = "action";
|
---|
121 | ainfo.multiplechar = true;
|
---|
122 | ainfo.defaultstatus = cgiarginfo::none;
|
---|
123 | ainfo.argdefault = "";
|
---|
124 | ainfo.savedarginfo = cgiarginfo::must;
|
---|
125 | argsinfo.addarginfo (NULL, ainfo);
|
---|
126 |
|
---|
127 | // w=western
|
---|
128 | ainfo.shortname = "w";
|
---|
129 | ainfo.longname = "encoding";
|
---|
130 | ainfo.multiplechar = true;
|
---|
131 | ainfo.defaultstatus = cgiarginfo::weak;
|
---|
132 | ainfo.argdefault = "w";
|
---|
133 | ainfo.savedarginfo = cgiarginfo::must;
|
---|
134 | argsinfo.addarginfo (NULL, ainfo);
|
---|
135 |
|
---|
136 | ainfo.shortname = "nw";
|
---|
137 | ainfo.longname = "new encoding";
|
---|
138 | ainfo.multiplechar = true;
|
---|
139 | ainfo.defaultstatus = cgiarginfo::none;
|
---|
140 | ainfo.argdefault = "";
|
---|
141 | ainfo.savedarginfo = cgiarginfo::mustnot;
|
---|
142 | argsinfo.addarginfo (NULL, ainfo);
|
---|
143 |
|
---|
144 | ainfo.shortname = "c";
|
---|
145 | ainfo.longname = "collection";
|
---|
146 | ainfo.multiplechar = true;
|
---|
147 | ainfo.defaultstatus = cgiarginfo::none;
|
---|
148 | ainfo.argdefault = "";
|
---|
149 | ainfo.savedarginfo = cgiarginfo::must;
|
---|
150 | argsinfo.addarginfo (NULL, ainfo);
|
---|
151 |
|
---|
152 | // 0=text+graphics, 1=text
|
---|
153 | ainfo.shortname = "v";
|
---|
154 | ainfo.longname = "version";
|
---|
155 | ainfo.multiplechar = false;
|
---|
156 | ainfo.defaultstatus = cgiarginfo::weak;
|
---|
157 | ainfo.argdefault = "0";
|
---|
158 | ainfo.savedarginfo = cgiarginfo::can;
|
---|
159 | argsinfo.addarginfo (NULL, ainfo);
|
---|
160 |
|
---|
161 | // 0=normal, 1=big
|
---|
162 | ainfo.shortname = "f";
|
---|
163 | ainfo.longname = "query box size";
|
---|
164 | ainfo.multiplechar = false;
|
---|
165 | ainfo.defaultstatus = cgiarginfo::weak;
|
---|
166 | ainfo.argdefault = "0";
|
---|
167 | ainfo.savedarginfo = cgiarginfo::can;
|
---|
168 | argsinfo.addarginfo (NULL, ainfo);
|
---|
169 |
|
---|
170 | // the interface language name should use the ISO 639
|
---|
171 | // standard
|
---|
172 | ainfo.shortname = "l";
|
---|
173 | ainfo.longname = "interface language";
|
---|
174 | ainfo.multiplechar = true;
|
---|
175 | ainfo.defaultstatus = cgiarginfo::weak;
|
---|
176 | ainfo.argdefault = "en";
|
---|
177 | ainfo.savedarginfo = cgiarginfo::must;
|
---|
178 | argsinfo.addarginfo (NULL, ainfo);
|
---|
179 | }
|
---|
180 |
|
---|
181 |
|
---|
182 | // configure should be called for each line in the
|
---|
183 | // configuration files to configure the receptionist and everything
|
---|
184 | // it contains. The configuration should take place after everything
|
---|
185 | // has been added but before the initialisation.
|
---|
186 | void receptionist::configure (const text_t &key, const text_tarray &cfgline) {
|
---|
187 | // configure the receptionist
|
---|
188 | if (cfgline.size() >= 1) {
|
---|
189 | cgiarginfo *info = NULL;
|
---|
190 | if (key == "gsdlhome") configinfo.gsdlhome = cfgline[0];
|
---|
191 | else if (key == "collection") {
|
---|
192 | configinfo.collection = cfgline[0];
|
---|
193 | // also need to set the default arg to this collection
|
---|
194 | if ((info = argsinfo.getarginfo("c")) != NULL) {
|
---|
195 | info->defaultstatus = cgiarginfo::good;
|
---|
196 | info->argdefault = cfgline[0];
|
---|
197 | }
|
---|
198 |
|
---|
199 | } else if (key == "collectdir") configinfo.collectdir = cfgline[0];
|
---|
200 | else if (key == "httpprefix") configinfo.httpprefix = cfgline[0];
|
---|
201 | else if (key == "httpimg") configinfo.httpimg = cfgline[0];
|
---|
202 | else if (key == "gwcgi") configinfo.gwcgi = cfgline[0];
|
---|
203 | else if (key == "macrofiles") configinfo.macrofiles = cfgline;
|
---|
204 | else if (key == "saveconf") configinfo.saveconf = cfgline[0];
|
---|
205 |
|
---|
206 | else if ((key == "argdefault") && (cfgline.size() == 2) &&
|
---|
207 | ((info = argsinfo.getarginfo(cfgline[0])) != NULL)) {
|
---|
208 | if (info->defaultstatus <= cgiarginfo::config) {
|
---|
209 | info->defaultstatus = cgiarginfo::config;
|
---|
210 | info->argdefault = cfgline[1];
|
---|
211 | }
|
---|
212 | }
|
---|
213 | }
|
---|
214 |
|
---|
215 | // configure the actions
|
---|
216 | actionptrmap::iterator actionhere = actions.begin ();
|
---|
217 | actionptrmap::iterator actionend = actions.end ();
|
---|
218 |
|
---|
219 | while (actionhere != actionend) {
|
---|
220 | assert ((*actionhere).second.a != NULL);
|
---|
221 | if ((*actionhere).second.a != NULL)
|
---|
222 | (*actionhere).second.a->configure(key, cfgline);
|
---|
223 |
|
---|
224 | actionhere++;
|
---|
225 | }
|
---|
226 |
|
---|
227 | // configure the protocols
|
---|
228 | recptprotolistclass::iterator protohere = protocols.begin ();
|
---|
229 | recptprotolistclass::iterator protoend = protocols.end ();
|
---|
230 |
|
---|
231 | while (protohere != protoend) {
|
---|
232 | assert ((*protohere).p != NULL);
|
---|
233 | if ((*protohere).p != NULL)
|
---|
234 | (*protohere).p->configure(key, cfgline);
|
---|
235 |
|
---|
236 | protohere++;
|
---|
237 | }
|
---|
238 | }
|
---|
239 |
|
---|
240 | void receptionist::configure (const text_t &key, const text_t &value) {
|
---|
241 | text_tarray cfgline;
|
---|
242 | cfgline.push_back (value);
|
---|
243 | configure(key, cfgline);
|
---|
244 | }
|
---|
245 |
|
---|
246 |
|
---|
247 | // init should be called after all the actions, protocols, and
|
---|
248 | // converters have been added to the receptionist and after everything
|
---|
249 | // has been configured but before any pages are created.
|
---|
250 | // It returns true on success and false on failure. If false is
|
---|
251 | // returned getpage should not be called (without producing
|
---|
252 | // meaningless output), instead an error page should be
|
---|
253 | // produced by the calling code.
|
---|
254 | bool receptionist::init (ostream &logout) {
|
---|
255 | // first configure collectdir
|
---|
256 | text_t thecollectdir = configinfo.gsdlhome;
|
---|
257 | if (!configinfo.collection.empty()) {
|
---|
258 | // collection specific mode
|
---|
259 | if (!configinfo.collectdir.empty()) {
|
---|
260 | // has already been configured
|
---|
261 | thecollectdir = configinfo.collectdir;
|
---|
262 | } else {
|
---|
263 | // decide where collectdir is by searching for collect.cfg
|
---|
264 | // look in $GSDLHOME/collect/collection-name/etc/collect.cfg and
|
---|
265 | // then $GSDLHOME/etc/collect.cfg
|
---|
266 | thecollectdir = filename_cat (configinfo.gsdlhome, "collect");
|
---|
267 | thecollectdir = filename_cat (thecollectdir, configinfo.collection);
|
---|
268 | text_t filename = filename_cat (thecollectdir, "etc");
|
---|
269 | filename = filename_cat (filename, "collect.cfg");
|
---|
270 |
|
---|
271 | if (!file_exists(filename)) thecollectdir = configinfo.gsdlhome;
|
---|
272 | }
|
---|
273 | }
|
---|
274 | configure("collectdir", thecollectdir);
|
---|
275 |
|
---|
276 | // read in the macro files
|
---|
277 | if (!read_macrofiles (logout)) return false;
|
---|
278 |
|
---|
279 | // there must be at least one action defined
|
---|
280 | if (actions.empty()) {
|
---|
281 | logout << "Error: no actions have been added to the receptionist\n";
|
---|
282 | return false;
|
---|
283 | }
|
---|
284 |
|
---|
285 | // add the cgi arguments from the actions
|
---|
286 | actionptrmap::iterator here = actions.begin ();
|
---|
287 | actionptrmap::iterator end = actions.end ();
|
---|
288 | while (here != end) {
|
---|
289 | assert ((*here).second.a != NULL);
|
---|
290 | if ((*here).second.a != NULL) {
|
---|
291 | if (!argsinfo.addarginfo (&logout, (*here).second.a->getargsinfo()))
|
---|
292 | return false;
|
---|
293 | }
|
---|
294 | here++;
|
---|
295 | }
|
---|
296 |
|
---|
297 | // create a saveconf string if there isn't one already
|
---|
298 | if (configinfo.saveconf.empty())
|
---|
299 | configinfo.saveconf = create_save_conf_str (argsinfo, logout);
|
---|
300 |
|
---|
301 | // check the saveconf string
|
---|
302 | if (!check_save_conf_str (configinfo.saveconf, argsinfo, logout))
|
---|
303 | return false;
|
---|
304 |
|
---|
305 | // set a random seed
|
---|
306 | srand (time(NULL));
|
---|
307 |
|
---|
308 | // make the output converters remove all the zero-width spaces
|
---|
309 | convertinfoclass::iterator converthere = converters.begin ();
|
---|
310 | convertinfoclass::iterator convertend = converters.end ();
|
---|
311 | text_t defaultconvertname;
|
---|
312 | while (converthere != convertend) {
|
---|
313 | assert ((*converthere).second.outconverter != NULL);
|
---|
314 | if ((*converthere).second.outconverter != NULL) {
|
---|
315 | (*converthere).second.outconverter->set_rzws(1);
|
---|
316 | if (defaultconvertname.empty())
|
---|
317 | defaultconvertname = (*converthere).second.name;
|
---|
318 | }
|
---|
319 | converthere++;
|
---|
320 | }
|
---|
321 |
|
---|
322 | // set default converter if no good one has been defined
|
---|
323 | if (!defaultconvertname.empty()) {
|
---|
324 | cgiarginfo *ainfo = argsinfo.getarginfo ("w");
|
---|
325 | if ((ainfo != NULL) && (ainfo->defaultstatus < cgiarginfo::config)) {
|
---|
326 | ainfo->defaultstatus = cgiarginfo::good;
|
---|
327 | ainfo->argdefault = defaultconvertname;
|
---|
328 | }
|
---|
329 | }
|
---|
330 |
|
---|
331 | // init the actions
|
---|
332 | actionptrmap::iterator actionhere = actions.begin ();
|
---|
333 | actionptrmap::iterator actionend = actions.end ();
|
---|
334 | while (actionhere != actionend) {
|
---|
335 | if (((*actionhere).second.a == NULL) ||
|
---|
336 | !(*actionhere).second.a->init(logout)) return false;
|
---|
337 | actionhere++;
|
---|
338 | }
|
---|
339 |
|
---|
340 | // init the protocols
|
---|
341 | recptprotolistclass::iterator protohere = protocols.begin ();
|
---|
342 | recptprotolistclass::iterator protoend = protocols.end ();
|
---|
343 | while (protohere != protoend) {
|
---|
344 | if (((*protohere).p == NULL) ||
|
---|
345 | !(*protohere).p->init(logout)) return false;
|
---|
346 | protohere++;
|
---|
347 | }
|
---|
348 |
|
---|
349 | return true;
|
---|
350 | }
|
---|
351 |
|
---|
352 |
|
---|
353 | // parse_cgi_args parses cgi arguments into an argument class.
|
---|
354 | // This function should be called for each page request. It returns false
|
---|
355 | // if there was a major problem with the cgi arguments.
|
---|
356 | bool receptionist::parse_cgi_args (const text_t &argstr, cgiargsclass &args,
|
---|
357 | ostream &logout) {
|
---|
358 | outconvertclass text_t2ascii;
|
---|
359 |
|
---|
360 | // get an initial list of cgi arguments
|
---|
361 | args.clear();
|
---|
362 | split_cgi_args (argstr, args);
|
---|
363 |
|
---|
364 | // expand the compressed argument (if there was one)
|
---|
365 | if (!expand_save_args (argsinfo, configinfo.saveconf, args, logout)) return false;
|
---|
366 |
|
---|
367 | // add the defaults
|
---|
368 | add_default_args (argsinfo, args, logout);
|
---|
369 |
|
---|
370 |
|
---|
371 | // get the input encoding
|
---|
372 | text_t &arg_w = args["w"];
|
---|
373 | inconvertclass defaultinconvert;
|
---|
374 | inconvertclass *inconvert = converters.get_inconverter (arg_w);
|
---|
375 | if (inconvert == NULL) inconvert = &defaultinconvert;
|
---|
376 |
|
---|
377 | // see if the next page will have a different encoding
|
---|
378 | if (args.getarg("nw") != NULL) arg_w = args["nw"];
|
---|
379 |
|
---|
380 | // convert arguments which aren't in unicode to unicode
|
---|
381 | args_tounicode (args, *inconvert);
|
---|
382 |
|
---|
383 |
|
---|
384 | // decide on the output conversion class (needed for checking the external
|
---|
385 | // cgi arguments)
|
---|
386 | rzwsoutconvertclass defaultoutconverter;
|
---|
387 | rzwsoutconvertclass *outconverter = converters.get_outconverter (arg_w);
|
---|
388 | if (outconverter == NULL) outconverter = &defaultoutconverter;
|
---|
389 | outconverter->reset();
|
---|
390 |
|
---|
391 |
|
---|
392 | // check the main cgi arguments
|
---|
393 | if (!check_mainargs (args, logout)) return false;
|
---|
394 |
|
---|
395 | // check the arguments for the action
|
---|
396 | action *a = actions.getaction (args["a"]);
|
---|
397 | if (a != NULL) {
|
---|
398 | if (!a->check_cgiargs (argsinfo, args, logout)) return false;
|
---|
399 | } else {
|
---|
400 | // the action was not found!!
|
---|
401 | logout << text_t2ascii << "Error: the action \"" << args["a"]
|
---|
402 | << "\" could not be found.\n";
|
---|
403 | return false;
|
---|
404 | }
|
---|
405 |
|
---|
406 | // check external cgi arguments for each action
|
---|
407 | actionptrmap::iterator actionhere = actions.begin ();
|
---|
408 | actionptrmap::iterator actionend = actions.end ();
|
---|
409 | while (actionhere != actionend) {
|
---|
410 | assert ((*actionhere).second.a != NULL);
|
---|
411 | if ((*actionhere).second.a != NULL) {
|
---|
412 | if (!(*actionhere).second.a->check_external_cgiargs (argsinfo, args, *outconverter,
|
---|
413 | configinfo.saveconf, logout))
|
---|
414 | return false;
|
---|
415 | }
|
---|
416 | actionhere++;
|
---|
417 | }
|
---|
418 |
|
---|
419 | // the action might have changed but we will assume that
|
---|
420 | // the cgiargs were checked properly when the change was made
|
---|
421 |
|
---|
422 | return true;
|
---|
423 | }
|
---|
424 |
|
---|
425 |
|
---|
426 | // produce_cgi_page will call get_cgihead_info and
|
---|
427 | // produce_content in the appropriate way to output a cgi header and
|
---|
428 | // the page content (if needed). If a page could not be created it
|
---|
429 | // will return false
|
---|
430 | bool receptionist::produce_cgi_page (cgiargsclass &args, ostream &contentout,
|
---|
431 | ostream &logout) {
|
---|
432 | outconvertclass text_t2ascii;
|
---|
433 |
|
---|
434 | response_t response;
|
---|
435 | text_t response_data;
|
---|
436 |
|
---|
437 | // produce cgi header
|
---|
438 | get_cgihead_info (args, response, response_data, logout);
|
---|
439 | if (response == location) {
|
---|
440 | // I've forgotten how to do this :-/
|
---|
441 | return true;
|
---|
442 | } else if (response == content) {
|
---|
443 | // content response
|
---|
444 | contentout << text_t2ascii << "Content-type: " << response_data << "\n\n";
|
---|
445 | } else {
|
---|
446 | // unknown response
|
---|
447 | logout << "Error: get_cgihead_info returned an unknown response type.\n";
|
---|
448 | return false;
|
---|
449 | }
|
---|
450 |
|
---|
451 | // produce cgi page
|
---|
452 | if (!produce_content (args, contentout, logout)) return false;
|
---|
453 |
|
---|
454 | // flush contentout
|
---|
455 | contentout << flush;
|
---|
456 | return true;
|
---|
457 | }
|
---|
458 |
|
---|
459 |
|
---|
460 | // get_cgihead_info determines the cgi header information for
|
---|
461 | // a set of cgi arguments. If response contains location then
|
---|
462 | // response_data contains the redirect address. If reponse
|
---|
463 | // contains content then reponse_data contains the content-type.
|
---|
464 | // Note that images can now be produced by the receptionist.
|
---|
465 | void receptionist::get_cgihead_info (cgiargsclass &args, response_t &response,
|
---|
466 | text_t &response_data, ostream &logout) {
|
---|
467 | outconvertclass text_t2ascii;
|
---|
468 |
|
---|
469 | // get the action
|
---|
470 | action *a = actions.getaction (args["a"]);
|
---|
471 | if (a != NULL) {
|
---|
472 | a->get_cgihead_info (args, response, response_data, logout);
|
---|
473 |
|
---|
474 | } else {
|
---|
475 | // the action was not found!!
|
---|
476 | logout << text_t2ascii << "Error receptionist::get_cgihead_info: the action \""
|
---|
477 | << args["a"] << "\" could not be found.\n";
|
---|
478 | response = content;
|
---|
479 | response_data = "text/html";
|
---|
480 | }
|
---|
481 |
|
---|
482 | // add the encoding information
|
---|
483 | if (response == content) {
|
---|
484 | if (args["w"] == "u") {
|
---|
485 | response_data += "; charset=UTF-8";
|
---|
486 | } else {
|
---|
487 | response_data += "; charset=ISO-8859-1";
|
---|
488 | }
|
---|
489 | }
|
---|
490 | }
|
---|
491 |
|
---|
492 |
|
---|
493 | // produce the page content
|
---|
494 | bool receptionist::produce_content (cgiargsclass &args, ostream &contentout,
|
---|
495 | ostream &logout) {
|
---|
496 | // decide on the output conversion class
|
---|
497 | text_t &arg_w = args["w"];
|
---|
498 | rzwsoutconvertclass defaultoutconverter;
|
---|
499 | rzwsoutconvertclass *outconverter = converters.get_outconverter (arg_w);
|
---|
500 | if (outconverter == NULL) outconverter = &defaultoutconverter;
|
---|
501 | outconverter->reset();
|
---|
502 |
|
---|
503 | // decide on the protocol used for communicating with
|
---|
504 | // the collection server
|
---|
505 | recptproto *collectproto = NULL;
|
---|
506 | if (!args["c"].empty()) {
|
---|
507 | collectproto = protocols.getrecptproto (args["c"], logout);
|
---|
508 | }
|
---|
509 |
|
---|
510 | // produce the page using the desired action
|
---|
511 | action *a = actions.getaction (args["a"]);
|
---|
512 | if (a != NULL) {
|
---|
513 | if (a->uses_display(args)) prepare_page (a, args, collectproto, (*outconverter), logout);
|
---|
514 | if (!a->do_action (args, collectinfo, collectproto, disp,
|
---|
515 | (*outconverter), contentout, logout))
|
---|
516 | return false;
|
---|
517 |
|
---|
518 | } else {
|
---|
519 | // the action was not found!!
|
---|
520 | outconvertclass text_t2ascii;
|
---|
521 |
|
---|
522 | logout << text_t2ascii << "Error receptionist::produce_content: the action \""
|
---|
523 | << args["a"] << "\" could not be found.\n";
|
---|
524 |
|
---|
525 | contentout << (*outconverter)
|
---|
526 | << "<html>\n"
|
---|
527 | << "<head>\n"
|
---|
528 | << "<title>Error</title>\n"
|
---|
529 | << "</head>\n"
|
---|
530 | << "<body>\n"
|
---|
531 | << "<h2>Oops!</h2>\n"
|
---|
532 | << "Undefined Page. The action \""
|
---|
533 | << args["a"] << "\" could not be found.\n"
|
---|
534 | << "</body>\n"
|
---|
535 | << "</html>\n";
|
---|
536 | }
|
---|
537 |
|
---|
538 | return true;
|
---|
539 | }
|
---|
540 |
|
---|
541 |
|
---|
542 | // returns the compressed argument ("e") corresponding to the argument
|
---|
543 | // list. This can be used to save preferences between sessions.
|
---|
544 | text_t receptionist::get_compressed_arg (cgiargsclass &args, ostream &logout) {
|
---|
545 | // decide on the output conversion class
|
---|
546 | text_t &arg_w = args["w"];
|
---|
547 | rzwsoutconvertclass defaultoutconverter;
|
---|
548 | rzwsoutconvertclass *outconverter = converters.get_outconverter (arg_w);
|
---|
549 | if (outconverter == NULL) outconverter = &defaultoutconverter;
|
---|
550 | outconverter->reset();
|
---|
551 |
|
---|
552 | text_t compressed_args;
|
---|
553 | if (compress_save_args (argsinfo, configinfo.saveconf, args,
|
---|
554 | compressed_args, *outconverter, logout))
|
---|
555 | return compressed_args;
|
---|
556 |
|
---|
557 | return "";
|
---|
558 | }
|
---|
559 |
|
---|
560 |
|
---|
561 | // will read in all the macro files. If one is not found an
|
---|
562 | // error message will be written to logout and the method will
|
---|
563 | // return false.
|
---|
564 | bool receptionist::read_macrofiles (ostream &logout) {
|
---|
565 | outconvertclass text_t2ascii;
|
---|
566 |
|
---|
567 | // redirect the error output to logout
|
---|
568 | disp.setlogout (&logout);
|
---|
569 |
|
---|
570 | // load up the default macro files, the collection directory
|
---|
571 | // is searched first for the file (if this is being used in
|
---|
572 | // collection specific mode) and then the main directory
|
---|
573 | text_t colmacrodir = filename_cat (configinfo.collectdir, "macros");
|
---|
574 | text_t gsdlmacrodir = filename_cat (configinfo.gsdlhome, "macros");
|
---|
575 | text_tarray::iterator arrhere = configinfo.macrofiles.begin();
|
---|
576 | text_tarray::iterator arrend = configinfo.macrofiles.end();
|
---|
577 | text_t filename;
|
---|
578 | while (arrhere != arrend) {
|
---|
579 | // filename is used as a flag to indicate whether
|
---|
580 | // the macro file has been found
|
---|
581 | filename.clear();
|
---|
582 |
|
---|
583 | // try in the collection directory if this is being
|
---|
584 | // run in collection specific mode
|
---|
585 | if (!configinfo.collection.empty()) {
|
---|
586 | filename = filename_cat (colmacrodir, *arrhere);
|
---|
587 | if (!file_exists (filename)) filename.clear ();
|
---|
588 | }
|
---|
589 |
|
---|
590 | // if we haven't found the macro file yet try in
|
---|
591 | // the main macro directory
|
---|
592 | if (filename.empty()) {
|
---|
593 | filename = filename_cat (gsdlmacrodir, *arrhere);
|
---|
594 | if (!file_exists (filename)) filename.clear ();
|
---|
595 | }
|
---|
596 |
|
---|
597 | // see if we found the file or not
|
---|
598 | if (filename.empty()) {
|
---|
599 | logout << text_t2ascii
|
---|
600 | << "Error: the macro file \"" << *arrhere << "\" could not be found.\n";
|
---|
601 | if (configinfo.collection.empty()) {
|
---|
602 | logout << text_t2ascii
|
---|
603 | << "It should be in " << gsdlmacrodir << ".\n\n";
|
---|
604 | } else {
|
---|
605 | logout << text_t2ascii
|
---|
606 | << "It should be in either " << colmacrodir << " or in "
|
---|
607 | << gsdlmacrodir << ".\n\n";
|
---|
608 | }
|
---|
609 | return false;
|
---|
610 |
|
---|
611 | } else { // found the file
|
---|
612 | disp.loaddefaultmacros(filename);
|
---|
613 | }
|
---|
614 |
|
---|
615 | arrhere++;
|
---|
616 | }
|
---|
617 |
|
---|
618 | // success
|
---|
619 | return true;
|
---|
620 | }
|
---|
621 |
|
---|
622 |
|
---|
623 | // check_mainargs will check all the main arguments. If a major
|
---|
624 | // error is found it will return false and no cgi page should
|
---|
625 | // be created using the arguments.
|
---|
626 | bool receptionist::check_mainargs (cgiargsclass &args, ostream &/*logout*/) {
|
---|
627 | // if this receptionist is running in collection dependant mode
|
---|
628 | // then it should always set the collection argument to the
|
---|
629 | // collection
|
---|
630 | if (!configinfo.collection.empty()) args["c"] = configinfo.collection;
|
---|
631 |
|
---|
632 | // argument "v" can only be 0 or 1. Use the default value
|
---|
633 | // if it is out of range
|
---|
634 | int arg_v = args.getintarg ("v");
|
---|
635 | if (arg_v != 0 && arg_v != 1) {
|
---|
636 | cgiarginfo *vinfo = argsinfo.getarginfo ("v");
|
---|
637 | if (vinfo != NULL) args["v"] = vinfo->argdefault;
|
---|
638 | }
|
---|
639 |
|
---|
640 | // argument "f" can only be 0 or 1. Use the default value
|
---|
641 | // if it is out of range
|
---|
642 | int arg_f = args.getintarg ("f");
|
---|
643 | if (arg_f != 0 && arg_f != 1) {
|
---|
644 | cgiarginfo *finfo = argsinfo.getarginfo ("f");
|
---|
645 | if (finfo != NULL) args["f"] = finfo->argdefault;
|
---|
646 | }
|
---|
647 |
|
---|
648 | return true;
|
---|
649 | }
|
---|
650 |
|
---|
651 | // prepare_page sets up page parameters, sets display macros,
|
---|
652 | // gets format information and opens the page ready for output
|
---|
653 | void receptionist::prepare_page (action *a, cgiargsclass &args, recptproto *collectproto,
|
---|
654 | outconvertclass &outconvert, ostream &logout) {
|
---|
655 | // set up page parameters
|
---|
656 | text_t pageparams;
|
---|
657 | text_t &collection = args["c"];
|
---|
658 |
|
---|
659 | bool first = true;
|
---|
660 | if (!collection.empty()) {
|
---|
661 | pageparams += "collection=" + collection; first = false;}
|
---|
662 | if (args.getintarg("u") == 1)
|
---|
663 | if (first) {pageparams += "style=htmlonly"; first = false;}
|
---|
664 | else pageparams += ",style=htmlonly";
|
---|
665 | if (args.getintarg("v") == 1)
|
---|
666 | if (first) {pageparams += "version=text"; first = false;}
|
---|
667 | else pageparams += ",version=text";
|
---|
668 | if (args.getintarg("f") == 1)
|
---|
669 | if (first) {pageparams += ",queryversion=big"; first = false;}
|
---|
670 | else pageparams += ",queryversion=big";
|
---|
671 | if (args["l"] != "en")
|
---|
672 | if (first) pageparams += ",language=" + args["l"];
|
---|
673 | else pageparams += ",language=" + args["l"];
|
---|
674 |
|
---|
675 | // get collection information
|
---|
676 | collectinfo.clear();
|
---|
677 | if (!collection.empty()) {
|
---|
678 | comerror_t err;
|
---|
679 | collectproto->get_collectinfo (collection, collectinfo, err, logout);
|
---|
680 | if (err != noError) collectinfo.clear();
|
---|
681 | }
|
---|
682 |
|
---|
683 | // open the page
|
---|
684 | disp.openpage(pageparams, MACROPRECEDENCE);
|
---|
685 |
|
---|
686 |
|
---|
687 | // define general macros
|
---|
688 | define_general_macros (args, outconvert, logout);
|
---|
689 |
|
---|
690 |
|
---|
691 | // define external macros for each action
|
---|
692 | actionptrmap::iterator actionhere = actions.begin ();
|
---|
693 | actionptrmap::iterator actionend = actions.end ();
|
---|
694 |
|
---|
695 | while (actionhere != actionend) {
|
---|
696 | assert ((*actionhere).second.a != NULL);
|
---|
697 | if ((*actionhere).second.a != NULL)
|
---|
698 | (*actionhere).second.a->define_external_macros (collectinfo, disp, args, collectproto, logout);
|
---|
699 | actionhere++;
|
---|
700 | }
|
---|
701 |
|
---|
702 | // define internal macros for the current action
|
---|
703 | a->define_internal_macros (collectinfo, disp, args, collectproto, logout);
|
---|
704 | }
|
---|
705 |
|
---|
706 | void receptionist::define_general_macros (cgiargsclass &args, outconvertclass &/*outconvert*/,
|
---|
707 | ostream &logout) {
|
---|
708 | disp.setmacro ("gwcgi", "Global", configinfo.gwcgi);
|
---|
709 | disp.setmacro ("httpimg", "Global", configinfo.httpimg);
|
---|
710 | disp.setmacro ("httpprefix", "Global", configinfo.httpprefix);
|
---|
711 | disp.setmacro("compressedoptions", "Global", get_compressed_arg(args, logout));
|
---|
712 |
|
---|
713 | // set _cgiargX_ macros for each cgi argument
|
---|
714 | cgiargsclass::const_iterator argshere = args.begin();
|
---|
715 | cgiargsclass::const_iterator argsend = args.end();
|
---|
716 | while (argshere != argsend) {
|
---|
717 | if ((*argshere).first == "q")
|
---|
718 | // need to escape special characters from query string
|
---|
719 | disp.setmacro ("cgiargq", "Global", html_safe((*argshere).second.value));
|
---|
720 | else
|
---|
721 | disp.setmacro ("cgiarg" + (*argshere).first, "Global", (*argshere).second.value);
|
---|
722 | argshere ++;
|
---|
723 | }
|
---|
724 | }
|
---|