source: trunk/gsdl/src/recpt/documentaction.cpp@ 1649

Last change on this file since 1649 was 1610, checked in by paynter, 24 years ago

Changed the formatstring parser in formattools so that an {If} macro (which
has the form {If}{decision,then,else}) can branch on any text, not just on
metadata. This means you can use extra cgi arguments and macros like
_cgiargmode_ to display documents in different modes and switch between
them. To accomplish all this, the formattools class needed to be able to
evaluate macros (through displayclass), so the other files have been
changed to pass in a displayclass object.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 31.1 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#include "documentaction.h"
28#include "browsetools.h"
29#include "OIDtools.h"
30#include "querytools.h"
31#include "unitool.h"
32#include "gsdltools.h"
33
34documentaction::documentaction () {
35 recpt = NULL;
36
37
38 // this action uses cgi variables "a", "d", "cl",
39 // "x", "gc", "gt", "gp", and "hl"
40 cgiarginfo arg_ainfo;
41 arg_ainfo.shortname = "a";
42 arg_ainfo.longname = "action";
43 arg_ainfo.multiplechar = true;
44 arg_ainfo.defaultstatus = cgiarginfo::weak;
45 arg_ainfo.argdefault = "p";
46 arg_ainfo.savedarginfo = cgiarginfo::must;
47 argsinfo.addarginfo (NULL, arg_ainfo);
48
49 arg_ainfo.shortname = "d";
50 arg_ainfo.longname = "document OID";
51 arg_ainfo.multiplechar = true;
52 arg_ainfo.defaultstatus = cgiarginfo::none;
53 arg_ainfo.argdefault = "";
54 arg_ainfo.savedarginfo = cgiarginfo::can;
55 argsinfo.addarginfo (NULL, arg_ainfo);
56
57 // whether or not a document should be retrieved from the
58 // library or the Web.
59 arg_ainfo.shortname = "il";
60 arg_ainfo.longname = "internal link preference";
61 arg_ainfo.multiplechar = false;
62 arg_ainfo.defaultstatus = cgiarginfo::weak;
63 arg_ainfo.argdefault = "l";
64 arg_ainfo.savedarginfo = cgiarginfo::must;
65 argsinfo.addarginfo (NULL, arg_ainfo);
66
67 arg_ainfo.shortname = "cl";
68 arg_ainfo.longname = "classification OID";
69 arg_ainfo.multiplechar = true;
70 arg_ainfo.defaultstatus = cgiarginfo::none;
71 arg_ainfo.argdefault = "";
72 arg_ainfo.savedarginfo = cgiarginfo::can;
73 argsinfo.addarginfo (NULL, arg_ainfo);
74
75 // in this action "gc" controls the expand/contract
76 // contents function
77 arg_ainfo.shortname = "gc";
78 arg_ainfo.longname = "expand contents";
79 arg_ainfo.multiplechar = false;
80 arg_ainfo.defaultstatus = cgiarginfo::weak;
81 arg_ainfo.argdefault = "0";
82 arg_ainfo.savedarginfo = cgiarginfo::can;
83 argsinfo.addarginfo (NULL, arg_ainfo);
84
85 // in this action "gt" controls the expand/contract
86 // text function 0 = not expanded, 1 = expand unless
87 // there are more than 10 sections containing text,
88 // 2 = expand all
89 arg_ainfo.shortname = "gt";
90 arg_ainfo.longname = "expand text";
91 arg_ainfo.multiplechar = false;
92 arg_ainfo.defaultstatus = cgiarginfo::weak;
93 arg_ainfo.argdefault = "0";
94 arg_ainfo.savedarginfo = cgiarginfo::can;
95 argsinfo.addarginfo (NULL, arg_ainfo);
96
97 // in this action "gp" is the "go to page" control
98 // used by the Book type of toc
99 arg_ainfo.shortname = "gp";
100 arg_ainfo.longname = "go to page";
101 arg_ainfo.multiplechar = true;
102 arg_ainfo.defaultstatus = cgiarginfo::none;
103 arg_ainfo.argdefault = "";
104 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
105 argsinfo.addarginfo (NULL, arg_ainfo);
106
107 // in this action "hl" is the "highlighting on/
108 // highlighting off control
109 arg_ainfo.shortname = "hl";
110 arg_ainfo.longname = "highlighting on/off";
111 arg_ainfo.multiplechar = false;
112 arg_ainfo.defaultstatus = cgiarginfo::weak;
113 arg_ainfo.argdefault = "1";
114 arg_ainfo.savedarginfo = cgiarginfo::must;
115 argsinfo.addarginfo (NULL, arg_ainfo);
116
117 // "x" is 0 normally or 1 if page
118 // has been "detached"
119 arg_ainfo.shortname = "x";
120 arg_ainfo.longname = "detached page";
121 arg_ainfo.multiplechar = false;
122 arg_ainfo.defaultstatus = cgiarginfo::weak;
123 arg_ainfo.argdefault = "0";
124 arg_ainfo.savedarginfo = cgiarginfo::must;
125 argsinfo.addarginfo (NULL, arg_ainfo);
126
127 // f arg is set to 1 if document is to
128 // be displayed in a frame
129 arg_ainfo.shortname = "f";
130 arg_ainfo.longname = "frame";
131 arg_ainfo.multiplechar = false;
132 arg_ainfo.defaultstatus = cgiarginfo::weak;
133 arg_ainfo.argdefault = "0";
134 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
135 argsinfo.addarginfo (NULL, arg_ainfo);
136
137 // fc arg is "1" if search bar is to be included (i.e. if "fc" == 1
138 // the httpdocument macro will include "&f=1"
139 arg_ainfo.shortname = "fc";
140 arg_ainfo.longname = "include search bar";
141 arg_ainfo.multiplechar = false;
142 arg_ainfo.defaultstatus = cgiarginfo::weak;
143 arg_ainfo.argdefault = "1";
144 arg_ainfo.savedarginfo = cgiarginfo::must;
145 argsinfo.addarginfo (NULL, arg_ainfo);
146}
147
148documentaction::~documentaction () {
149}
150
151bool documentaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
152 ostream &logout) {
153
154 // check gc argument
155 int arg_gc = args.getintarg("gc");
156 if (arg_gc != 0 && arg_gc != 1) {
157 logout << "Warning: \"gc\" argument out of range (" << arg_gc << ")\n";
158 cgiarginfo *gcinfo = argsinfo.getarginfo ("gc");
159 if (gcinfo != NULL) args["gc"] = gcinfo->argdefault;
160 }
161
162 // check gt argument (may be either 0, 1 or 2)
163 int arg_gt = args.getintarg("gt");
164 if (arg_gt != 0 && arg_gt != 1 && arg_gt != 2) {
165 logout << "Warning: \"gt\" argument out of range (" << arg_gt << ")\n";
166 cgiarginfo *gtinfo = argsinfo.getarginfo ("gt");
167 if (gtinfo != NULL) args["gt"] = gtinfo->argdefault;
168 }
169
170 // check hl argument
171 int arg_hl = args.getintarg("hl");
172 if (arg_hl != 0 && arg_hl != 1) {
173 logout << "Warning: \"hl\" argument out of range (" << arg_hl << ")\n";
174 cgiarginfo *hlinfo = argsinfo.getarginfo ("hl");
175 if (hlinfo != NULL) args["hl"] = hlinfo->argdefault;
176 }
177
178 // check x argument
179 int arg_x = args.getintarg("x");
180 if (arg_x != 0 && arg_x != 1) {
181 logout << "Warning: \"x\" argument out of range (" << arg_x << ")\n";
182 cgiarginfo *xinfo = argsinfo.getarginfo ("x");
183 if (xinfo != NULL) args["x"] = xinfo->argdefault;
184 }
185
186 return true;
187}
188
189void documentaction::get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
190 response_t &response,text_t &response_data,
191 ostream &logout) {
192
193 if ((args["il"] == "w") && (!args["d"].empty())) {
194
195 recptproto* collectproto = protos->getrecptproto (args["c"], logout);
196 if (collectproto != NULL) {
197
198 text_tset metadata;
199 FilterResponse_t filt_response;
200 text_t top;
201
202 metadata.insert ("URL");
203
204 // get metadata for parent document
205 get_top (args["d"], top);
206 if (get_info (top, args["c"], metadata, false, collectproto, filt_response, logout)) {
207 text_t url = filt_response.docInfo[0].metadata["URL"].values[0];
208
209 response = location;
210 response_data = url;
211 return;
212 } else {
213 // error, no URL
214 logout << "Error: documentaction::get_cgihead_info failed on get_info" << endl;
215 }
216 }
217 }
218 response = content;
219 response_data = "text/html";
220}
221
222// set_widthtspace calculates how wide the spaces in the nav bar should
223// be and sets the appropriate macro
224void documentaction::set_spacemacro (displayclass &disp, FilterResponse_t &response) {
225
226 text_t width;
227 int twidth, swidth, iwidth = 0;
228
229 int numc = response.docInfo.size();
230 ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
231 ResultDocInfo_tarray::iterator docend = response.docInfo.end();
232
233 disp.expandstring ("Global", "_pagewidth_", width);
234 twidth = width.getint();
235
236 disp.expandstring ("query", "_searchwidth_", width);
237 iwidth += width.getint();
238
239
240
241 while (dochere != docend) {
242 const text_t &title = (*dochere).metadata["Title"].values[0];
243
244 disp.expandstring ("document", "_" + title + "width_", width);
245 if (width == ("_" + title + "width_"))
246 disp.expandstring ("document", "_defaultwidth_", width);
247 iwidth += width.getint();
248 dochere ++;
249 }
250 if ((twidth - iwidth) < numc) swidth = 2;
251 else {
252 swidth = twidth - iwidth;
253 if (numc > 0) swidth = swidth / numc;
254 }
255 disp.setmacro ("widthtspace", "Global", swidth);
256}
257
258// set_navbarmacros sets _navigationbar_ and _httpbrowseXXX_ macros
259// reponse contains 1 metadata field (Title)
260void documentaction::set_navbarmacros (displayclass &disp, FilterResponse_t &response,
261 cgiargsclass &args) {
262
263 text_t topparent;
264 text_t &arg_d = args["d"];
265 text_t navigationbar = "<!-- Navigation Bar -->\n";
266
267 get_top (args["cl"], topparent);
268 int numc = response.docInfo.size();
269 ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
270 ResultDocInfo_tarray::iterator docend = response.docInfo.end();
271
272 navigationbar += "<nobr>\n";
273 if (args["a"] == "q") {
274 navigationbar += "_icontabsearchgreen_";
275 } else {
276 navigationbar += "_imagesearch_";
277 }
278
279
280 if (numc == 0) navigationbar += "_imagespacer_";
281
282 while (dochere != docend) {
283 text_t title = (*dochere).metadata["Title"].values[0];
284
285 bool unknown = false;
286
287 // test the _XXXwidth_ macro to see if image macros are
288 // defined for this type of classification - if not we'll
289 // just display the text
290 text_t tmpwidth;
291 disp.expandstring ("document", "_" + title + "width_", tmpwidth);
292 if (tmpwidth == ("_" + title + "width_")) unknown = true;
293
294 // if we're inside a document all the classification buttons should be enabled
295 if (arg_d.empty() && ((*dochere).OID == topparent)) {
296 if (unknown) navigationbar += "_imagespacer_&nbsp;" + title + "&nbsp;";
297 else navigationbar += "_imagespacer__icontab" + title + "green_";
298 } else {
299
300 // set the _httpbrowseXXX_ macro for this classification
301 if (unknown) navigationbar += "_imagespacer_&nbsp;<a href=\"_httpdocument_&cl=" +
302 (*dochere).OID + "\">" + title + "</a>&nbsp;";
303 else {
304 navigationbar += "_imagespacer__image" + title + "_";
305 disp.setmacro ("httpbrowse" + title, "Global", "_httpdocument_&cl=" + (*dochere).OID);
306 }
307 }
308 dochere ++;
309 }
310 navigationbar += "\n</nobr>\n";
311 navigationbar += "<!-- End of Navigation Bar -->\n";
312 disp.setmacro ("navigationbar", "Global", navigationbar);
313}
314
315// define all the macros which might be used by other actions
316// to produce pages.
317void documentaction::define_external_macros (displayclass &disp, cgiargsclass &args,
318 recptprotolistclass *protos, ostream &logout) {
319
320 // define_external_macros sets the following macros:
321
322 // _navigationbar_ this is the navigation bar containing the search button
323 // and any classification buttons - it goes at the top of
324 // most pages. for now we're assuming that there'll always
325 // be a search button - we should probably check that there
326 // is a query action before making this assumption
327
328 // _httpbrowseXXX_ the http macros for each classification (i.e. if there
329 // are Title and Creator classifications _httpbrowseTitle_
330 // and _httpbrowseCreator_ will be set
331
332 // _widthtspace_ the width of the spacers between buttons in navigation
333 // bar
334
335 // _httpdocument_ has '&f=1' added if displaying document inside a frame
336
337 // _gsdltop_ macro to replace _top targets with
338
339 // _httppagehome_ overridden home url if html collections have own homepage
340
341 // must have a valid collection server to continue
342 text_t &collection = args["c"];
343 if (collection.empty()) return;
344 recptproto *collectproto = protos->getrecptproto (collection, logout);
345 if (collectproto == NULL) return;
346
347 if (recpt == NULL) {
348 logout << "ERROR (documentaction::define_external_macros): This action does not contain\n"
349 << " information about any receptionists. The method set_receptionist was\n"
350 << " probably not called from the module which instantiated this action.\n";
351 return;
352 }
353
354 outconvertclass text_t2ascii;
355 comerror_t err;
356 InfoFiltersResponse_t filterinfo;
357 FilterResponse_t response;
358 text_tset metadata;
359
360 // get info on current collection and load up formatinfo
361 // I'd prefer not to do this here as we're getting
362 // collection info every time (and probably also getting
363 // it in other places some of the time) - One day I'll
364 // fix it ... maybe - Stefan.
365 ColInfoResponse_t cinfo;
366
367 collectproto->get_collectinfo (collection, cinfo, err, logout);
368 load_formatinfo (cinfo.format, args.getintarg("gt"));
369 // ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
370 // if (cinfo == NULL) {
371 // logout << "ERROR (documentaction::define_external_macros): get_collectinfo_ptr returned NULL\n";
372 // return;
373 // }
374 //load_formatinfo (cinfo->format, args.getintarg("gt"));
375
376 if (formatinfo.DocumentUseHTML) {
377
378 // frame stuff
379 if (args["fc"] == "1") {
380 text_t httpdocument;
381 disp.expandstring ("Global", "_httpdocument_", httpdocument);
382 httpdocument += "&f=1";
383 disp.setmacro ("httpdocument", "Global", httpdocument);
384 disp.setmacro ("gsdltop", "Global", "documenttop");
385 }
386 text_tmap::iterator it = cinfo.format.find ("homepage");
387 if (it != cinfo.format.end()) {
388 text_t httppagehome;
389 if (get_link (args, protos, (*it).second, httppagehome, logout))
390 disp.setmacro ("httppagehome", "Global", httppagehome);
391 }
392 }
393
394 // don't want navigation bar if page is 'detached'
395 if (!args.getintarg("x")) {
396
397 collectproto->get_filterinfo (collection, filterinfo, err, logout);
398 if (err == noError) {
399 // check that there's a browse filter
400 if (filterinfo.filterNames.find ("BrowseFilter") != filterinfo.filterNames.end()) {
401
402 metadata.insert ("Title");
403 bool getParents = false;
404 get_children ("", collection, metadata, getParents, collectproto, response, logout);
405
406 // calculate width of spacers and set _widthtspace_ macro
407 if (args.getintarg("v") == 0) set_spacemacro (disp, response);
408
409 // set _navigationbar_ macro
410 set_navbarmacros (disp, response, args);
411
412 }
413 } else {
414 logout << text_t2ascii
415 << "Error (documentaction::define_external_macros()) in call to get_filterinfo() "
416 << get_comerror_string (err);
417 }
418 }
419}
420
421bool documentaction::get_link (cgiargsclass &args, recptprotolistclass *protos,
422 const text_t &inlink, text_t &outlink, ostream &logout) {
423
424 FilterResponse_t response;
425 text_tset metadata;
426 metadata.insert ("section");
427
428 // check current collection first
429 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
430
431 if (get_info (inlink, args["c"], metadata, false, collectproto, response, logout)) {
432 if (!response.docInfo[0].metadata["section"].values[0].empty()) {
433 outlink = "_httpdocument_&d=" + response.docInfo[0].metadata["section"].values[0];
434 return true;
435 }
436 }
437
438 // check all the other enabled collections
439
440 if (args["ccs"] == "1" && !args["cc"].empty()) {
441 text_tarray collections;
442 splitchar (args["cc"].begin(), args["cc"].end(), ',', collections);
443
444 text_tarray::const_iterator col_here = collections.begin();
445 text_tarray::const_iterator col_end = collections.end();
446
447 while (col_here != col_end) {
448
449 // don't need to check current collection again
450 if (*col_here == args["c"]) {col_here ++; continue;}
451
452 collectproto = protos->getrecptproto (*col_here, logout);
453
454 if (get_info (inlink, *col_here, metadata, false, collectproto, response, logout)) {
455 if (!response.docInfo[0].metadata["section"].values[0].empty()) {
456 outlink = "_httpdocument_&c=" + *col_here + "&d=" +
457 response.docInfo[0].metadata["section"].values[0];
458 return true;
459 }
460 }
461 col_here ++;
462 }
463 }
464 return false;
465}
466
467void documentaction::load_formatinfo (const text_tmap &colformat, int gt) {
468
469 formatinfo.clear();
470 text_tmap::const_iterator format_here = colformat.begin();
471 text_tmap::const_iterator format_end = colformat.end();
472
473 while (format_here != format_end) {
474 if (((*format_here).first == "DocumentImages") &&
475 ((*format_here).second == "true"))
476 formatinfo.DocumentImages = true;
477 else if (((*format_here).first == "DocumentTitles") &&
478 ((*format_here).second == "false"))
479 formatinfo.DocumentTitles = false;
480 else if ((*format_here).first == "DocumentHeading")
481 formatinfo.DocumentHeading = (*format_here).second;
482 else if (((*format_here).first == "DocumentContents") &&
483 ((*format_here).second == "false"))
484 formatinfo.DocumentContents = false;
485 else if (((*format_here).first == "DocumentArrowsBottom") &&
486 ((*format_here).second == "false"))
487 formatinfo.DocumentArrowsBottom = false;
488 else if ((*format_here).first == "DocumentButtons")
489 splitchar ((*format_here).second.begin(), (*format_here).second.end(),
490 '|', formatinfo.DocumentButtons);
491 else if ((*format_here).first == "DocumentText")
492 formatinfo.DocumentText = (*format_here).second;
493 else if (((*format_here).first == "DocumentUseHTML") &&
494 ((*format_here).second == "true"))
495 formatinfo.DocumentUseHTML = true;
496 else
497 formatinfo.formatstrings[(*format_here).first] = (*format_here).second;
498
499 format_here ++;
500 }
501
502 // never want arrows when text is expanded
503 if (gt) formatinfo.DocumentArrowsBottom = false;
504}
505
506
507// define all the macros which are related to pages generated
508// by this action. we also load up the formatinfo structure
509// here (it's used in do_action as well as here)
510void documentaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
511 recptprotolistclass *protos, ostream &logout) {
512
513 // define_internal_macros sets the following macros:
514
515 // _pagetitle_ the title to be displayed at the top of the browser window
516
517 // _imagethispage_ the title image to be displayed at top right of page
518
519 // _navarrows_ this may be overridden to "" when format option
520 // DocumentArrowsBottom is false
521
522 // _header_ the header macro is overridden if we're not at a top level
523 // classification to remove the title block
524
525 // _thisOID_ the OID (directory) of the current document - this corresponds
526 // to the archivedir metadata element
527
528 // must have a valid collection server to continue
529 text_t &collection = args["c"];
530 if (collection.empty()) return;
531 recptproto *collectproto = protos->getrecptproto (collection, logout);
532 if (collectproto == NULL) return;
533
534 text_tset metadata;
535 FilterResponse_t response;
536 text_t &arg_d = args["d"];
537 text_t &arg_cl = args["cl"];
538
539 if (!formatinfo.DocumentArrowsBottom)
540 disp.setmacro("navarrows", "document", "");
541
542 metadata.insert ("Title");
543
544 bool fulltoc = false;
545
546 if (args["cl"] != "search") {
547 // see if there's a FullTOC string
548 text_t cl_top, full_toc;
549 get_top (arg_cl, cl_top);
550 if (get_formatstring (cl_top, "FullTOC", formatinfo.formatstrings, full_toc))
551 if (full_toc == "true") fulltoc = true;
552 }
553
554 if (!arg_d.empty() && !fulltoc) {
555 // we're at document level
556
557 metadata.insert ("archivedir");
558
559 OptionValue_tarray options;
560 // we need to know what the query was for the z3950proto
561 if (collectproto->get_protocol_name()=="z3950proto") {
562 OptionValue_t opt;
563 opt.name="Query";
564 opt.value=args["q"];
565 options.push_back(opt);
566 }
567
568 // get metadata for this document and it's parents
569 if (get_info (arg_d, collection, metadata, options,
570 true, collectproto, response, logout)) {
571 disp.setmacro ("header", "document", "_textheader_");
572
573 text_tarray pagetitlearray;
574 if (!response.docInfo[0].metadata["Title"].values[0].empty())
575 pagetitlearray.push_back (response.docInfo[0].metadata["Title"].values[0]);
576 if (args["gt"] != "1") {
577 MetadataInfo_t *parenttitle = response.docInfo[0].metadata["Title"].parent;
578 while (parenttitle != NULL) {
579 if (!parenttitle->values[0].empty())
580 pagetitlearray.push_back (parenttitle->values[0]);
581 parenttitle = parenttitle->parent;
582 }
583 }
584 reverse (pagetitlearray.begin(), pagetitlearray.end());
585 text_t pagetitle;
586 joinchar (pagetitlearray, ": ", pagetitle);
587 disp.setmacro ("pagetitle", "document", pagetitle);
588
589 if (is_top (arg_d))
590 disp.setmacro ("thisOID", "Global", dm_safe(response.docInfo[0].metadata["archivedir"].values[0]));
591 else {
592 MetadataInfo_t *parentad = response.docInfo[0].metadata["archivedir"].parent;
593 text_t thisOID;
594 while (parentad != NULL) {
595 thisOID = parentad->values[0];
596 parentad = parentad->parent;
597 }
598 disp.setmacro ("thisOID", "Global", dm_safe(thisOID));
599 }
600 }
601 } else {
602 if (!arg_cl.empty()) {
603
604 // get metadata for top level classification
605 text_t classtop;
606 get_top (arg_cl, classtop);
607 if (get_info (classtop, collection, metadata, false, collectproto, response, logout)) {
608
609 text_t &title = response.docInfo[0].metadata["Title"].values[0];
610 bool unknown = false;
611
612 // test the _XXXwidth_ macro to see if image macros are
613 // defined for this type of classification - if not we'll
614 // just display the text
615 text_t tmp;
616 disp.expandstring ("document", "_" + title + "width_", tmp);
617 if (tmp == ("_" + title + "width_")) unknown = true;
618
619 if (unknown) {
620 disp.setmacro ("pagetitle", "document", title);
621 disp.setmacro ("imagethispage", "document", "<h2>" + title + "</h2>");
622 } else {
623 disp.setmacro ("pagetitle", "document", "_text" + title + "page_");
624 disp.setmacro ("imagethispage", "document", "_icon" + title + "page_");
625 }
626 }
627 }
628 }
629}
630
631
632bool documentaction::do_action (cgiargsclass &args, recptprotolistclass *protos,
633 browsermapclass *browsers, displayclass &disp,
634 outconvertclass &outconvert, ostream &textout,
635 ostream &logout) {
636
637
638 // must have a valid collection server
639 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
640 if (collectproto == NULL) {
641 logout << "documentaction::do_action called with NULL collectproto\n";
642 textout << outconvert << disp << "_document:header_\n"
643 << "Error: Attempt to get document without setting collection\n"
644 << "_document:footer_\n";
645 } else {
646
647 text_t OID = args["d"];
648 if (OID.empty()) OID = args["cl"];
649 if (OID.empty()) {
650 textout << outconvert << disp << "Document contains no data_document:footer_\n";
651 return true;
652 }
653
654 if (formatinfo.DocumentUseHTML) {
655
656 if (!args["d"].empty()) {
657 if (args["f"] == "1") {
658 textout << outconvert << disp
659 << "<html><head></head>\n"
660 << "<frameset rows=\"68,*\" noresize border=0>\n"
661 << "<frame scrolling=no frameborder=0 src=\"_gwcgi_?e=_compressedoptions_&a=p&p=nav\">\n"
662 << "<frame name=\"documenttop\" frameborder=0 src=\"_gwcgi_?e=_compressedoptions_&a=d&d="
663 << args["d"] << "\">"
664 << "<noframes>\n"
665 << "<p>You must have a frame enabled browser to view this.</p>\n"
666 << "</noframes>\n"
667 << "</frameset>\n"
668 << "</html>\n";
669 } else {
670 output_document (OID, args, collectproto, disp, outconvert, textout, logout);
671 }
672 return true;
673 }
674 }
675
676 textout << outconvert << disp << "_document:header_\n"
677 << "_document:content_\n";
678
679 // output the table of contents
680 output_toc (args, browsers, formatinfo, collectproto,
681 disp, outconvert, textout, logout);
682
683 // output the document text
684 textout << "<p>\n";
685 output_document (OID, args, collectproto, disp, outconvert, textout, logout);
686
687 textout << outconvert << disp << "_document:footer_\n";
688 }
689 return true;
690}
691
692void documentaction::output_text (ResultDocInfo_t &docinfo, format_t *formatlistptr,
693 const TermInfo_tarray &terminfo, const text_t &OID,
694 bool highlight, int hastxt, int wanttext,
695 text_t &collection, recptproto *collectproto,
696 displayclass &disp, outconvertclass &outconvert,
697 ostream &textout, ostream &logout) {
698
699 DocumentRequest_t docrequest;
700 DocumentResponse_t docresponse;
701 comerror_t err;
702
703 if (hastxt == 1) {
704
705 if (wanttext) {
706 // get the text
707 docrequest.OID = OID;
708 collectproto->get_document (collection, docrequest, docresponse, err, logout);
709
710 // cut down on overhead by not using formattools if we only want the text
711 // (wanttext will equal 2 if we want text and other stuff too)
712 if (wanttext == 1)
713 if (highlight)
714 highlighttext(docresponse.doc, terminfo, disp, outconvert, textout, logout);
715 else
716 textout << outconvert << disp << docresponse.doc;
717 }
718
719 if (wanttext != 1) {
720 text_t doctext
721 = get_formatted_string (collection, collectproto,
722 docinfo, disp, formatlistptr, docresponse.doc,
723 logout);
724
725 if (highlight)
726 highlighttext(doctext, terminfo, disp, outconvert, textout, logout);
727 else
728 textout << outconvert << disp << doctext;
729 }
730 }
731}
732
733
734void documentaction::output_document (const text_t &OID, cgiargsclass &args,
735 recptproto *collectproto, displayclass &disp,
736 outconvertclass &outconvert, ostream &textout,
737 ostream &logout) {
738 FilterResponse_t inforesponse;
739 FilterResponse_t queryresponse;
740 text_tset metadata;
741 bool getParents = false;
742 bool highlight = false;
743 int wanttext = 0;
744 int arg_gt = args.getintarg("gt");
745 text_t &collection = args["c"];
746
747 // if we have a query string and highlighting is turned on we need
748 // to redo the query to get the terms for highlighting
749 if (!args["q"].empty() && args.getintarg("hl")) {
750 FilterRequest_t request;
751 comerror_t err;
752 request.filterResultOptions = FRmatchTerms;
753 text_t formattedstring = args["q"];
754 format_querystring (formattedstring, args.getintarg("b"));
755 set_queryfilter_options (request, formattedstring, args);
756 collectproto->filter (args["c"], request, queryresponse, err, logout);
757 if (err != noError) {
758 outconvertclass text_t2ascii;
759 logout << text_t2ascii
760 << "documentaction::output_document: call to QueryFilter failed "
761 << "for " << args["c"] << " collection (" << get_comerror_string (err) << ")\n";
762 highlight = false;
763 } else {
764 highlight = true;
765 }
766 }
767
768 format_t *formatlistptr = new format_t();
769 parse_formatstring (formatinfo.DocumentText, formatlistptr, metadata, getParents);
770
771 metadata.insert ("hastxt");
772 metadata.insert ("haschildren");
773
774 if (formatinfo.DocumentText == "[Text]")
775 wanttext = 1;
776 else {
777 char *docformat = formatinfo.DocumentText.getcstr();
778 if (strstr (docformat, "[Text]") != NULL)
779 wanttext = 2;
780 delete docformat;
781 }
782
783 if (get_info (OID, collection, metadata, getParents, collectproto, inforesponse, logout)) {
784 int hastxt = inforesponse.docInfo[0].metadata["hastxt"].values[0].getint();
785 int haschildren = inforesponse.docInfo[0].metadata["haschildren"].values[0].getint();
786
787 if (arg_gt == 0) {
788 output_text (inforesponse.docInfo[0], formatlistptr, queryresponse.termInfo,
789 OID, highlight, hastxt, wanttext, collection, collectproto,
790 disp, outconvert, textout, logout);
791
792
793 } else {
794
795 ResultDocInfo_t thisdocinfo = inforesponse.docInfo[0];
796
797 // text is to be expanded
798 text_t exOID = OID;
799 if (haschildren != 1) exOID = get_parent (OID);
800 if (exOID.empty()) exOID = OID;
801
802 // if we're not in a document (i.e. we're in a top level classification)
803 // we need to pass "is_classify = true" to get_contents so that it
804 // doesn't recurse all the way through each document in the classification
805 bool is_classify = false;
806 if (args["d"].empty()) is_classify = true;
807
808 get_contents (exOID, is_classify, metadata, collection,
809 collectproto, inforesponse, logout);
810
811 ResultDocInfo_tarray::iterator sechere = inforesponse.docInfo.begin();
812 ResultDocInfo_tarray::iterator secend = inforesponse.docInfo.end();
813
814 if (arg_gt == 1) {
815 // check if there are more than 10 sections containing text to be expanded -
816 // if there are output warning message - this isn't a great way to do this
817 // since the sections may be very large or very small - one day I'll fix it
818 // -- Stefan.
819 int seccount = 0;
820 while (sechere != secend) {
821 int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
822 if (shastxt == 1) seccount ++;
823 if (seccount > 10) break;
824 sechere ++;
825 }
826 if (seccount > 10) {
827 // more than 10 sections so output warning message and text
828 // for current section only
829 textout << outconvert << disp << "_document:textltwarning_";
830
831 output_text (thisdocinfo, formatlistptr, queryresponse.termInfo,
832 OID, highlight, hastxt, wanttext, collection,
833 collectproto, disp, outconvert, textout, logout);
834
835 }
836 else arg_gt = 2;
837 }
838
839 if (arg_gt == 2) {
840 // get the text for each section
841 sechere = inforesponse.docInfo.begin();
842 int count = 0;
843 while (sechere != secend) {
844 textout << outconvert << disp << "\n<p><a name=" << count << "></a>\n";
845
846 int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
847
848 output_text (*sechere, formatlistptr, queryresponse.termInfo,
849 (*sechere).OID, highlight, shastxt, wanttext, collection,
850 collectproto, disp, outconvert, textout, logout);
851 count ++;
852 sechere ++;
853 }
854 }
855 }
856 }
857 delete formatlistptr;
858}
859
860// highlighttext highlights query terms in text string and outputs the resulting text string
861void documentaction::highlighttext(text_t &text, const TermInfo_tarray &terms,
862 displayclass &disp, outconvertclass &outconvert,
863 ostream &textout, ostream &/*logout*/) {
864
865 text_tmap allterms;
866 text_tmap::const_iterator it;
867
868 // first load all the term variations into a map
869 TermInfo_tarray::const_iterator this_term = terms.begin();
870 TermInfo_tarray::const_iterator last_term = terms.end();
871 while (this_term != last_term) {
872 text_tarray::const_iterator this_var = (*this_term).matchTerms.begin();
873 text_tarray::const_iterator last_var = (*this_term).matchTerms.end();
874 while (this_var != last_var) {
875 allterms[*this_var] = 1;
876 this_var ++;
877 }
878 this_term ++;
879 }
880
881 // get the text to start and end a hightlight
882 text_t starthighlight = "<b><u>";
883 text_t endhighlight = "</u></b>";
884 if (disp.isdefaultmacro("Global", "starthighlight"))
885 disp.expandstring("Global", "_starthighlight_", starthighlight);
886 if (disp.isdefaultmacro("Global", "endhighlight"))
887 disp.expandstring("Global", "_endhighlight_", endhighlight);
888
889
890 text_t::iterator here = text.begin();
891 text_t::iterator end = text.end();
892 text_t word, buffer;
893 while (here != end) {
894 if (is_unicode_letdig(*here)) {
895 // not word boundary
896 word.push_back(*here);
897 here++;
898
899 } else {
900 // found word boundary
901 // add last word if there was one
902 if (!word.empty()) {
903 it = allterms.find(word);
904 if (it != allterms.end()) {
905 word = starthighlight + word + endhighlight;
906 }
907 buffer += word;
908 word.clear();
909 }
910
911 if (*here == '<') {
912 // skip over rest of html tag
913 while ((here != end) && (*here != '>')) {
914 buffer.push_back(*here);
915 here++;
916 }
917 }
918
919 buffer.push_back(*here);
920 here++;
921
922 if (buffer.size() > 1024) {
923 textout << outconvert << disp << buffer;
924 buffer.clear();
925 }
926 }
927 }
928 textout << outconvert << disp << buffer;
929}
Note: See TracBrowser for help on using the repository browser.