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