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

Last change on this file since 1804 was 1804, checked in by paynter, 23 years ago

Changed phind classifier so that its HTML is generated by documentaction,
instead of pageaction. This ensures that the macros it requires are set
properly and makes it consistant with the other classifiers. But what a
waste of my time it was.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 31.4 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 metadata.insert ("childtype");
608
609 if (get_info (classtop, collection, metadata, false, collectproto, response, logout)) {
610
611 text_t &title = response.docInfo[0].metadata["Title"].values[0];
612 bool unknown = false;
613
614 // test the _XXXwidth_ macro to see if image macros are
615 // defined for this type of classification - if not we'll
616 // just display the text
617 text_t tmp;
618 disp.expandstring ("document", "_" + title + "width_", tmp);
619 if (tmp == ("_" + title + "width_")) unknown = true;
620
621 if (unknown) {
622 disp.setmacro ("pagetitle", "document", title);
623 disp.setmacro ("imagethispage", "document", "<h2>" + title + "</h2>");
624 } else {
625 disp.setmacro ("pagetitle", "document", "_text" + title + "page_");
626 disp.setmacro ("imagethispage", "document", "_icon" + title + "page_");
627 }
628
629 // Add a macro to display the phind classifier (if appropriate)
630 text_t &childtype = response.docInfo[0].metadata["childtype"].values[0];
631 if (childtype == "Phind") {
632 disp.setmacro ("phindclassifier", "document", "_phindapplet_");
633 }
634 }
635 }
636 }
637}
638
639
640bool documentaction::do_action (cgiargsclass &args, recptprotolistclass *protos,
641 browsermapclass *browsers, displayclass &disp,
642 outconvertclass &outconvert, ostream &textout,
643 ostream &logout) {
644
645
646 // must have a valid collection server
647 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
648 if (collectproto == NULL) {
649 logout << "documentaction::do_action called with NULL collectproto\n";
650 textout << outconvert << disp << "_document:header_\n"
651 << "Error: Attempt to get document without setting collection\n"
652 << "_document:footer_\n";
653 } else {
654
655 text_t OID = args["d"];
656 if (OID.empty()) OID = args["cl"];
657 if (OID.empty()) {
658 textout << outconvert << disp << "Document contains no data_document:footer_\n";
659 return true;
660 }
661
662 if (formatinfo.DocumentUseHTML) {
663
664 if (!args["d"].empty()) {
665 if (args["f"] == "1") {
666 textout << outconvert << disp
667 << "<html><head></head>\n"
668 << "<frameset rows=\"68,*\" noresize border=0>\n"
669 << "<frame scrolling=no frameborder=0 src=\"_gwcgi_?e=_compressedoptions_&a=p&p=nav\">\n"
670 << "<frame name=\"documenttop\" frameborder=0 src=\"_gwcgi_?e=_compressedoptions_&a=d&d="
671 << args["d"] << "\">"
672 << "<noframes>\n"
673 << "<p>You must have a frame enabled browser to view this.</p>\n"
674 << "</noframes>\n"
675 << "</frameset>\n"
676 << "</html>\n";
677 } else {
678 output_document (OID, args, collectproto, disp, outconvert, textout, logout);
679 }
680 return true;
681 }
682 }
683
684 textout << outconvert << disp << "_document:header_\n"
685 << "_document:content_\n";
686
687 // output the table of contents
688 output_toc (args, browsers, formatinfo, collectproto,
689 disp, outconvert, textout, logout);
690
691 // output the document text
692 textout << "<p>\n";
693 output_document (OID, args, collectproto, disp, outconvert, textout, logout);
694
695 textout << outconvert << disp << "_document:footer_\n";
696 }
697 return true;
698}
699
700void documentaction::output_text (ResultDocInfo_t &docinfo, format_t *formatlistptr,
701 const TermInfo_tarray &terminfo, const text_t &OID,
702 bool highlight, int hastxt, int wanttext,
703 text_t &collection, recptproto *collectproto,
704 displayclass &disp, outconvertclass &outconvert,
705 ostream &textout, ostream &logout) {
706
707 DocumentRequest_t docrequest;
708 DocumentResponse_t docresponse;
709 comerror_t err;
710
711 if (hastxt == 1) {
712
713 if (wanttext) {
714 // get the text
715 docrequest.OID = OID;
716 collectproto->get_document (collection, docrequest, docresponse, err, logout);
717
718 // cut down on overhead by not using formattools if we only want the text
719 // (wanttext will equal 2 if we want text and other stuff too)
720 if (wanttext == 1)
721 if (highlight)
722 highlighttext(docresponse.doc, terminfo, disp, outconvert, textout, logout);
723 else
724 textout << outconvert << disp << docresponse.doc;
725 }
726
727 if (wanttext != 1) {
728 text_t doctext
729 = get_formatted_string (collection, collectproto,
730 docinfo, disp, formatlistptr, docresponse.doc,
731 logout);
732
733 if (highlight)
734 highlighttext(doctext, terminfo, disp, outconvert, textout, logout);
735 else
736 textout << outconvert << disp << doctext;
737 }
738 }
739}
740
741
742void documentaction::output_document (const text_t &OID, cgiargsclass &args,
743 recptproto *collectproto, displayclass &disp,
744 outconvertclass &outconvert, ostream &textout,
745 ostream &logout) {
746 FilterResponse_t inforesponse;
747 FilterResponse_t queryresponse;
748 text_tset metadata;
749 bool getParents = false;
750 bool highlight = false;
751 int wanttext = 0;
752 int arg_gt = args.getintarg("gt");
753 text_t &collection = args["c"];
754
755 // if we have a query string and highlighting is turned on we need
756 // to redo the query to get the terms for highlighting
757 if (!args["q"].empty() && args.getintarg("hl")) {
758 FilterRequest_t request;
759 comerror_t err;
760 request.filterResultOptions = FRmatchTerms;
761 text_t formattedstring = args["q"];
762 format_querystring (formattedstring, args.getintarg("b"));
763 set_queryfilter_options (request, formattedstring, args);
764 collectproto->filter (args["c"], request, queryresponse, err, logout);
765 if (err != noError) {
766 outconvertclass text_t2ascii;
767 logout << text_t2ascii
768 << "documentaction::output_document: call to QueryFilter failed "
769 << "for " << args["c"] << " collection (" << get_comerror_string (err) << ")\n";
770 highlight = false;
771 } else {
772 highlight = true;
773 }
774 }
775
776 format_t *formatlistptr = new format_t();
777 parse_formatstring (formatinfo.DocumentText, formatlistptr, metadata, getParents);
778
779 metadata.insert ("hastxt");
780 metadata.insert ("haschildren");
781
782 if (formatinfo.DocumentText == "[Text]")
783 wanttext = 1;
784 else {
785 char *docformat = formatinfo.DocumentText.getcstr();
786 if (strstr (docformat, "[Text]") != NULL)
787 wanttext = 2;
788 delete docformat;
789 }
790
791 if (get_info (OID, collection, metadata, getParents, collectproto, inforesponse, logout)) {
792 int hastxt = inforesponse.docInfo[0].metadata["hastxt"].values[0].getint();
793 int haschildren = inforesponse.docInfo[0].metadata["haschildren"].values[0].getint();
794
795 if (arg_gt == 0) {
796 output_text (inforesponse.docInfo[0], formatlistptr, queryresponse.termInfo,
797 OID, highlight, hastxt, wanttext, collection, collectproto,
798 disp, outconvert, textout, logout);
799
800
801 } else {
802
803 ResultDocInfo_t thisdocinfo = inforesponse.docInfo[0];
804
805 // text is to be expanded
806 text_t exOID = OID;
807 if (haschildren != 1) exOID = get_parent (OID);
808 if (exOID.empty()) exOID = OID;
809
810 // if we're not in a document (i.e. we're in a top level classification)
811 // we need to pass "is_classify = true" to get_contents so that it
812 // doesn't recurse all the way through each document in the classification
813 bool is_classify = false;
814 if (args["d"].empty()) is_classify = true;
815
816 get_contents (exOID, is_classify, metadata, collection,
817 collectproto, inforesponse, logout);
818
819 ResultDocInfo_tarray::iterator sechere = inforesponse.docInfo.begin();
820 ResultDocInfo_tarray::iterator secend = inforesponse.docInfo.end();
821
822 if (arg_gt == 1) {
823 // check if there are more than 10 sections containing text to be expanded -
824 // if there are output warning message - this isn't a great way to do this
825 // since the sections may be very large or very small - one day I'll fix it
826 // -- Stefan.
827 int seccount = 0;
828 while (sechere != secend) {
829 int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
830 if (shastxt == 1) seccount ++;
831 if (seccount > 10) break;
832 sechere ++;
833 }
834 if (seccount > 10) {
835 // more than 10 sections so output warning message and text
836 // for current section only
837 textout << outconvert << disp << "_document:textltwarning_";
838
839 output_text (thisdocinfo, formatlistptr, queryresponse.termInfo,
840 OID, highlight, hastxt, wanttext, collection,
841 collectproto, disp, outconvert, textout, logout);
842
843 }
844 else arg_gt = 2;
845 }
846
847 if (arg_gt == 2) {
848 // get the text for each section
849 sechere = inforesponse.docInfo.begin();
850 int count = 0;
851 while (sechere != secend) {
852 textout << outconvert << disp << "\n<p><a name=" << count << "></a>\n";
853
854 int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
855
856 output_text (*sechere, formatlistptr, queryresponse.termInfo,
857 (*sechere).OID, highlight, shastxt, wanttext, collection,
858 collectproto, disp, outconvert, textout, logout);
859 count ++;
860 sechere ++;
861 }
862 }
863 }
864 }
865 delete formatlistptr;
866}
867
868// highlighttext highlights query terms in text string and outputs the resulting text string
869void documentaction::highlighttext(text_t &text, const TermInfo_tarray &terms,
870 displayclass &disp, outconvertclass &outconvert,
871 ostream &textout, ostream &/*logout*/) {
872
873 text_tmap allterms;
874 text_tmap::const_iterator it;
875
876 // first load all the term variations into a map
877 TermInfo_tarray::const_iterator this_term = terms.begin();
878 TermInfo_tarray::const_iterator last_term = terms.end();
879 while (this_term != last_term) {
880 text_tarray::const_iterator this_var = (*this_term).matchTerms.begin();
881 text_tarray::const_iterator last_var = (*this_term).matchTerms.end();
882 while (this_var != last_var) {
883 allterms[*this_var] = 1;
884 this_var ++;
885 }
886 this_term ++;
887 }
888
889 // get the text to start and end a hightlight
890 text_t starthighlight = "<b><u>";
891 text_t endhighlight = "</u></b>";
892 if (disp.isdefaultmacro("Global", "starthighlight"))
893 disp.expandstring("Global", "_starthighlight_", starthighlight);
894 if (disp.isdefaultmacro("Global", "endhighlight"))
895 disp.expandstring("Global", "_endhighlight_", endhighlight);
896
897
898 text_t::iterator here = text.begin();
899 text_t::iterator end = text.end();
900 text_t word, buffer;
901 while (here != end) {
902 if (is_unicode_letdig(*here)) {
903 // not word boundary
904 word.push_back(*here);
905 here++;
906
907 } else {
908 // found word boundary
909 // add last word if there was one
910 if (!word.empty()) {
911 it = allterms.find(word);
912 if (it != allterms.end()) {
913 word = starthighlight + word + endhighlight;
914 }
915 buffer += word;
916 word.clear();
917 }
918
919 if (*here == '<') {
920 // skip over rest of html tag
921 while ((here != end) && (*here != '>')) {
922 buffer.push_back(*here);
923 here++;
924 }
925 }
926
927 buffer.push_back(*here);
928 here++;
929
930 if (buffer.size() > 1024) {
931 textout << outconvert << disp << buffer;
932 buffer.clear();
933 }
934 }
935 }
936 textout << outconvert << disp << buffer;
937}
Note: See TracBrowser for help on using the repository browser.