[108] | 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$
|
---|
[388] | 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 |
|
---|
[366] | 20 | Revision 1.18 1999/07/11 01:05:20 rjmcnab
|
---|
| 21 | Stored origin of cgiarg with argument.
|
---|
| 22 |
|
---|
[362] | 23 | Revision 1.17 1999/07/10 22:18:26 rjmcnab
|
---|
| 24 | Added calls to define_external_cgiargs.
|
---|
| 25 |
|
---|
[297] | 26 | Revision 1.16 1999/06/27 21:49:03 sjboddie
|
---|
| 27 | fixed a couple of version conflicts - tidied up some small things
|
---|
| 28 |
|
---|
[296] | 29 | Revision 1.15 1999/06/26 01:14:32 rjmcnab
|
---|
| 30 | Made a couple of changes to handle different encodings.
|
---|
| 31 |
|
---|
[263] | 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 |
|
---|
[261] | 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 |
|
---|
[248] | 39 | Revision 1.12 1999/04/30 01:59:42 sjboddie
|
---|
| 40 | lots of stuff - getting documentaction working (documentaction replaces
|
---|
| 41 | old browseaction)
|
---|
| 42 |
|
---|
[206] | 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 |
|
---|
[189] | 49 | Revision 1.10 1999/03/05 03:53:54 sjboddie
|
---|
| 50 |
|
---|
| 51 | fixed some bugs
|
---|
| 52 |
|
---|
[173] | 53 | Revision 1.9 1999/02/28 20:00:16 rjmcnab
|
---|
| 54 |
|
---|
| 55 |
|
---|
| 56 | Fixed a few things.
|
---|
| 57 |
|
---|
[172] | 58 | Revision 1.8 1999/02/25 21:58:59 rjmcnab
|
---|
| 59 |
|
---|
| 60 | Merged sources.
|
---|
| 61 |
|
---|
[165] | 62 | Revision 1.7 1999/02/21 22:33:55 rjmcnab
|
---|
| 63 |
|
---|
| 64 | Lots of stuff :-)
|
---|
| 65 |
|
---|
[158] | 66 | Revision 1.6 1999/02/11 01:24:05 rjmcnab
|
---|
| 67 |
|
---|
| 68 | Fixed a few compiler warnings.
|
---|
| 69 |
|
---|
[155] | 70 | Revision 1.5 1999/02/08 01:28:02 rjmcnab
|
---|
| 71 |
|
---|
| 72 | Got the receptionist producing something using the statusaction.
|
---|
| 73 |
|
---|
[150] | 74 | Revision 1.4 1999/02/05 10:42:46 rjmcnab
|
---|
| 75 |
|
---|
| 76 | Continued working on receptionist
|
---|
| 77 |
|
---|
[146] | 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 |
|
---|
[145] | 83 | Revision 1.2 1999/02/04 01:17:27 rjmcnab
|
---|
[108] | 84 |
|
---|
[145] | 85 | Got it outputing something.
|
---|
[108] | 86 |
|
---|
| 87 |
|
---|
| 88 | */
|
---|
| 89 |
|
---|
| 90 |
|
---|
| 91 | #include "receptionist.h"
|
---|
| 92 | #include "fileutil.h"
|
---|
[155] | 93 | #include "cgiutils.h"
|
---|
[263] | 94 | #include "htmlutils.h"
|
---|
[248] | 95 | #include "OIDtools.h"
|
---|
[108] | 96 | #include <assert.h>
|
---|
[150] | 97 | #include <time.h>
|
---|
[108] | 98 |
|
---|
| 99 |
|
---|
| 100 |
|
---|
[388] | 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 |
|
---|
[165] | 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) {
|
---|
[388] | 185 | cgiarginfo *info = NULL;
|
---|
[165] | 186 | if (key == "gsdlhome") configinfo.gsdlhome = cfgline[0];
|
---|
[388] | 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];
|
---|
[297] | 196 | else if (key == "httpprefix") configinfo.httpprefix = cfgline[0];
|
---|
[165] | 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];
|
---|
[388] | 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 | }
|
---|
[165] | 209 | }
|
---|
[108] | 210 |
|
---|
[165] | 211 | // configure the actions
|
---|
| 212 | actionptrmap::iterator actionhere = actions.begin ();
|
---|
| 213 | actionptrmap::iterator actionend = actions.end ();
|
---|
[108] | 214 |
|
---|
[165] | 215 | while (actionhere != actionend) {
|
---|
| 216 | assert ((*actionhere).second.a != NULL);
|
---|
| 217 | if ((*actionhere).second.a != NULL)
|
---|
| 218 | (*actionhere).second.a->configure(key, cfgline);
|
---|
[108] | 219 |
|
---|
[165] | 220 | actionhere++;
|
---|
| 221 | }
|
---|
[108] | 222 |
|
---|
[165] | 223 | // configure the protocols
|
---|
| 224 | recptprotolistclass::iterator protohere = protocols.begin ();
|
---|
| 225 | recptprotolistclass::iterator protoend = protocols.end ();
|
---|
[108] | 226 |
|
---|
[165] | 227 | while (protohere != protoend) {
|
---|
| 228 | assert ((*protohere).p != NULL);
|
---|
| 229 | if ((*protohere).p != NULL)
|
---|
| 230 | (*protohere).p->configure(key, cfgline);
|
---|
| 231 |
|
---|
| 232 | protohere++;
|
---|
[155] | 233 | }
|
---|
[108] | 234 | }
|
---|
| 235 |
|
---|
[165] | 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.
|
---|
[145] | 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.
|
---|
[150] | 250 | bool receptionist::init (ostream &logout) {
|
---|
[165] | 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
|
---|
[189] | 262 | thecollectdir = filename_cat (configinfo.gsdlhome, "collect");
|
---|
[165] | 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 |
|
---|
[155] | 271 | // read in the macro files
|
---|
| 272 | if (!read_macrofiles (logout)) return false;
|
---|
[108] | 273 |
|
---|
[165] | 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 |
|
---|
[155] | 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 | }
|
---|
[108] | 291 |
|
---|
[155] | 292 | // create a saveconf string if there isn't one already
|
---|
[165] | 293 | if (configinfo.saveconf.empty())
|
---|
| 294 | configinfo.saveconf = create_save_conf_str (argsinfo, logout);
|
---|
[108] | 295 |
|
---|
[155] | 296 | // check the saveconf string
|
---|
[165] | 297 | if (!check_save_conf_str (configinfo.saveconf, argsinfo, logout))
|
---|
[155] | 298 | return false;
|
---|
| 299 |
|
---|
| 300 | // set a random seed
|
---|
| 301 | srand (time(NULL));
|
---|
| 302 |
|
---|
[165] | 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 | }
|
---|
[108] | 316 |
|
---|
[165] | 317 | // set default converter if no good one has been defined
|
---|
| 318 | if (!defaultconvertname.empty()) {
|
---|
| 319 | cgiarginfo *ainfo = argsinfo.getarginfo ("w");
|
---|
[388] | 320 | if ((ainfo != NULL) && (ainfo->defaultstatus < cgiarginfo::config)) {
|
---|
[165] | 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 |
|
---|
[146] | 344 | return true;
|
---|
[108] | 345 | }
|
---|
| 346 |
|
---|
| 347 |
|
---|
[155] | 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)
|
---|
[165] | 360 | if (!expand_save_args (argsinfo, configinfo.saveconf, args, logout)) return false;
|
---|
[155] | 361 |
|
---|
| 362 | // add the defaults
|
---|
| 363 | add_default_args (argsinfo, args, logout);
|
---|
| 364 |
|
---|
[362] | 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 |
|
---|
[155] | 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) {
|
---|
[261] | 393 | if (!a->check_cgiargs (argsinfo, args, logout)) return false;
|
---|
[155] | 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 |
|
---|
[362] | 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 | }
|
---|
[165] | 413 |
|
---|
[362] | 414 | // the action might have changed but we will assume that
|
---|
| 415 | // the cgiargs were checked properly when the change was made
|
---|
[165] | 416 |
|
---|
[155] | 417 | return true;
|
---|
| 418 | }
|
---|
| 419 |
|
---|
| 420 |
|
---|
| 421 | // produce_cgi_page will call get_cgihead_info and
|
---|
[145] | 422 | // produce_content in the appropriate way to output a cgi header and
|
---|
[155] | 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,
|
---|
[145] | 426 | ostream &logout) {
|
---|
[155] | 427 | outconvertclass text_t2ascii;
|
---|
[108] | 428 |
|
---|
[155] | 429 | response_t response;
|
---|
| 430 | text_t response_data;
|
---|
[108] | 431 |
|
---|
[155] | 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;
|
---|
[108] | 452 | }
|
---|
| 453 |
|
---|
| 454 |
|
---|
[145] | 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.
|
---|
[146] | 460 | void receptionist::get_cgihead_info (cgiargsclass &args, response_t &response,
|
---|
[145] | 461 | text_t &response_data, ostream &logout) {
|
---|
[155] | 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 | }
|
---|
[388] | 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 | }
|
---|
[108] | 485 | }
|
---|
| 486 |
|
---|
| 487 |
|
---|
[145] | 488 | // produce the page content
|
---|
[155] | 489 | bool receptionist::produce_content (cgiargsclass &args, ostream &contentout,
|
---|
[145] | 490 | ostream &logout) {
|
---|
[155] | 491 | // decide on the output conversion class
|
---|
[165] | 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();
|
---|
[155] | 497 |
|
---|
[165] | 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 |
|
---|
[155] | 505 | // produce the page using the desired action
|
---|
| 506 | action *a = actions.getaction (args["a"]);
|
---|
| 507 | if (a != NULL) {
|
---|
[296] | 508 | if (a->uses_display(args)) prepare_page (a, args, collectproto, (*outconverter), logout);
|
---|
[172] | 509 | if (!a->do_action (args, collectproto, disp, (*outconverter), contentout, logout))
|
---|
[155] | 510 | return false;
|
---|
| 511 |
|
---|
| 512 | } else {
|
---|
| 513 | // the action was not found!!
|
---|
[165] | 514 | outconvertclass text_t2ascii;
|
---|
| 515 |
|
---|
[155] | 516 | logout << text_t2ascii << "Error receptionist::produce_content: the action \""
|
---|
| 517 | << args["a"] << "\" could not be found.\n";
|
---|
| 518 |
|
---|
[165] | 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";
|
---|
[155] | 530 | }
|
---|
| 531 |
|
---|
| 532 | return true;
|
---|
[108] | 533 | }
|
---|
| 534 |
|
---|
| 535 |
|
---|
[145] | 536 | // returns the compressed argument ("e") corresponding to the argument
|
---|
| 537 | // list. This can be used to save preferences between sessions.
|
---|
[362] | 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 |
|
---|
[248] | 546 | text_t compressed_args;
|
---|
| 547 | if (compress_save_args (argsinfo, configinfo.saveconf, args,
|
---|
[362] | 548 | compressed_args, *outconverter, logout))
|
---|
[248] | 549 | return compressed_args;
|
---|
[362] | 550 |
|
---|
| 551 | return "";
|
---|
[108] | 552 | }
|
---|
[155] | 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
|
---|
[165] | 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();
|
---|
[155] | 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
|
---|
[165] | 579 | if (!configinfo.collection.empty()) {
|
---|
[155] | 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";
|
---|
[165] | 595 | if (configinfo.collection.empty()) {
|
---|
[155] | 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.
|
---|
[158] | 620 | bool receptionist::check_mainargs (cgiargsclass &args, ostream &/*logout*/) {
|
---|
[155] | 621 | // if this receptionist is running in collection dependant mode
|
---|
| 622 | // then it should always set the collection argument to the
|
---|
| 623 | // collection
|
---|
[165] | 624 | if (!configinfo.collection.empty()) args["c"] = configinfo.collection;
|
---|
[155] | 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 | }
|
---|
[173] | 644 |
|
---|
| 645 | // prepare_page sets up page parameters, sets display macros
|
---|
| 646 | // and opens the page ready for output
|
---|
[296] | 647 | void receptionist::prepare_page (action *a, cgiargsclass &args, recptproto *collectproto,
|
---|
| 648 | outconvertclass &outconvert, ostream &logout) {
|
---|
[173] | 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
|
---|
[296] | 673 | define_general_macros (args, outconvert, logout);
|
---|
[173] | 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)
|
---|
[206] | 683 | (*actionhere).second.a->define_external_macros (disp, args, collectproto, logout);
|
---|
[173] | 684 | actionhere++;
|
---|
| 685 | }
|
---|
| 686 |
|
---|
| 687 |
|
---|
| 688 | // define internal macros for the current action
|
---|
[206] | 689 | a->define_internal_macros (disp, args, collectproto, logout);
|
---|
[173] | 690 | }
|
---|
| 691 |
|
---|
[362] | 692 | void receptionist::define_general_macros (cgiargsclass &args, outconvertclass &/*outconvert*/,
|
---|
[296] | 693 | ostream &logout) {
|
---|
[173] | 694 | disp.setmacro ("gwcgi", "Global", configinfo.gwcgi);
|
---|
| 695 | disp.setmacro ("httpimg", "Global", configinfo.httpimg);
|
---|
[297] | 696 | disp.setmacro ("httpprefix", "Global", configinfo.httpprefix);
|
---|
[362] | 697 | disp.setmacro("compressedoptions", "Global", get_compressed_arg(args, logout));
|
---|
[173] | 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) {
|
---|
[263] | 703 | if ((*argshere).first == "q")
|
---|
| 704 | // need to escape special characters from query string
|
---|
[366] | 705 | disp.setmacro ("cgiargq", "Global", html_safe((*argshere).second.value));
|
---|
[263] | 706 | else
|
---|
[366] | 707 | disp.setmacro ("cgiarg" + (*argshere).first, "Global", (*argshere).second.value);
|
---|
[173] | 708 | argshere ++;
|
---|
| 709 | }
|
---|
| 710 | }
|
---|