source: main/trunk/greenstone2/runtime-src/src/recpt/documentaction.cpp@ 28899

Last change on this file since 28899 was 28899, checked in by ak19, 10 years ago

Third commit for security, for ensuring cgiargs macros are websafe. This time all the changes to the runtime action classes.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 57.3 KB
Line 
1/**********************************************************************
2 *
3 * documentaction.cpp --
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include <string.h>
27
28#include "documentaction.h"
29#include "recptprototools.h"
30#include "OIDtools.h"
31#include "querytools.h"
32#include "unitool.h"
33#include "gsdltools.h"
34#include "highlighttext.h"
35#include "browsetoolsclass.h"
36
37documentaction::documentaction () {
38 recpt = NULL;
39
40 // this action uses cgi variables "a", "d", "cl",
41 // "x", "gc", "gt", "gp", and "hl"
42 cgiarginfo arg_ainfo;
43 arg_ainfo.shortname = "a";
44 arg_ainfo.longname = "action";
45 arg_ainfo.multiplechar = true;
46 arg_ainfo.multiplevalue = false;
47 arg_ainfo.defaultstatus = cgiarginfo::weak;
48 arg_ainfo.argdefault = "p";
49 arg_ainfo.savedarginfo = cgiarginfo::must;
50 argsinfo.addarginfo (NULL, arg_ainfo);
51
52 arg_ainfo.shortname = "d";
53 arg_ainfo.longname = "document OID";
54 arg_ainfo.multiplechar = true;
55 arg_ainfo.multiplevalue = false;
56 arg_ainfo.defaultstatus = cgiarginfo::none;
57 arg_ainfo.argdefault = g_EmptyText;
58 arg_ainfo.savedarginfo = cgiarginfo::can;
59 argsinfo.addarginfo (NULL, arg_ainfo);
60
61 // whether or not a document should be retrieved from the
62 // library or the Web.
63 arg_ainfo.shortname = "il";
64 arg_ainfo.longname = "internal link preference";
65 arg_ainfo.multiplechar = false;
66 arg_ainfo.multiplevalue = false;
67 arg_ainfo.defaultstatus = cgiarginfo::weak;
68 arg_ainfo.argdefault = "l";
69 arg_ainfo.savedarginfo = cgiarginfo::must;
70 argsinfo.addarginfo (NULL, arg_ainfo);
71
72 arg_ainfo.shortname = "cl";
73 arg_ainfo.longname = "classification OID";
74 arg_ainfo.multiplechar = true;
75 arg_ainfo.multiplevalue = false;
76 arg_ainfo.defaultstatus = cgiarginfo::none;
77 arg_ainfo.argdefault = g_EmptyText;
78 arg_ainfo.savedarginfo = cgiarginfo::can;
79 argsinfo.addarginfo (NULL, arg_ainfo);
80
81 // in this action "gc" controls the expand/contract
82 // contents function
83 arg_ainfo.shortname = "gc";
84 arg_ainfo.longname = "expand contents";
85 arg_ainfo.multiplechar = false;
86 arg_ainfo.multiplevalue = false;
87 arg_ainfo.defaultstatus = cgiarginfo::weak;
88 arg_ainfo.argdefault = "0";
89 arg_ainfo.savedarginfo = cgiarginfo::can;
90 argsinfo.addarginfo (NULL, arg_ainfo);
91
92 // in this action "gt" controls the expand/contract
93 // text function 0 = not expanded, 1 = expand unless
94 // there are more than 10 sections containing text,
95 // 2 = expand all
96 arg_ainfo.shortname = "gt";
97 arg_ainfo.longname = "expand text";
98 arg_ainfo.multiplechar = false;
99 arg_ainfo.multiplevalue = false;
100 arg_ainfo.defaultstatus = cgiarginfo::weak;
101 arg_ainfo.argdefault = "0";
102 arg_ainfo.savedarginfo = cgiarginfo::can;
103 argsinfo.addarginfo (NULL, arg_ainfo);
104
105 // in this action "gp" is the "go to page" control
106 // used by the Book type of toc
107 arg_ainfo.shortname = "gp";
108 arg_ainfo.longname = "go to page";
109 arg_ainfo.multiplechar = true;
110 arg_ainfo.multiplevalue = false;
111 arg_ainfo.defaultstatus = cgiarginfo::none;
112 arg_ainfo.argdefault = g_EmptyText;
113 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
114 argsinfo.addarginfo (NULL, arg_ainfo);
115
116 // in this action "hl" is the "highlighting on/
117 // highlighting off control ("hl" == "2" is a
118 // special case that forces phrase highlighting
119 // to be used even if the query string doesn't
120 // appear to be a phrase)
121 arg_ainfo.shortname = "hl";
122 arg_ainfo.longname = "highlighting on/off";
123 arg_ainfo.multiplechar = false;
124 arg_ainfo.multiplevalue = false;
125 arg_ainfo.defaultstatus = cgiarginfo::weak;
126 arg_ainfo.argdefault = "1";
127 arg_ainfo.savedarginfo = cgiarginfo::must;
128 argsinfo.addarginfo (NULL, arg_ainfo);
129
130 // "x" is 0 normally or 1 if page
131 // has been "detached"
132 arg_ainfo.shortname = "x";
133 arg_ainfo.longname = "detached page";
134 arg_ainfo.multiplechar = false;
135 arg_ainfo.multiplevalue = false;
136 arg_ainfo.defaultstatus = cgiarginfo::weak;
137 arg_ainfo.argdefault = "0";
138 arg_ainfo.savedarginfo = cgiarginfo::must;
139 argsinfo.addarginfo (NULL, arg_ainfo);
140
141 // "xx" is 0 normally or 1 if documents should be detached by default
142 arg_ainfo.shortname = "xx";
143 arg_ainfo.longname = "detach all doc pages";
144 arg_ainfo.multiplechar = false;
145 arg_ainfo.multiplevalue = false;
146 arg_ainfo.defaultstatus = cgiarginfo::weak;
147 arg_ainfo.argdefault = "0";
148 arg_ainfo.savedarginfo = cgiarginfo::must;
149 argsinfo.addarginfo (NULL, arg_ainfo);
150
151
152 // f arg is set to 1 if document is to
153 // be displayed in a frame
154 arg_ainfo.shortname = "f";
155 arg_ainfo.longname = "frame";
156 arg_ainfo.multiplechar = false;
157 arg_ainfo.multiplevalue = false;
158 arg_ainfo.defaultstatus = cgiarginfo::weak;
159 arg_ainfo.argdefault = "0";
160 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
161 argsinfo.addarginfo (NULL, arg_ainfo);
162
163 // fc arg is "1" if search bar is to be included (i.e. if "fc" == 1
164 // the httpdocument macro will include "&f=1"
165 arg_ainfo.shortname = "fc";
166 arg_ainfo.longname = "include search bar";
167 arg_ainfo.multiplechar = false;
168 arg_ainfo.multiplevalue = false;
169 arg_ainfo.defaultstatus = cgiarginfo::weak;
170 arg_ainfo.argdefault = "1";
171 arg_ainfo.savedarginfo = cgiarginfo::must;
172 argsinfo.addarginfo (NULL, arg_ainfo);
173
174 //rd is whether a document will be displayed
175 //with a relevant document list
176 arg_ainfo.shortname = "rd";
177 arg_ainfo.longname = "include relevant documents";
178 arg_ainfo.multiplechar = false;
179 arg_ainfo.multiplevalue = false;
180 arg_ainfo.defaultstatus = cgiarginfo::weak;
181 arg_ainfo.argdefault = "0";
182 arg_ainfo.savedarginfo = cgiarginfo::must;
183 argsinfo.addarginfo (NULL, arg_ainfo);
184
185 //dm is the metadata that has been used for the datelist
186 arg_ainfo.shortname = "dm";
187 arg_ainfo.longname = "date metadata";
188 arg_ainfo.multiplechar = true;
189 arg_ainfo.multiplevalue = false;
190 arg_ainfo.defaultstatus = cgiarginfo::weak;
191 arg_ainfo.argdefault = g_EmptyText;
192 arg_ainfo.savedarginfo = cgiarginfo::must;
193 argsinfo.addarginfo (NULL, arg_ainfo);
194
195}
196
197documentaction::~documentaction()
198{
199}
200
201bool documentaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
202 recptprotolistclass *protos, ostream &logout) {
203
204 if(!args["d"].empty())
205 {
206 text_t docTop;
207 get_top(args["d"],docTop);
208
209 recptproto* collectproto = protos->getrecptproto (args["c"], logout);
210 if (collectproto != NULL)
211 {
212 ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout);
213
214 if(cinfo->authenticate == "document")
215 {
216 // both are either commented out or uncomment and are empty
217 if (cinfo->public_documents.empty() && cinfo->private_documents.empty())
218 {
219 //deny everything
220 args["uan"] = "1";
221 args["ug"] = cinfo->auth_group;
222 }
223
224 // both public_documents and private_documents are turned on !
225 else if (!cinfo->public_documents.empty() && !cinfo->private_documents.empty())
226 {
227 //deny everything
228 args["uan"] = "1";
229 args["ug"] = cinfo->auth_group;
230 }
231
232 // if public_documents is set but this document isn't
233 // listed in it we need to authenticate
234 else if ((!cinfo->public_documents.empty()) &&
235 (cinfo->public_documents.find(docTop) == cinfo->public_documents.end()))
236 {
237 args["uan"] = "1";
238 args["ug"] = cinfo->auth_group;
239 }
240
241 // if private_documents is set and this document is
242 // listed in it we need to authenticate
243 else if ((!cinfo->private_documents.empty()) &&
244 (cinfo->private_documents.find(docTop) != cinfo->private_documents.end()))
245 {
246 args["uan"] = "1";
247 args["ug"] = cinfo->auth_group;
248 }
249
250 }
251 }
252 }
253 // check gc argument
254 int arg_gc = args.getintarg("gc");
255 if (arg_gc < 0 || arg_gc > 2) {
256 logout << "Warning: \"gc\" argument out of range (" << arg_gc << ")\n";
257 cgiarginfo *gcinfo = argsinfo.getarginfo ("gc");
258 if (gcinfo != NULL) args["gc"] = gcinfo->argdefault;
259 }
260
261 // check gt argument (may be either 0, 1 or 2)
262 int arg_gt = args.getintarg("gt");
263 if (arg_gt != 0 && arg_gt != 1 && arg_gt != 2) {
264 logout << "Warning: \"gt\" argument out of range (" << arg_gt << ")\n";
265 cgiarginfo *gtinfo = argsinfo.getarginfo ("gt");
266 if (gtinfo != NULL) args["gt"] = gtinfo->argdefault;
267 }
268
269 // check hl argument
270 int arg_hl = args.getintarg("hl");
271 if (arg_hl < 0 || arg_hl > 2) {
272 logout << "Warning: \"hl\" argument out of range (" << arg_hl << ")\n";
273 cgiarginfo *hlinfo = argsinfo.getarginfo ("hl");
274 if (hlinfo != NULL) args["hl"] = hlinfo->argdefault;
275 }
276
277 // check x argument
278 int arg_x = args.getintarg("x");
279 if (arg_x != 0 && arg_x != 1) {
280 logout << "Warning: \"x\" argument out of range (" << arg_x << ")\n";
281 cgiarginfo *xinfo = argsinfo.getarginfo ("x");
282 if (xinfo != NULL) args["x"] = xinfo->argdefault;
283 }
284
285 //checks whether rd arg is valid
286 int arg_rd = args.getintarg("rd");
287 if (arg_rd != 0 && arg_rd != 1) {
288 logout << "Warning: \"rd\" argument out of range (" << arg_rd << ")\n";
289 cgiarginfo *rdinfo = argsinfo.getarginfo ("rd");
290 if (rdinfo != NULL) args["rd"] = rdinfo->argdefault;
291 }
292
293
294 return true;
295}
296
297void documentaction::get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
298 response_t &response,text_t &response_data,
299 ostream &logout) {
300
301 if ((args["il"] == "w") && (!args["d"].empty())) {
302
303 recptproto* collectproto = protos->getrecptproto (args["c"], logout);
304 if (collectproto != NULL) {
305
306 text_tset metadata;
307 FilterResponse_t filt_response;
308 text_t top;
309
310 metadata.insert ("URL");
311
312 // get metadata for parent document
313 get_top (args["d"], top);
314 if (get_info (top, args["c"], args["l"], metadata, false, collectproto, filt_response, logout)) {
315 text_t url = filt_response.docInfo[0].metadata["URL"].values[0];
316
317 response = location;
318 response_data = url;
319 return;
320 } else {
321 // error, no URL
322 logout << "Error: documentaction::get_cgihead_info failed on get_info" << endl;
323 }
324 }
325 }
326 response = content;
327 response_data = "text/html";
328}
329
330// set_widthtspace calculates how wide the spaces in the nav bar should
331// be and sets the appropriate macro
332void documentaction::set_spacemacro (displayclass &disp, FilterResponse_t &response,
333 bool has_search_button) {
334
335 text_t width;
336 int twidth, swidth, iwidth = 0;
337
338 int numc = response.docInfo.size();
339 ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
340 ResultDocInfo_tarray::iterator docend = response.docInfo.end();
341
342 disp.expandstring (displayclass::defaultpackage, "_pagewidth_", width);
343 twidth = width.getint();
344
345 if (has_search_button) {
346 disp.expandstring ("query", "_searchwidth_", width);
347 iwidth += width.getint();
348 } else {
349 numc -= 1;
350 }
351
352 while (dochere != docend) {
353 const text_t &title = (*dochere).metadata["Title"].values[0];
354
355 disp.expandstring ("document", "_" + title + "width_", width);
356 if (width == ("_" + title + "width_")) {
357 disp.expandstring ("document", "_defaultwidth_", width);
358 }
359 iwidth += width.getint();
360 ++dochere;
361 }
362
363 if ((twidth - iwidth) < numc) swidth = 2;
364 else {
365 swidth = twidth - iwidth;
366 if (numc > 0) swidth = swidth / numc;
367 }
368 disp.setmacro ("widthtspace", displayclass::defaultpackage, swidth);
369}
370
371// set_navbarmacros sets _navigationbar_ and _httpbrowseXXX_ macros
372// reponse contains 1 metadata field (Title)
373void documentaction::set_navbarmacros (displayclass &disp, FilterResponse_t &response,
374 bool has_search_button, cgiargsclass &args,
375 ColInfoResponse_t &cinfo) {
376
377
378 bool use_pulldown = false;
379 text_tmap::iterator it = cinfo.format.find("NavigationBar");
380 if (it != cinfo.format.end()) {
381 if (it->second == "pulldown") {
382 use_pulldown = true;
383 }
384 }
385
386 text_t topparent;
387 text_t &arg_d = args["d"];
388 text_t navigationbar = "<!-- Navigation Bar -->\n";
389
390 get_top (args["cl"], topparent);
391 int numc = response.docInfo.size();
392 ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
393 ResultDocInfo_tarray::iterator docend = response.docInfo.end();
394
395 if (!use_pulldown) {
396 if (has_search_button) {
397 // search uses its own navtab, as it may be suppressed based on other args
398 navigationbar += "_navtabsearch_";
399 if (args["a"] == "q") {
400 navigationbar += "(selected)";
401 }
402 }
403
404 if (has_search_button || numc == 0) navigationbar += "_navbarspacer_";
405
406 bool first = true;
407 while (dochere != docend) {
408 if (!first) navigationbar += "_navbarspacer_";
409
410 text_t title = (*dochere).metadata["Title"].values[0];
411
412 navigationbar += "_navtab_(_httpbrowse"+(*dochere).OID+"_,"+title;
413 // if we are at this classifier
414 if (arg_d.empty() && ((*dochere).OID == topparent)) {
415 // don't link to this classifier as it is the current one
416 navigationbar += ",selected";
417 }
418 navigationbar += ")";
419
420 // set the _httpbrowseCLX_ macro for this classification
421 disp.setmacro ("httpbrowse" + (*dochere).OID, displayclass::defaultpackage, "_httpdocument_&amp;cl=" + (*dochere).OID);
422 ++dochere;
423 first = false;
424 }
425
426 navigationbar += "_dynamicclassifiernavbarentries_";
427 navigationbar += "\n<!-- End of Navigation Bar -->\n";
428
429 } else {
430
431 navigationbar = "<form method=\"get\" name=\"navform\">\n";
432 navigationbar += "<select name=\"navbar\" onChange=\"location.href=";
433 navigationbar += "document.navform.navbar.options[document.navform.navbar.selectedIndex].value\">\n";
434
435 if (args["a"] != "q" && args["cl"].empty()) {
436 navigationbar += "<option value=\"\" selected>_textselectpage_</option>\n";
437 }
438
439 if (has_search_button) {
440 navigationbar += "<option value=\"_httpquery_\"";
441 if (args["a"] == "q") {
442 navigationbar += " selected";
443 }
444 navigationbar += ">_labelSearch_</option>\n";
445 }
446
447 while (dochere != docend) {
448 text_t title = dochere->metadata["Title"].values[0];
449
450 navigationbar += "<option value=\"_httpdocument_&amp;cl=" + dochere->OID + "\"";
451 if (topparent == dochere->OID) {
452 navigationbar += " selected";
453 }
454 navigationbar += ">_navlinktitle_(" + title + ")</option>\n";
455 ++dochere;
456 }
457
458 navigationbar += "</select>\n";
459 navigationbar += "</form>\n";
460 }
461
462 disp.setmacro ("navigationbar", displayclass::defaultpackage, navigationbar);
463}
464
465// define all the macros which might be used by other actions
466// to produce pages.
467void documentaction::define_external_macros (displayclass &disp, cgiargsclass &args,
468 recptprotolistclass *protos, ostream &logout) {
469
470 // define_external_macros sets the following macros:
471
472 // _navigationbar_ this is the navigation bar containing the search button
473 // and any classification buttons - it goes at the top of
474 // most pages. for now we're assuming that there'll always
475 // be a search button - we should probably check that there
476 // is a query action before making this assumption
477
478 // _httpbrowseXXX_ the http macros for each classification (i.e. if there
479 // are Title and Creator classifications _httpbrowseTitle_
480 // and _httpbrowseCreator_ will be set
481
482 // _widthtspace_ the width of the spacers between buttons in navigation
483 // bar
484
485 // _httpdocument_ has '&f=1' added if displaying document inside a frame
486
487 // _gsdltop_ macro to replace _top targets with
488
489 // _httppagehome_ overridden home url if html collections have own homepage
490
491 // _usability_ macros for remote usability reporting: if
492 // _usabinterface_ "format Usability [multi|textonly|stepwise]" is in
493 // _usabilityscript_ collect.cfg
494
495 // _versionnnum_ greenstone version number (hard-coded)
496 // must have a valid collection server to continue
497
498 text_t &collection = args["c"];
499 if (collection.empty()) return;
500 recptproto *collectproto = protos->getrecptproto (collection, logout);
501 if (collectproto == NULL) return;
502
503 if (recpt == NULL) {
504 logout << "ERROR (documentaction::define_external_macros): This action does not contain\n"
505 << " information about any receptionists. The method set_receptionist was\n"
506 << " probably not called from the module which instantiated this action.\n";
507 return;
508 }
509
510 outconvertclass text_t2ascii;
511 comerror_t err;
512 InfoFiltersResponse_t filterinfo;
513 FilterResponse_t response;
514 text_tset metadata;
515
516 // get info on current collection and load up formatinfo
517 // I'd prefer not to do this here as we're getting
518 // collection info every time (and probably also getting
519 // it in other places some of the time) - One day I'll
520 // fix it ... maybe - Stefan.
521 ColInfoResponse_t cinfo;
522
523 collectproto->get_collectinfo (collection, cinfo, err, logout);
524 load_formatinfo (cinfo.format, args.getintarg("gt"));
525 // ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
526 // if (cinfo == NULL) {
527 // logout << "ERROR (documentaction::define_external_macros): get_collectinfo_ptr returned NULL\n";
528 // return;
529 // }
530 //load_formatinfo (cinfo->format, args.getintarg("gt"));
531
532 if (formatinfo.DocumentUseHTML) {
533
534 // frame stuff
535 if (args["fc"] == "1") {
536 text_t httpdocument;
537 disp.expandstring (displayclass::defaultpackage, "_httpdocument_", httpdocument);
538 httpdocument += "&amp;f=1";
539 disp.setmacro ("httpdocument", displayclass::defaultpackage, httpdocument);
540 disp.setmacro ("gsdltop", displayclass::defaultpackage, "documenttop");
541 formatinfo.DocumentText = "[Text]";
542 }
543 text_tmap::iterator it = cinfo.format.find ("homepage");
544 if (it != cinfo.format.end()) {
545 text_t httppagehome;
546 if (get_link (args, protos, (*it).second, httppagehome, logout))
547 disp.setmacro ("httppagehome", displayclass::defaultpackage, httppagehome);
548 }
549 }
550
551 // don't want navigation bar if page is 'detached'
552 if (!args.getintarg("x")) {
553
554 collectproto->get_filterinfo (collection, filterinfo, err, logout);
555 if (err == noError) {
556 // check that there's a browse filter
557 if (filterinfo.filterNames.find ("BrowseFilter") != filterinfo.filterNames.end()) {
558
559 metadata.insert ("Title");
560 bool getParents = false;
561 get_children ("", collection, args["l"], metadata, getParents, collectproto, response, logout);
562
563 bool has_search_button = true;
564 collectproto->is_searchable(collection, has_search_button, err, logout);
565 if (err != noError) has_search_button = false;
566
567 // calculate width of spacers and set _widthtspace_ macro
568 if (args.getintarg("v") == 0) set_spacemacro (disp, response, has_search_button);
569
570 // set _navigationbar_ macro
571 set_navbarmacros (disp, response, has_search_button, args, cinfo);
572
573 }
574 } else {
575 logout << text_t2ascii
576 << "Error (documentaction::define_external_macros()) in call to get_filterinfo() "
577 << get_comerror_string (err);
578 }
579 }
580
581 // send feedback button and pages
582 text_tmap::iterator usability = cinfo.format.find("Usability");
583 if(usability!=cinfo.format.end()){
584 disp.setmacro("usability",displayclass::defaultpackage,"_usablink_");
585 disp.setmacro("usabinterface",displayclass::defaultpackage,("_usab"+(*usability).second+"_"));
586 disp.setmacro("usabilityscript", displayclass::defaultpackage, "_usabshowscript_");
587 }
588
589 // version num
590 disp.setmacro("versionnum", displayclass::defaultpackage, GSDL_VERSION);
591
592}
593
594bool documentaction::get_link (cgiargsclass &args, recptprotolistclass *protos,
595 const text_t &inlink, text_t &outlink, ostream &logout) {
596
597 FilterResponse_t response;
598 text_tset metadata;
599 metadata.insert ("section");
600
601 // check current collection first
602 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
603
604 if (get_info (inlink, args["c"], args["l"], metadata, false, collectproto, response, logout)) {
605 if (!response.docInfo[0].metadata["section"].values[0].empty()) {
606#ifndef DOCHANDLE
607 outlink = "_httpdocument_&amp;d=" + response.docInfo[0].metadata["section"].values[0];
608#else
609 outlink = "_httpdocumenthandle_("+encodeForURL(args["c"])+","+response.docInfo[0].metadata["section"].values[0]+")";
610#endif
611
612 return true;
613 }
614 }
615
616 // check all the other enabled collections
617
618 if (args["ccs"] == "1" && !args["cc"].empty()) {
619 text_tarray collections;
620 splitchar (args["cc"].begin(), args["cc"].end(), ',', collections);
621
622 text_tarray::const_iterator col_here = collections.begin();
623 text_tarray::const_iterator col_end = collections.end();
624
625 while (col_here != col_end) {
626
627 // don't need to check current collection again
628 if (*col_here == args["c"]) {++col_here; continue;}
629
630 collectproto = protos->getrecptproto (*col_here, logout);
631
632 if (get_info (inlink, *col_here, args["l"], metadata, false, collectproto, response, logout)) {
633 if (!response.docInfo[0].metadata["section"].values[0].empty()) {
634#ifndef DOCHANDLE
635 outlink = "_httpdocument_&amp;c=" + *col_here + "&amp;d=" +
636 response.docInfo[0].metadata["section"].values[0];
637#else
638 outlink = "_httpdocumenthandle_("+*col_here+","+response.docInfo[0].metadata["section"].values[0]+")";
639#endif
640
641 return true;
642 }
643 }
644 ++col_here;
645 }
646 }
647 return false;
648}
649
650void documentaction::load_formatinfo (const text_tmap &colformat, int gt) {
651
652 formatinfo.clear();
653 text_tmap::const_iterator format_here = colformat.begin();
654 text_tmap::const_iterator format_end = colformat.end();
655
656 while (format_here != format_end) {
657 if (((*format_here).first == "DocumentImages") &&
658 ((*format_here).second == "true"))
659 formatinfo.DocumentImages = true;
660 else if (((*format_here).first == "DocumentTitles") &&
661 ((*format_here).second == "false"))
662 formatinfo.DocumentTitles = false;
663 else if ((*format_here).first == "DocumentHeading")
664 formatinfo.DocumentHeading = (*format_here).second;
665 else if (((*format_here).first == "DocumentContents") &&
666 ((*format_here).second == "false"))
667 formatinfo.DocumentContents = false;
668 else if (((*format_here).first == "DocumentArrowsBottom") &&
669 ((*format_here).second == "false"))
670 formatinfo.DocumentArrowsBottom = false;
671 else if (((*format_here).first == "DocumentArrowsTop") &&
672 ((*format_here).second == "true"))
673 formatinfo.DocumentArrowsTop = true;
674 else if ((*format_here).first == "DocumentButtons")
675 splitchar ((*format_here).second.begin(), (*format_here).second.end(),
676 '|', formatinfo.DocumentButtons);
677 else if ((*format_here).first == "DocumentText")
678 formatinfo.DocumentText = (*format_here).second;
679 else if ((*format_here).first == "RelatedDocuments")
680 formatinfo.RelatedDocuments = (*format_here).second;
681 else if (((*format_here).first == "DocumentUseHTML") &&
682 ((*format_here).second == "true"))
683 formatinfo.DocumentUseHTML = true;
684 else if (((*format_here).first == "AllowExtendedOptions") &&
685 ((*format_here).second == "true"))
686 formatinfo.AllowExtendedOptions = true;
687 else
688 formatinfo.formatstrings[(*format_here).first] = (*format_here).second;
689
690 ++format_here;
691 }
692
693 // never want arrows when text is expanded
694 if (gt) {
695 formatinfo.DocumentArrowsBottom = false;
696 formatinfo.DocumentArrowsTop = false;
697 }
698}
699
700
701// define all the macros which are related to pages generated
702// by this action. we also load up the formatinfo structure
703// here (it's used in do_action as well as here)
704void documentaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
705 recptprotolistclass *protos, ostream &logout) {
706
707 // define_internal_macros sets the following macros:
708
709 // _pagetitle_ the title to be displayed at the top of the browser window
710
711 // _imagethispage_ the title image to be displayed at top right of page
712
713 // _navarrowsbottom_ this may be overridden to "" when format option
714 // DocumentArrowsBottom is false
715
716 // _navarrowstop_ likewise for DocumentArrowsTop
717
718 // _httpprevarrow_ links to next and previous sections of document - used
719 // _httpnextarrow_ by DocumentArrowsBottom
720
721 // _header_ the header macro is overridden if we're not at a top level
722 // classification to remove the title block
723
724 // _thisOID_ the OID (directory) of the current document - this corresponds
725 // to the assocfilepath metadata element
726
727 // _documentheader_ Custom header info for the specified document
728 // must have a valid collection server to continue
729
730 // _allowusercomments_ Whether the User Comments area is to be shown for this doc or not
731
732 text_t &collection = args["c"];
733 if (collection.empty()) return;
734 recptproto *collectproto = protos->getrecptproto (collection, logout);
735 if (collectproto == NULL) return;
736
737 text_tset metadata;
738 FilterResponse_t response;
739 text_t &arg_d = args["d"];
740 text_t &arg_cl = args["cl"];
741
742 if (!formatinfo.DocumentArrowsBottom) {
743 disp.setmacro("navarrowsbottom", "document", "");
744 } else if (!formatinfo.DocumentArrowsBottom) {
745 disp.setmacro("navarrowstop", "document", "");
746 }
747
748 if (!arg_d.empty() && (formatinfo.DocumentArrowsBottom || formatinfo.DocumentArrowsTop)) {
749 // set _httpprevarrow_ and _httpnextarrow_
750 set_arrow_macros (args, collectproto, disp, logout);
751 }
752
753 metadata.insert ("Title");
754 metadata.insert ("gs.DocumentHeader");
755 metadata.insert ("DocumentHeader");
756
757 bool fulltoc = false;
758
759 if (args["cl"] != "search") {
760 // see if there's a FullTOC string
761 text_t cl_top, full_toc;
762 get_top (arg_cl, cl_top);
763 if (get_formatstring (cl_top, "FullTOC", formatinfo.formatstrings, full_toc))
764 if (full_toc == "true") fulltoc = true;
765 disp.setmacro("cltop", "document", cl_top);
766 }
767
768 if (!arg_d.empty() && !fulltoc) {
769 // we're at document level
770
771 metadata.insert ("assocfilepath");
772
773 comerror_t err;
774 OptionValue_tarray options;
775 // we need to do the query again for the z3950proto
776 if (collectproto->get_protocol_name(err)=="z3950proto") {
777 OptionValue_t opt;
778 opt.name="Term";opt.value=args["q"];options.push_back(opt);
779 opt.name="QueryType";
780 opt.value=(args.getintarg("t")) ? "ranked" : "boolean";
781 options.push_back(opt);
782 opt.name="Index";opt.value=args["h"];options.push_back(opt);
783 }
784
785 //do not display relation metadata
786 disp.setmacro ("relateddoc", "document", "");
787
788 // Whether the UserComments section is supposed to be displayed when a document is loaded or not
789 if (collectproto != NULL) {
790 ColInfoResponse_t *cinfo = NULL;
791
792 cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
793
794 text_tmap::const_iterator user_comments_it = cinfo->format.find ("AllowUserComments");
795 if ((user_comments_it != cinfo->format.end()) && ((*user_comments_it).second == "true")) {
796 disp.setmacro ("allowusercomments", "document", "1"); // document package
797 //disp.setmacro ("allowusercomments", displayclass::defaultpackage, "1"); // Global
798 }
799 }
800
801 //if preferences indicate relevant docs should be collected
802 //and there is no particular format specified then display
803 //this default format.
804 if(args["rd"] == "1" && formatinfo.RelatedDocuments.empty()){
805
806 text_t relation = g_EmptyText; //string for displaying relation metadata
807
808 //call function in formattools.cpp which will return the text of the
809 //related documents in a vertical list. This is the default format.
810
811 if (get_info (arg_d, collection, args["l"], metadata, options, false, collectproto, response, logout))
812 relation += get_related_docs(collection, collectproto, response.docInfo[0], logout);
813
814 //set macro to be the related document string
815
816 disp.setmacro ("relateddoc", "document", relation);
817 }
818
819
820 // get metadata for this document and it's parents
821 if (get_info (arg_d, collection, args["l"], metadata, options,
822 true, collectproto, response, logout)) {
823
824 disp.setmacro ("header", "document", "_textheader_");
825 text_tarray pagetitlearray;
826 if (!response.docInfo[0].metadata["Title"].values[0].empty())
827 pagetitlearray.push_back (response.docInfo[0].metadata["Title"].values[0]);
828
829 if (args["gt"] != "1") {
830 MetadataInfo_t *parenttitle = response.docInfo[0].metadata["Title"].parent;
831 while (parenttitle != NULL) {
832 if (!parenttitle->values[0].empty())
833 pagetitlearray.push_back (parenttitle->values[0]);
834 parenttitle = parenttitle->parent;
835 }
836 }
837 reverse (pagetitlearray.begin(), pagetitlearray.end());
838 text_t pagetitle;
839 joinchar (pagetitlearray, ": ", pagetitle);
840 // remove html tags from the title
841 text_t::iterator open_tag=pagetitle.begin();
842 while (open_tag < pagetitle.end()) {
843 if (*open_tag == '<') {
844 text_t::iterator close_tag=open_tag+1;
845 text_t::iterator donechar=pagetitle.end();
846 while (close_tag < donechar) {
847 if (*close_tag == '>')
848 break;
849 ++close_tag;
850 }
851 if (close_tag < donechar) // remove this html tag, replace with space
852 *close_tag=' ';
853 pagetitle.erase(open_tag, close_tag);
854 }
855 ++open_tag;
856 }
857 disp.setmacro ("pagetitle", "document", pagetitle);
858
859 // custom header info
860 text_t custom_header;
861 if (is_top (arg_d)) {
862 custom_header = response.docInfo[0].metadata["gs.DocumentHeader"].values[0];
863 if (custom_header.empty()) {
864 // try ex header
865 custom_header = response.docInfo[0].metadata["DocumentHeader"].values[0];
866 }
867 } else {
868 MetadataInfo_t *parentch = response.docInfo[0].metadata["gs.DocumentHeader"].parent;
869 while (parentch != NULL) {
870 custom_header = parentch->values[0];
871 parentch = parentch->parent;
872 }
873 if (custom_header.empty()) {
874 // try ex header
875 MetadataInfo_t *parentch = response.docInfo[0].metadata["DocumentHeader"].parent;
876 while (parentch != NULL) {
877 custom_header = parentch->values[0];
878 parentch = parentch->parent;
879 }
880 }
881 }
882 if (!custom_header.empty()) {
883 disp.setmacro("documentheader", "document", custom_header);
884 }
885
886 if (is_top (arg_d))
887 disp.setmacro ("thisOID", displayclass::defaultpackage, dm_safe(response.docInfo[0].metadata["assocfilepath"].values[0]));
888 else {
889 MetadataInfo_t *parentad = response.docInfo[0].metadata["assocfilepath"].parent;
890 text_t thisOID;
891 while (parentad != NULL) {
892 thisOID = parentad->values[0];
893 parentad = parentad->parent;
894 }
895 disp.setmacro ("thisOID", displayclass::defaultpackage, dm_safe(thisOID));
896 }
897 }
898 } else {
899 if (!arg_cl.empty()) {
900
901 // create the currentnodevalue macro - this is the value of the node
902 // in the hierarchy that is currently open.
903 if (get_info (arg_cl, collection, args["l"], metadata, false, collectproto, response, logout)) {
904 text_t &title = response.docInfo[0].metadata["Title"].values[0];
905 disp.setmacro ("currentnodevalue", "document", title);
906 }
907 // get metadata for top level classification
908 text_t classtop;
909 get_top (arg_cl, classtop);
910 metadata.insert ("childtype");
911 metadata.insert ("parameters");
912
913 if (get_info (classtop, collection, args["l"], metadata, false, collectproto, response, logout)) {
914
915 text_t &title = response.docInfo[0].metadata["Title"].values[0];
916 bool unknown = false;
917
918 // test if we have macros defined for this classification's
919 // metadata name - if not we'll just display the name
920 text_t tmp;
921 text_t macroname="_label" + title + "_";
922 disp.expandstring ("Global", macroname, tmp);
923 if (tmp == macroname) unknown = true; // it wasn't expanded
924
925 if (unknown) {
926 disp.setmacro ("pagetitle", "document", title);
927 } else {
928 disp.setmacro ("pagetitle", "document", macroname);
929 }
930 /* for ns4/image layout compatibility. when this is no longer
931 * needed, set imagethispage to _label+title+_ */
932 text_t titlemacroname="_titleimage" + title + "_";
933 disp.expandstring ("Global", titlemacroname, tmp);
934 if (tmp == titlemacroname) { /* _titleimage$META_ isn't defined */
935 if (!unknown) /* _label$META_ is defined */
936 disp.setmacro ("imagethispage", "document", macroname);
937 else
938 disp.setmacro ("imagethispage", "document", title);
939 } else { /* _titleimage$META_ is defined */
940 disp.setmacro ("imagethispage", "document", titlemacroname);
941 }
942
943 //if the document is not a document from a collection
944 //we must set the macro to be an empty string
945 disp.setmacro ("relateddoc", "document", "");
946
947 // Add macros specific to the Collage/Phind classifiers
948 text_t &childtype = response.docInfo[0].metadata["childtype"].values[0];
949 if (childtype == "Collage") {
950
951 text_t::iterator a = arg_cl.begin();
952 text_t::iterator b = arg_cl.end();
953
954 bool collage = true;
955 while (a != b) {
956 if (*a == 46) collage = false;
957 ++a;
958 }
959
960 if (collage) {
961 disp.setmacro ("collageclassifier", "document", "_collageapplet_");
962
963 // Next, macros that control the way the classifier is displayed
964 text_t parameters = response.docInfo[0].metadata["parameters"].values[0];
965
966 // extract key=value pairs and set as macros
967 text_t::iterator here = parameters.begin();
968 text_t::iterator end = parameters.end();
969 text_t key, value;
970
971 while (here != end) {
972 // get the next key and value pair
973 here = getdelimitstr (here, end, '=', key);
974 here = getdelimitstr (here, end, ';', value);
975
976 // store this key=value pair
977 if (!key.empty() && !value.empty()) {
978 disp.setmacro ("collage"+key, "document", value);
979 }
980 }
981
982
983 }
984 }
985
986 if (childtype == "Phind") {
987
988 // First, a macro to display the phind classifier
989 disp.setmacro ("phindclassifier", "document", "_phindapplet_");
990
991 // Next, macros that control the way the classifier is displayed
992 text_t parameters = response.docInfo[0].metadata["parameters"].values[0];
993
994 // extract key=value pairs and set as macros
995 text_t::iterator here = parameters.begin();
996 text_t::iterator end = parameters.end();
997 text_t key, value;
998
999 while (here != end) {
1000 // get the next key and value pair
1001 here = getdelimitstr (here, end, '=', key);
1002 here = getdelimitstr (here, end, ';', value);
1003
1004 // store this key=value pair
1005 if (!key.empty() && !value.empty()) {
1006 disp.setmacro (key, "document", value);
1007 }
1008 }
1009 } // end if (childtype == "Phind")
1010 }
1011 } // end if (!arg_cl.empty()) {
1012 }
1013}
1014
1015
1016bool documentaction::do_action(cgiargsclass &args, recptprotolistclass *protos,
1017 browsermapclass *browsers, displayclass &disp,
1018 outconvertclass &outconvert, ostream &textout,
1019 ostream &logout)
1020{
1021 if ((args["book"] == "flashxml") && (!args["d"].empty()))
1022 {
1023 return do_action_flashxml(args,protos,browsers,disp,outconvert,textout,logout);
1024 }
1025 else if ((args["book"] == "on") && (!args["d"].empty()))
1026 {
1027 return do_action_book(args,protos,browsers,disp,outconvert,textout,logout);
1028 }
1029 else
1030 {
1031 return do_action_html(args,protos,browsers,disp,outconvert,textout,logout);
1032 }
1033
1034}
1035
1036//displaying the normal display when bookswitch=0(html)
1037bool documentaction::do_action_html(cgiargsclass &args, recptprotolistclass *protos,
1038 browsermapclass *browsers, displayclass &disp,
1039 outconvertclass &outconvert, ostream &textout,
1040 ostream &logout)
1041{
1042 // must have a valid collection server
1043 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
1044 if (collectproto == NULL) {
1045 logout << "documentaction::do_action called with NULL collectproto\n";
1046 textout << outconvert << disp << "_document:header_\n"
1047 << "Error: Attempt to get document without setting collection\n"
1048 << "_document:footer_\n";
1049 } else {
1050
1051 text_t OID = args["d"];
1052 if (OID.empty()) OID = args["cl"];
1053 if (OID.empty()) {
1054 textout << outconvert << disp << "Document contains no data_document:footer_\n";
1055 return true;
1056 }
1057
1058
1059 if (formatinfo.DocumentUseHTML && !args["d"].empty()) {
1060
1061 if (args["f"] == "1") {
1062 textout << outconvert << disp
1063 << "<html><head></head>\n"
1064 << "<frameset rows=\"68,*\" noresize border=0>\n"
1065 << "<frame scrolling=no frameborder=0 src=\"_gwcgi_?_optsite_e=_compressedoptions_&a=p&p=nav\">\n"
1066#ifndef DOCHANDLE
1067 << "<frame name=\"documenttop\" frameborder=0 src=\"_gwcgi_?_optsite_e=_compressedoptions_&a=d&d="
1068 << encodeForURL(args["d"]) << "\">"
1069#else
1070 << "<frame name=\"documenttop\" frameborder=0 src=\"_httpdocumenthandle_("
1071 << encodeForURL(args["c"]) << "," << encodeForURL(args["d"]) << ")\">"
1072#endif
1073 << "<noframes>\n"
1074 << "<p>You must have a frame enabled browser to view this.</p>\n"
1075 << "</noframes>\n"
1076 << "</frameset>\n"
1077 << "</html>\n";
1078 } else {
1079 output_document (OID, args, collectproto, browsers, disp, outconvert, textout, logout);
1080 }
1081 return true;
1082 }
1083
1084
1085 textout << outconvert << disp << "_document:header_\n"
1086 << "_document:content_\n";
1087
1088 // output the table of contents
1089 browsetoolsclass b;
1090 b.output_toc(args, browsers, formatinfo, collectproto,
1091 disp, outconvert, textout, logout);
1092
1093 if (formatinfo.DocumentArrowsTop && !args["d"].empty()) {
1094 textout << outconvert << disp << "_document:navarrowstop_\n";
1095 }
1096
1097 //output the related documents (may be the empty string)
1098 //will not output the docs if a format string is specified
1099 textout << outconvert << disp << "_document:relateddoc_\n";
1100
1101 // output the document text
1102 if (!args["d"].empty()) {
1103 output_document (OID, args, collectproto, browsers, disp, outconvert, textout, logout);
1104 }
1105
1106 textout << outconvert << disp << "_document:footer_\n";
1107 }
1108 return true;
1109}
1110
1111//displaying the book display when bookswitch=on
1112bool documentaction::do_action_book(cgiargsclass &args, recptprotolistclass *protos,
1113 browsermapclass *browsers, displayclass &disp,
1114 outconvertclass &outconvert, ostream &textout,
1115 ostream &logout)
1116{
1117 // must have a valid collection server
1118 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
1119 if (collectproto == NULL)
1120 {
1121 logout << "documentaction::do_action called with NULL collectproto\n";
1122 textout << outconvert << disp << "_document:header_\n"
1123 << "Error: Attempt to get document without setting collection\n";
1124 }
1125 else
1126 {
1127 text_t OID = args["d"];
1128 if (OID.empty()) OID = args["cl"];
1129 if (OID.empty())
1130 {
1131 textout << outconvert << disp << "Document contains no data\n";
1132 return true;
1133 }
1134
1135 if (formatinfo.DocumentUseHTML && !args["d"].empty())
1136 {
1137 if (args["f"] == "1")
1138 {
1139 textout << outconvert << disp
1140 << "<html><head></head>\n"
1141 << "<frameset rows=\"68,*\" noresize border=0>\n"
1142 << "<frame scrolling=no frameborder=0 src=\"_gwcgi_?_optsite_e=_compressedoptions_&a=p&p=nav\">\n"
1143 #ifndef DOCHANDLE
1144 << "<frame name=\"documenttop\" frameborder=0 src=\"_gwcgi_?_optsite_e=_compressedoptions_&a=d&d="
1145 << encodeForURL(args["d"]) << "\">"
1146 #else
1147 << "<frame name=\"documenttop\" frameborder=0 src=\"_httpdocumenthandle_("
1148 << encodeForURL(args["c"]) << "," << encodeForURL(args["d"]) << ")\">"
1149 #endif
1150 << "<noframes>\n"
1151 << "<p>You must have a frame enabled browser to view this.</p>\n"
1152 << "</noframes>\n"
1153 << "</frameset>\n"
1154 << "</html>\n";
1155 }
1156 else
1157 {
1158 output_document (OID, args, collectproto, browsers, disp, outconvert, textout, logout);
1159 }
1160
1161 return true;
1162 }
1163
1164
1165 //the header bit and the navigation button
1166 textout << outconvert << disp << "_document:header_\n" << "_document:content_\n";
1167
1168 //display the book
1169 textout << outconvert << disp << "_document:flashbook_\n";
1170
1171 //the footer bit without the document arrow
1172 textout << outconvert << disp << "</div> <!-- id=document -->\n";
1173 textout << outconvert << disp << "_endspacer__htmlfooter_\n";
1174 }
1175
1176 return true;
1177}
1178
1179//Displaying the xml when bookswitch=flashxml
1180bool documentaction::do_action_flashxml(cgiargsclass &args, recptprotolistclass *protos,
1181 browsermapclass *browsers, displayclass &disp,
1182 outconvertclass &outconvert, ostream &textout,
1183 ostream &logout)
1184{
1185 // must have a valid collection server
1186 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
1187 if (collectproto == NULL)
1188 {
1189 logout << "documentaction::do_action called with NULL collectproto\n";
1190 textout << outconvert << disp
1191 << "<Message>\n"
1192 << " Error: Attempt to get document without setting collection\n"
1193 << "</Message>\n";
1194 }
1195 else
1196 {
1197 text_t OID = args["d"];
1198 if (OID.empty()) OID = args["cl"];
1199 if (OID.empty())
1200 {
1201 textout << outconvert << disp
1202 << "<Message>\n"
1203 << " Document contains no data\n"
1204 << "</Message>\n";
1205 return true;
1206 }
1207
1208 if (formatinfo.DocumentUseHTML && !args["d"].empty())
1209 {
1210 if (args["f"] == "1")
1211 {
1212 textout << outconvert << disp
1213 << "<Message>\n"
1214 << " Using frames makes no sense for XML output\n"
1215 << "</Message>\n";
1216 }
1217 else
1218 {
1219 output_document_flashxml (OID, args, collectproto, browsers, disp, outconvert, textout, logout);
1220 }
1221
1222 return true;
1223 }
1224
1225 // output the document text
1226 if (!args["d"].empty())
1227 {
1228 output_document_flashxml (OID, args, collectproto, browsers, disp, outconvert, textout, logout);
1229 }
1230 }
1231
1232 return true;
1233}
1234
1235
1236
1237void documentaction::output_text (ResultDocInfo_t &docinfo, format_t *formatlistptr,
1238 const TermInfo_tarray &terminfo, const text_t &OID,
1239 bool highlight, int hastxt, int wanttext,
1240 text_t &collection, recptproto *collectproto,
1241 browsermapclass *browsers, displayclass &disp,
1242 outconvertclass &outconvert, ostream &textout,
1243 ostream &logout, cgiargsclass &args) {
1244
1245 DocumentRequest_t docrequest;
1246 DocumentResponse_t docresponse;
1247 comerror_t err;
1248 if (hastxt == 1) {
1249
1250 if (wanttext) {
1251 // get the text
1252 docrequest.OID = OID;
1253 collectproto->get_document (collection, docrequest, docresponse, err, logout);
1254
1255 // cut down on overhead by not using formattools if we only want the text
1256 // (wanttext will equal 2 if we want text and other stuff too)
1257 if (wanttext == 1)
1258 if (highlight) {
1259 highlighttext(docresponse.doc, args, terminfo, disp, outconvert, textout);
1260 } else {
1261 textout << outconvert << disp << docresponse.doc;
1262 }
1263 }
1264
1265 if (wanttext != 1) {
1266 text_tmap options;
1267 options["text"] = docresponse.doc;
1268
1269 browsetoolsclass b;
1270 options["assocfilepath"] = b.get_assocfile_path();
1271 if (formatinfo.AllowExtendedOptions) {
1272 b.load_extended_options(options, args, browsers, formatinfo,
1273 collectproto, disp, outconvert, logout);
1274 }
1275
1276 text_t doctext
1277 = get_formatted_string (collection, collectproto, docinfo, disp,
1278 formatlistptr, options, logout);
1279
1280 if (highlight) {
1281 highlighttext(doctext, args, terminfo, disp, outconvert, textout);
1282 } else {
1283 textout << outconvert << disp << doctext;
1284 }
1285 }
1286 }
1287}
1288
1289
1290void documentaction::output_document (const text_t &OID, cgiargsclass &args,
1291 recptproto *collectproto, browsermapclass *browsers,
1292 displayclass &disp, outconvertclass &outconvert,
1293 ostream &textout, ostream &logout) {
1294 FilterResponse_t inforesponse;
1295 FilterResponse_t queryresponse;
1296 text_tset metadata;
1297 bool getParents = false;
1298 bool highlight = false;
1299 int wanttext = 0;
1300 int arg_gt = args.getintarg("gt");
1301 text_t &collection = args["c"];
1302
1303 // if we have a query string and highlighting is turned on we need
1304 // to redo the query to get the terms for highlighting
1305
1306 if (!args["q"].empty() && args.getintarg("hl")) {
1307
1308 ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
1309 bool segment = false;
1310 if (cinfo != NULL) {
1311 segment = cinfo->isSegmented;
1312 }
1313 FilterRequest_t request;
1314 comerror_t err;
1315 request.filterResultOptions = FRmatchTerms;
1316 text_t formattedstring = args["q"];
1317 format_querystring (formattedstring, args.getintarg("b"), segment);
1318 set_fulltext_queryfilter_options (request, formattedstring, args);
1319 args["q"] = formattedstring; // need to set this here for phrase
1320 // highlighting, where we look at the querystring
1321 collectproto->filter (args["c"], request, queryresponse, err, logout);
1322 if (err != noError) {
1323 outconvertclass text_t2ascii;
1324 logout << text_t2ascii
1325 << "documentaction::output_document: call to QueryFilter failed "
1326 << "for " << args["c"] << " collection (" << get_comerror_string (err) << ")\n";
1327 highlight = false;
1328 } else {
1329 highlight = true;
1330 }
1331 }
1332
1333 format_t *formatlistptr = new format_t();
1334 parse_formatstring (formatinfo.DocumentText, formatlistptr, metadata, getParents);
1335
1336 metadata.insert ("hastxt");
1337 metadata.insert ("haschildren");
1338
1339 if (formatinfo.DocumentText == "[Text]")
1340 wanttext = 1;
1341 else {
1342 char *docformat = formatinfo.DocumentText.getcstr();
1343 if (strstr (docformat, "[Text]") != NULL)
1344 wanttext = 2;
1345 delete []docformat;
1346 }
1347
1348 textout << outconvert << "<div class=\"documenttext\">\n";
1349
1350 if (get_info (OID, collection, args["l"], metadata, getParents, collectproto, inforesponse, logout)) {
1351 int hastxt = inforesponse.docInfo[0].metadata["hastxt"].values[0].getint();
1352 int haschildren = inforesponse.docInfo[0].metadata["haschildren"].values[0].getint();
1353
1354 if (arg_gt == 0) {
1355 output_text (inforesponse.docInfo[0], formatlistptr, queryresponse.termInfo,
1356 OID, highlight, hastxt, wanttext, collection, collectproto,
1357 browsers, disp, outconvert, textout, logout, args);
1358
1359 } else {
1360
1361 ResultDocInfo_t thisdocinfo = inforesponse.docInfo[0];
1362
1363 // text is to be expanded
1364 text_t exOID = OID;
1365 if (haschildren != 1) exOID = get_parent (OID);
1366 if (exOID.empty()) exOID = OID;
1367
1368 // if we're not in a document (i.e. we're in a top level classification)
1369 // we need to pass "is_classify = true" to get_contents so that it
1370 // doesn't recurse all the way through each document in the classification
1371 bool is_classify = false;
1372 if (args["d"].empty()) is_classify = true;
1373
1374 get_contents (exOID, is_classify, metadata, collection, args["l"],
1375 collectproto, inforesponse, logout);
1376
1377 ResultDocInfo_tarray::iterator sechere = inforesponse.docInfo.begin();
1378 ResultDocInfo_tarray::iterator secend = inforesponse.docInfo.end();
1379
1380 if (arg_gt == 1) {
1381 // check if there are more than 10 sections containing text to be expanded -
1382 // if there are output warning message - this isn't a great way to do this
1383 // since the sections may be very large or very small - one day I'll fix it
1384 // -- Stefan.
1385 int seccount = 0;
1386 while (sechere != secend) {
1387 int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
1388 if (shastxt == 1) ++seccount;
1389 if (seccount > 10) break;
1390 ++sechere;
1391 }
1392 if (seccount > 10) {
1393 // more than 10 sections so output warning message and text
1394 // for current section only
1395 textout << outconvert << disp << "<div class=\"warning\">_document:textltwarning_</div>\n";
1396
1397 output_text (thisdocinfo, formatlistptr, queryresponse.termInfo,
1398 OID, highlight, hastxt, wanttext, collection,
1399 collectproto, browsers, disp, outconvert, textout, logout, args);
1400
1401 }
1402 else arg_gt = 2;
1403 }
1404
1405 if (arg_gt == 2) {
1406 // get the text for each section
1407 sechere = inforesponse.docInfo.begin();
1408 int count = 0;
1409 while (sechere != secend) {
1410 textout << outconvert << disp << "\n<p><a name=\"" << (*sechere).OID << "\"></a>\n";
1411
1412 int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
1413
1414
1415 output_text (*sechere, formatlistptr, queryresponse.termInfo,
1416 (*sechere).OID, highlight, shastxt, wanttext, collection,
1417 collectproto, browsers, disp, outconvert, textout, logout, args);
1418
1419 ++count;
1420 ++sechere;
1421 }
1422 }
1423 }
1424 }
1425 textout << outconvert << "</div>\n";
1426 delete formatlistptr;
1427}
1428
1429void documentaction::output_document_flashxml(const text_t &OID, cgiargsclass &args,
1430 recptproto *collectproto, browsermapclass *browsermap,
1431 displayclass &disp, outconvertclass &outconvert,
1432 ostream &textout, ostream &logout) {
1433 //if this is not at the document level --> do Nothing!!
1434 if (args["d"].empty())
1435 return;
1436
1437 //if we have a query string and highlighting is turned on we need
1438 //to redo the query to get the terms for highlighting
1439 FilterResponse_t queryresponse;
1440 bool highlight = false;
1441 if (!args["q"].empty() && args.getintarg("hl"))
1442 {
1443 text_t &collection = args["c"];
1444 ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
1445 bool segment = false;
1446 if (cinfo != NULL)
1447 {
1448 segment = cinfo->isSegmented;
1449 }
1450 FilterRequest_t request;
1451 comerror_t err;
1452 request.filterResultOptions = FRmatchTerms;
1453 text_t formattedstring = args["q"];
1454 format_querystring (formattedstring, args.getintarg("b"), segment);
1455 set_fulltext_queryfilter_options (request, formattedstring, args);
1456 args["q"] = formattedstring; //need to set this here for phrase
1457 //highlighting, where we look at the querystring
1458 collectproto->filter (args["c"], request, queryresponse, err, logout);
1459 if (err != noError)
1460 {
1461 outconvertclass text_t2ascii;
1462 logout << text_t2ascii
1463 << "documentaction::output_document: call to QueryFilter failed "
1464 << "for " << args["c"] << " collection (" << get_comerror_string (err) << ")\n";
1465 highlight = false;
1466 }
1467 else
1468 {
1469 highlight = true;
1470 }
1471 }
1472
1473 FilterResponse_t response;
1474 bool getParents = false;
1475 text_tset metadata;
1476 text_t classifytype, classification, formatstring;
1477
1478 //metadata elements needed by recurse_contents
1479 metadata.insert ("Title");
1480 metadata.insert ("gs.allowPrinting");
1481 metadata.insert ("haschildren");
1482
1483 //protocol call
1484 if (!get_info (OID, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
1485 return;
1486
1487 recurse_contents (response.docInfo[0], args, metadata,
1488 getParents, collectproto, disp, outconvert, textout, logout, highlight, queryresponse.termInfo);
1489}
1490
1491void documentaction::recurse_contents(ResultDocInfo_t &section, cgiargsclass &args,
1492 text_tset &metadata, bool &getParents,
1493 recptproto *collectproto, displayclass &disp,
1494 outconvertclass &outconvert, ostream &textout, ostream &logout,
1495 bool highlight, const TermInfo_tarray &terminfo)
1496{
1497 text_t formatstring;
1498
1499 bool is_classify = false;
1500
1501 //output this section
1502 text_t classification = "Document";
1503
1504 textout << outconvert << disp << "<Section>\n";
1505
1506 //get the title
1507 textout << outconvert << disp << "<Description>\n";
1508
1509 textout << outconvert << disp << " <Metadata name=\"Title\">";
1510 text_t t_title = section.metadata["Title"].values[0];
1511
1512 //if it is highlighted
1513 /*if (highlight == true)
1514 {
1515 highlighttext(t_title, args, terminfo, disp, outconvert, textout);
1516 }
1517 else
1518 {*/
1519 textout << outconvert << disp << t_title;
1520 //}
1521
1522 textout << outconvert << disp << "</Metadata>\n";
1523
1524 // if top-level document section, add in allowPrint metadata
1525 if (is_top(section.OID)) {
1526 textout << outconvert << disp << " <Metadata name=\"allowPrint\">";
1527 text_t t_allowprint = "true";
1528
1529 if (section.metadata["gs.allowPrinting"].values.size()>0) {
1530 text_t opt_allowprint = section.metadata["gs.allowPrinting"].values[0];
1531 if (!opt_allowprint.empty()) {
1532 t_allowprint = opt_allowprint;
1533 }
1534 }
1535
1536 textout << outconvert << disp << t_allowprint;
1537 textout << outconvert << disp << "</Metadata>\n";
1538 }
1539
1540 textout << outconvert << disp << "</Description>\n";
1541
1542 //get the text
1543 DocumentRequest_t docrequest;
1544 DocumentResponse_t docresponse;
1545 comerror_t err;
1546 docrequest.OID = section.OID;
1547 text_t &collection = args["c"];
1548 collectproto->get_document(collection, docrequest, docresponse, err, logout);
1549 //if it is highlighted
1550 if (highlight == true)
1551 {
1552 highlighttext(docresponse.doc, args, terminfo, disp, outconvert, textout);
1553 }
1554 else
1555 {
1556 textout << outconvert << disp << docresponse.doc;
1557 }
1558 textout << outconvert << disp << "\n";
1559
1560 int haschildren = section.metadata["haschildren"].values[0].getint();
1561
1562 // recurse through children
1563 if (haschildren == 1)
1564 {
1565 FilterResponse_t tmp;
1566 get_children (section.OID, args["c"], args["l"], metadata, getParents, collectproto, tmp, logout);
1567 ResultDocInfo_tarray::iterator thisdoc = tmp.docInfo.begin();
1568 ResultDocInfo_tarray::iterator lastdoc = tmp.docInfo.end();
1569
1570 while (thisdoc != lastdoc)
1571 {
1572 recurse_contents (*thisdoc, args, metadata, getParents, collectproto, disp, outconvert, textout, logout, highlight, terminfo);
1573 ++thisdoc;
1574 }
1575 }
1576
1577 textout << outconvert << disp << "</Section>\n";
1578}
1579
1580void documentaction::set_arrow_macros (cgiargsclass &args, recptproto *collectproto,
1581 displayclass &disp, ostream &logout) {
1582
1583 text_tset metadata;
1584 FilterResponse_t response;
1585 FilterResponse_t presponse;
1586
1587 int haschildren = 0;
1588 text_tarray next_siblings;
1589 text_t previous_sibling;
1590 text_t &arg_d = args["d"];
1591
1592 // get info on current section
1593 metadata.insert("haschildren");
1594 if (!get_info(arg_d, args["c"], args["l"], metadata, false, collectproto, response, logout)) {
1595 logout << "error 1 in documentaction::set_arrow_macros\n";
1596 return;
1597 }
1598 haschildren = response.docInfo[0].metadata["haschildren"].values[0].getint();
1599
1600 // get OIDs of next and previous siblings of current section and
1601 // all it's parents
1602 int parentcount = countchar(arg_d.begin(), arg_d.end(), '.');
1603 text_t thisoid = arg_d;
1604 while (parentcount > 0) {
1605 get_children (get_parent(thisoid), args["c"], args["l"], metadata, false,
1606 collectproto, response, logout);
1607 ResultDocInfo_tarray::iterator this_sibling = response.docInfo.begin();
1608 ResultDocInfo_tarray::iterator last_sibling = response.docInfo.end();
1609 bool first = true;
1610 while (this_sibling != last_sibling) {
1611 if ((*this_sibling).OID == thisoid) {
1612 if (!first && next_siblings.empty()) {
1613 previous_sibling = (*(this_sibling-1)).OID;
1614 int section_has_children = (*(this_sibling-1)).metadata["haschildren"].values[0].getint();
1615 // if previous sibling has children we need to recurse
1616 // down to the last descendant
1617 while (section_has_children) {
1618 get_children (previous_sibling, args["c"], args["l"], metadata, false,
1619 collectproto, presponse, logout);
1620 if (!presponse.docInfo.empty()) {
1621 ResultDocInfo_tarray::iterator it = presponse.docInfo.end() - 1;
1622 previous_sibling = (*it).OID;
1623 section_has_children = (*it).metadata["haschildren"].values[0].getint();
1624 } else {
1625 section_has_children = 0; // this should never happen
1626 }
1627 }
1628 }
1629
1630 if ((this_sibling+1) != last_sibling) {
1631 next_siblings.push_back((*(this_sibling+1)).OID);
1632 } else {
1633 next_siblings.push_back("");
1634 }
1635 break;
1636 }
1637 ++this_sibling;
1638 first = false;
1639 }
1640 thisoid = get_parent(thisoid);
1641 --parentcount;
1642 }
1643
1644 // work out values for next link
1645 if (haschildren) {
1646#ifndef DOCHANLE
1647 disp.setmacro ("httpnextarrow", "document", "_httpdocument_&amp;cl=" + encodeForURL(args["cl"]) +
1648 "&amp;d=" + encodeForURL(arg_d) + ".fc");
1649#else
1650 disp.setmacro ("httpnextarrow", "document", "_httpdocumenthandle_("+encodeForURL(args["c"])+","+encodeForURL(arg_d) + ".fc)";
1651
1652#endif
1653
1654 } else {
1655 text_tarray::const_iterator h = next_siblings.begin();
1656 text_tarray::const_iterator e = next_siblings.end();
1657 while (h != e) {
1658 if (!(*h).empty()) {
1659#ifndef DOCHANLE
1660 disp.setmacro ("httpnextarrow", "document", "_httpdocument_&amp;cl=" + encodeForURL(args["cl"]) +
1661 "&amp;d=" + *h);
1662#else
1663 disp.setmacro ("httpnextarrow", "document", "_httpdocumenthandle_("+encodeForURL(args["c"])+","+*h+")";
1664
1665#endif
1666
1667 break;
1668 }
1669 ++h;
1670 }
1671 }
1672
1673 // work out value for previous link
1674 if (!previous_sibling.empty()) {
1675#ifndef DOCHANDLE
1676 disp.setmacro ("httpprevarrow", "document", "_httpdocument_&amp;cl=" + encodeForURL(args["cl"]) +
1677 "&amp;d=" + previous_sibling);
1678#else
1679 disp.setmacro ("httpprevarrow", "document", "_httpdocumenthandle_("+encodeForURL(args["c"])+","+ previous_sibling+")");
1680
1681#endif
1682
1683 } else {
1684 if (countchar(arg_d.begin(), arg_d.end(), '.')) {
1685#ifndef DOCHANDLE
1686 disp.setmacro ("httpprevarrow", "document", "_httpdocument_&amp;cl=" + encodeForURL(args["cl"]) +
1687 "&amp;d=" + get_parent(arg_d));
1688#else
1689 disp.setmacro ("httpprevarrow", "document", "_httpdocumenthandle_("+encodeForURL(args["c"])+","+get_parent(arg_d)+")");
1690
1691#endif
1692
1693 }
1694 }
1695}
Note: See TracBrowser for help on using the repository browser.