root/main/trunk/greenstone2/runtime-src/src/recpt/documentaction.cpp @ 22984

Revision 22984, 56.3 KB (checked in by ak19, 9 years ago)

1. Undoing commit of 22934 where decode_commas was called on stem and fold comma separated list: previously separated due to url-encoding of commas. Now that the problem has been fixed at the source, the decode_commas hack is no longer necessary. 2. Commas in stem and fold are no longer url-encoded because the multiple_value field of the continuously-reused struct arg_ainfo is always set back to the default false after ever being set to true. So it no longer subtly stays at true to affect Greenstone functioning in unforeseen ways (such as suddenly and unnecessarily URL-encoding commas where this is not wanted).

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
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_("+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   text_t &collection = args["c"];
731  if (collection.empty()) return;
732  recptproto *collectproto = protos->getrecptproto (collection, logout);
733  if (collectproto == NULL) return;
734
735  text_tset metadata;
736  FilterResponse_t response;
737  text_t &arg_d = args["d"];
738  text_t &arg_cl = args["cl"];
739
740  if (!formatinfo.DocumentArrowsBottom) {
741    disp.setmacro("navarrowsbottom", "document", "");
742  } else if (!formatinfo.DocumentArrowsBottom) {
743    disp.setmacro("navarrowstop", "document", "");
744  }
745
746  if (!arg_d.empty() && (formatinfo.DocumentArrowsBottom || formatinfo.DocumentArrowsTop)) {
747    // set _httpprevarrow_ and _httpnextarrow_
748    set_arrow_macros (args, collectproto, disp, logout);
749  }
750
751  metadata.insert ("Title");
752  metadata.insert ("gs.DocumentHeader");
753  metadata.insert ("DocumentHeader");
754 
755  bool fulltoc = false;
756
757  if (args["cl"] != "search") {
758    // see if there's a FullTOC string
759    text_t cl_top, full_toc;
760    get_top (arg_cl, cl_top);
761    if (get_formatstring (cl_top, "FullTOC", formatinfo.formatstrings, full_toc))
762      if (full_toc == "true") fulltoc = true;
763    disp.setmacro("cltop", "document", cl_top);
764  }
765 
766  if (!arg_d.empty() && !fulltoc) {
767    // we're at document level
768
769    metadata.insert ("assocfilepath");
770
771    comerror_t err;
772    OptionValue_tarray options;
773    // we need to do the query again for the z3950proto
774    if (collectproto->get_protocol_name(err)=="z3950proto") {
775      OptionValue_t opt;
776      opt.name="Term";opt.value=args["q"];options.push_back(opt);
777      opt.name="QueryType";
778      opt.value=(args.getintarg("t")) ? "ranked" : "boolean";
779      options.push_back(opt);
780      opt.name="Index";opt.value=args["h"];options.push_back(opt);
781    }
782   
783    //do not display relation metadata
784    disp.setmacro ("relateddoc", "document", ""); 
785       
786    //if preferences indicate relevant docs should be collected
787    //and there is no particular format specified then display
788    //this default format.
789     if(args["rd"] == "1" && formatinfo.RelatedDocuments.empty()){
790
791       text_t relation = g_EmptyText; //string for displaying relation metadata
792
793       //call function in formattools.cpp which will return the text of the
794       //related documents in a vertical list. This is the default format.
795
796       if (get_info (arg_d, collection, args["l"], metadata, options, false, collectproto, response, logout))
797     relation += get_related_docs(collection, collectproto, response.docInfo[0], logout);
798       
799       //set macro to be the related document string
800
801       disp.setmacro ("relateddoc", "document", relation);
802     }
803     
804 
805    // get metadata for this document and it's parents
806    if (get_info (arg_d, collection, args["l"], metadata, options,
807          true, collectproto, response, logout)) {
808
809      disp.setmacro ("header", "document", "_textheader_");
810      text_tarray pagetitlearray;
811      if (!response.docInfo[0].metadata["Title"].values[0].empty())
812    pagetitlearray.push_back (response.docInfo[0].metadata["Title"].values[0]);
813     
814      if (args["gt"] != "1") {
815    MetadataInfo_t *parenttitle = response.docInfo[0].metadata["Title"].parent;
816    while (parenttitle != NULL) {
817      if (!parenttitle->values[0].empty())
818        pagetitlearray.push_back (parenttitle->values[0]);
819      parenttitle = parenttitle->parent;
820    }
821      }
822      reverse (pagetitlearray.begin(), pagetitlearray.end());
823      text_t pagetitle;
824      joinchar (pagetitlearray, ": ", pagetitle);
825      // remove html tags from the title
826      text_t::iterator open_tag=pagetitle.begin();
827      while (open_tag < pagetitle.end()) {
828    if (*open_tag == '<') {
829      text_t::iterator close_tag=open_tag+1;
830      text_t::iterator donechar=pagetitle.end();
831      while (close_tag < donechar) {
832        if (*close_tag == '>')
833          break;
834        ++close_tag;
835      }
836      if (close_tag < donechar) // remove this html tag, replace with space
837        *close_tag=' ';
838      pagetitle.erase(open_tag, close_tag);
839    }
840    ++open_tag;
841      }
842      disp.setmacro ("pagetitle", "document", pagetitle);
843
844      // custom header info
845      text_t custom_header;
846      if (is_top (arg_d)) {
847    custom_header = response.docInfo[0].metadata["gs.DocumentHeader"].values[0];
848    if (custom_header.empty()) {
849      // try ex header
850      custom_header = response.docInfo[0].metadata["DocumentHeader"].values[0];
851    }
852      } else {
853    MetadataInfo_t *parentch = response.docInfo[0].metadata["gs.DocumentHeader"].parent;
854    while (parentch != NULL) {
855      custom_header = parentch->values[0];
856      parentch = parentch->parent;
857    }
858    if (custom_header.empty()) {
859      // try ex header
860      MetadataInfo_t *parentch = response.docInfo[0].metadata["DocumentHeader"].parent;
861      while (parentch != NULL) {
862        custom_header = parentch->values[0];
863        parentch = parentch->parent;
864      }
865    }
866      }
867      if (!custom_header.empty()) {
868    disp.setmacro("documentheader", "document", custom_header);
869      }
870   
871      if (is_top (arg_d))
872    disp.setmacro ("thisOID", displayclass::defaultpackage, dm_safe(response.docInfo[0].metadata["assocfilepath"].values[0]));
873      else {
874    MetadataInfo_t *parentad = response.docInfo[0].metadata["assocfilepath"].parent;
875    text_t thisOID;
876    while (parentad != NULL) {
877      thisOID = parentad->values[0];
878      parentad = parentad->parent;
879    }
880    disp.setmacro ("thisOID", displayclass::defaultpackage, dm_safe(thisOID));
881      }
882    }
883  } else {
884    if (!arg_cl.empty()) {
885   
886      // create the currentnodevalue macro - this is the value of the node
887      // in the hierarchy that is currently open.
888      if (get_info (arg_cl, collection, args["l"], metadata, false, collectproto, response, logout)) {
889    text_t &title = response.docInfo[0].metadata["Title"].values[0];
890    disp.setmacro ("currentnodevalue", "document", title);
891      }
892      // get metadata for top level classification
893      text_t classtop;
894      get_top (arg_cl, classtop);
895      metadata.insert ("childtype");
896      metadata.insert ("parameters");
897
898      if (get_info (classtop, collection, args["l"], metadata, false, collectproto, response, logout)) {
899     
900    text_t &title = response.docInfo[0].metadata["Title"].values[0];
901    bool unknown = false;
902
903    // test if we have macros defined for this classification's
904    // metadata name - if not we'll just display the name
905    text_t tmp;
906    text_t macroname="_label" + title + "_";
907    disp.expandstring ("Global", macroname, tmp);
908    if (tmp == macroname) unknown = true; // it wasn't expanded
909
910    if (unknown) {
911      disp.setmacro ("pagetitle", "document", title);
912    } else {
913      disp.setmacro ("pagetitle", "document", macroname);
914    }
915    /* for ns4/image layout compatibility. when this is no longer
916     * needed, set imagethispage to _label+title+_ */
917    text_t titlemacroname="_titleimage" + title + "_";
918    disp.expandstring ("Global", titlemacroname, tmp);
919    if (tmp == titlemacroname) { /* _titleimage$META_ isn't defined */
920      if (!unknown) /* _label$META_ is defined */
921        disp.setmacro ("imagethispage", "document", macroname);
922      else
923        disp.setmacro ("imagethispage", "document", title);
924    } else { /* _titleimage$META_ is defined */
925      disp.setmacro ("imagethispage", "document", titlemacroname);
926    }
927
928        //if the document is not a document from a collection
929    //we must set the macro to be an empty string
930    disp.setmacro ("relateddoc", "document", "");
931
932    // Add macros specific to the Collage/Phind classifiers
933    text_t &childtype = response.docInfo[0].metadata["childtype"].values[0];
934    if (childtype == "Collage") {
935
936      text_t::iterator a = arg_cl.begin();
937      text_t::iterator b = arg_cl.end();
938
939      bool collage = true;
940      while (a != b) {
941        if (*a == 46) collage = false;
942        ++a;
943      }
944
945      if (collage) {
946        disp.setmacro ("collageclassifier", "document", "_collageapplet_");
947
948            // Next, macros that control the way the classifier is displayed
949            text_t parameters = response.docInfo[0].metadata["parameters"].values[0];
950
951            // extract key=value pairs and set as macros
952            text_t::iterator here = parameters.begin();
953            text_t::iterator end = parameters.end();
954            text_t key, value;
955
956            while (here != end) {
957              // get the next key and value pair
958              here = getdelimitstr (here, end, '=', key);
959              here = getdelimitstr (here, end, ';', value);
960
961              // store this key=value pair
962              if (!key.empty() && !value.empty()) {
963                disp.setmacro ("collage"+key, "document", value);
964              }
965            }
966
967       
968      }
969    }
970
971    if (childtype == "Phind") {
972
973      // First, a macro to display the phind classifier
974      disp.setmacro ("phindclassifier", "document", "_phindapplet_");
975
976      // Next, macros that control the way the classifier is displayed
977      text_t parameters = response.docInfo[0].metadata["parameters"].values[0];
978
979      // extract key=value pairs and set as macros
980      text_t::iterator here = parameters.begin();
981      text_t::iterator end = parameters.end();
982      text_t key, value;
983     
984      while (here != end) {
985        // get the next key and value pair
986        here = getdelimitstr (here, end, '=', key);
987        here = getdelimitstr (here, end, ';', value);
988
989        // store this key=value pair
990        if (!key.empty() && !value.empty()) {
991          disp.setmacro (key, "document", value);
992        }
993      }
994    } // end if (childtype == "Phind")
995      }
996    } // end if (!arg_cl.empty()) {
997  }
998}
999
1000
1001bool documentaction::do_action(cgiargsclass &args, recptprotolistclass *protos,
1002                               browsermapclass *browsers, displayclass &disp,
1003                               outconvertclass &outconvert, ostream &textout,
1004                               ostream &logout)
1005{
1006  if ((args["book"] == "flashxml") && (!args["d"].empty()))
1007  {
1008    return do_action_flashxml(args,protos,browsers,disp,outconvert,textout,logout);
1009  }
1010  else if ((args["book"] == "on") && (!args["d"].empty()))
1011  {
1012    return do_action_book(args,protos,browsers,disp,outconvert,textout,logout);
1013  }
1014  else
1015  {
1016    return do_action_html(args,protos,browsers,disp,outconvert,textout,logout);
1017  }
1018
1019}
1020
1021//displaying the normal display when bookswitch=0(html)
1022bool documentaction::do_action_html(cgiargsclass &args, recptprotolistclass *protos,
1023                               browsermapclass *browsers, displayclass &disp,
1024                               outconvertclass &outconvert, ostream &textout,
1025                               ostream &logout)
1026{
1027  // must have a valid collection server
1028  recptproto *collectproto = protos->getrecptproto (args["c"], logout);
1029  if (collectproto == NULL) {
1030    logout << "documentaction::do_action called with NULL collectproto\n";
1031    textout << outconvert << disp << "_document:header_\n"
1032        << "Error: Attempt to get document without setting collection\n"
1033        << "_document:footer_\n";
1034  } else { 
1035   
1036    text_t OID = args["d"];
1037    if (OID.empty()) OID = args["cl"];
1038    if (OID.empty()) {
1039      textout << outconvert << disp << "Document contains no data_document:footer_\n";
1040      return true;
1041    }
1042
1043 
1044    if (formatinfo.DocumentUseHTML && !args["d"].empty()) {
1045     
1046      if (args["f"] == "1") {
1047    textout << outconvert << disp
1048        << "<html><head></head>\n"
1049        << "<frameset rows=\"68,*\" noresize border=0>\n"
1050        << "<frame scrolling=no frameborder=0 src=\"_gwcgi_?_optsite_e=_compressedoptions_&a=p&p=nav\">\n"
1051#ifndef DOCHANDLE
1052        << "<frame name=\"documenttop\" frameborder=0 src=\"_gwcgi_?_optsite_e=_compressedoptions_&a=d&d="
1053        << args["d"] << "\">"
1054#else
1055        << "<frame name=\"documenttop\" frameborder=0 src=\"_httpdocumenthandle_("
1056        << args["c"] << "," << args["d"] << ")\">"
1057#endif
1058        << "<noframes>\n"
1059        << "<p>You must have a frame enabled browser to view this.</p>\n"
1060        << "</noframes>\n"
1061        << "</frameset>\n"
1062        << "</html>\n";
1063      } else {
1064    output_document (OID, args, collectproto, browsers, disp, outconvert, textout, logout);
1065      }
1066      return true;
1067    }
1068
1069   
1070    textout << outconvert << disp << "_document:header_\n"
1071        << "_document:content_\n";
1072     
1073    // output the table of contents
1074    browsetoolsclass b;
1075    b.output_toc(args, browsers, formatinfo, collectproto,
1076                 disp, outconvert, textout, logout);
1077   
1078    if (formatinfo.DocumentArrowsTop && !args["d"].empty()) {
1079      textout << outconvert << disp << "_document:navarrowstop_\n";
1080    }
1081
1082    //output the related documents (may be the empty string)
1083    //will not output the docs if a format string is specified
1084    textout << outconvert << disp << "_document:relateddoc_\n";
1085
1086    // output the document text
1087    if (!args["d"].empty()) {
1088      output_document (OID, args, collectproto, browsers, disp, outconvert, textout, logout);
1089    }
1090
1091    textout << outconvert << disp << "_document:footer_\n";
1092  }
1093  return true;
1094}
1095
1096//displaying the book display when bookswitch=on
1097bool documentaction::do_action_book(cgiargsclass &args, recptprotolistclass *protos,
1098                               browsermapclass *browsers, displayclass &disp,
1099                               outconvertclass &outconvert, ostream &textout,
1100                               ostream &logout)
1101{
1102  // must have a valid collection server
1103  recptproto *collectproto = protos->getrecptproto (args["c"], logout);
1104  if (collectproto == NULL)
1105  {
1106        logout << "documentaction::do_action called with NULL collectproto\n";
1107        textout << outconvert << disp << "_document:header_\n"
1108        << "Error: Attempt to get document without setting collection\n";
1109  }
1110  else
1111  { 
1112        text_t OID = args["d"];
1113        if (OID.empty()) OID = args["cl"];
1114        if (OID.empty())
1115    {
1116            textout << outconvert << disp << "Document contains no data\n";
1117            return true;
1118        }
1119
1120        if (formatinfo.DocumentUseHTML && !args["d"].empty())
1121    {
1122            if (args["f"] == "1")
1123        {
1124            textout << outconvert << disp
1125                << "<html><head></head>\n"
1126                << "<frameset rows=\"68,*\" noresize border=0>\n"
1127                << "<frame scrolling=no frameborder=0 src=\"_gwcgi_?_optsite_e=_compressedoptions_&a=p&p=nav\">\n"
1128            #ifndef DOCHANDLE
1129                << "<frame name=\"documenttop\" frameborder=0 src=\"_gwcgi_?_optsite_e=_compressedoptions_&a=d&d="
1130                << args["d"] << "\">"
1131            #else
1132                << "<frame name=\"documenttop\" frameborder=0 src=\"_httpdocumenthandle_("
1133                << args["c"] << "," << args["d"] << ")\">"
1134            #endif
1135                << "<noframes>\n"
1136                << "<p>You must have a frame enabled browser to view this.</p>\n"
1137                << "</noframes>\n"
1138                << "</frameset>\n"
1139                << "</html>\n";
1140            }
1141        else
1142        {
1143            output_document (OID, args, collectproto, browsers, disp, outconvert, textout, logout);
1144            }
1145           
1146        return true;
1147        }
1148
1149
1150    //the header bit and the navigation button   
1151        textout << outconvert << disp << "_document:header_\n" << "_document:content_\n";
1152       
1153    //display the book
1154    textout << outconvert << disp << "_document:flashbook_\n";
1155   
1156    //the footer bit without the document arrow
1157    textout << outconvert << disp << "</div> <!-- id=document -->\n";
1158    textout << outconvert << disp << "_endspacer__htmlfooter_\n";
1159  }
1160 
1161  return true;
1162}
1163
1164//Displaying the xml when bookswitch=flashxml
1165bool documentaction::do_action_flashxml(cgiargsclass &args, recptprotolistclass *protos,
1166                               browsermapclass *browsers, displayclass &disp,
1167                               outconvertclass &outconvert, ostream &textout,
1168                               ostream &logout)
1169{
1170  // must have a valid collection server
1171  recptproto *collectproto = protos->getrecptproto (args["c"], logout);
1172  if (collectproto == NULL)
1173  {
1174    logout << "documentaction::do_action called with NULL collectproto\n";
1175    textout << outconvert << disp
1176        << "<Message>\n"
1177        << "  Error: Attempt to get document without setting collection\n"
1178        << "</Message>\n";
1179  }
1180  else
1181  { 
1182    text_t OID = args["d"];
1183    if (OID.empty()) OID = args["cl"];
1184    if (OID.empty())
1185    {
1186      textout << outconvert << disp
1187          << "<Message>\n"
1188          << "  Document contains no data\n"
1189          << "</Message>\n";
1190      return true;
1191    }
1192
1193    if (formatinfo.DocumentUseHTML && !args["d"].empty())
1194    { 
1195      if (args["f"] == "1")
1196      {
1197    textout << outconvert << disp
1198        << "<Message>\n"
1199        << "  Using frames makes no sense for XML output\n"
1200        << "</Message>\n";
1201      }
1202      else
1203      {
1204    output_document_flashxml (OID, args, collectproto, browsers, disp, outconvert, textout, logout);   
1205      }
1206
1207      return true;
1208    }
1209
1210    // output the document text
1211    if (!args["d"].empty())
1212    {
1213      output_document_flashxml (OID, args, collectproto, browsers, disp, outconvert, textout, logout);
1214    }
1215  }
1216
1217  return true;
1218}
1219
1220
1221
1222void documentaction::output_text (ResultDocInfo_t &docinfo, format_t *formatlistptr,
1223                  const TermInfo_tarray &terminfo, const text_t &OID,
1224                  bool highlight, int hastxt, int wanttext,
1225                  text_t &collection, recptproto *collectproto,
1226                  browsermapclass *browsers, displayclass &disp,
1227                  outconvertclass &outconvert, ostream &textout,
1228                  ostream &logout, cgiargsclass &args) {
1229 
1230  DocumentRequest_t docrequest;
1231  DocumentResponse_t docresponse;
1232  comerror_t err;
1233  if (hastxt == 1) {
1234
1235    if (wanttext) {
1236      // get the text
1237      docrequest.OID = OID;
1238      collectproto->get_document (collection, docrequest, docresponse, err, logout);
1239
1240      // cut down on overhead by not using formattools if we only want the text
1241      // (wanttext will equal 2 if we want text and other stuff too)
1242      if (wanttext == 1)
1243    if (highlight) {
1244      highlighttext(docresponse.doc, args, terminfo, disp, outconvert, textout);
1245    } else {
1246      textout << outconvert << disp << docresponse.doc;
1247    }
1248    }
1249 
1250    if (wanttext != 1) {
1251      text_tmap options;
1252      options["text"] = docresponse.doc;
1253
1254      browsetoolsclass b;
1255      options["assocfilepath"] = b.get_assocfile_path();
1256      if (formatinfo.AllowExtendedOptions) {
1257    b.load_extended_options(options, args, browsers, formatinfo,
1258                                collectproto, disp, outconvert, logout);
1259      }
1260     
1261      text_t doctext
1262     = get_formatted_string (collection, collectproto, docinfo, disp,
1263                 formatlistptr, options, logout);
1264     
1265      if (highlight) {
1266    highlighttext(doctext, args, terminfo, disp, outconvert, textout);
1267      } else {
1268    textout << outconvert << disp << doctext;
1269      }
1270    }
1271  }
1272}
1273
1274
1275void documentaction::output_document (const text_t &OID, cgiargsclass &args,
1276                      recptproto *collectproto, browsermapclass *browsers,
1277                      displayclass &disp, outconvertclass &outconvert,
1278                      ostream &textout, ostream &logout) {
1279  FilterResponse_t inforesponse;
1280  FilterResponse_t queryresponse;
1281  text_tset metadata;
1282  bool getParents = false;
1283  bool highlight = false;
1284  int wanttext = 0;
1285  int arg_gt = args.getintarg("gt");
1286  text_t &collection = args["c"];
1287   
1288  // if we have a query string and highlighting is turned on we need
1289  // to redo the query to get the terms for highlighting
1290 
1291  if (!args["q"].empty() && args.getintarg("hl")) {
1292
1293    ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
1294    bool segment = false;
1295    if (cinfo != NULL) {
1296      segment = cinfo->isSegmented;
1297    }
1298    FilterRequest_t request;
1299    comerror_t err;
1300    request.filterResultOptions = FRmatchTerms;
1301    text_t formattedstring = args["q"];
1302    format_querystring (formattedstring, args.getintarg("b"), segment);
1303    set_fulltext_queryfilter_options (request, formattedstring, args);
1304    args["q"] = formattedstring; // need to set this here for phrase
1305                   // highlighting, where we look at the querystring
1306    collectproto->filter (args["c"], request, queryresponse, err, logout);
1307    if (err != noError) {
1308      outconvertclass text_t2ascii;
1309      logout << text_t2ascii
1310         << "documentaction::output_document: call to QueryFilter failed "
1311         << "for " << args["c"] << " collection (" << get_comerror_string (err) << ")\n";
1312      highlight = false;
1313    } else {
1314      highlight = true;
1315    }
1316  }
1317
1318  format_t *formatlistptr = new format_t();
1319  parse_formatstring (formatinfo.DocumentText, formatlistptr, metadata, getParents);
1320
1321  metadata.insert ("hastxt");
1322  metadata.insert ("haschildren");
1323
1324  if (formatinfo.DocumentText == "[Text]")
1325    wanttext = 1;
1326  else {
1327    char *docformat = formatinfo.DocumentText.getcstr();
1328    if (strstr (docformat, "[Text]") != NULL)
1329      wanttext = 2;
1330    delete []docformat;
1331  }
1332   
1333  textout << outconvert << "<div class=\"documenttext\">\n";
1334
1335  if (get_info (OID, collection, args["l"], metadata, getParents, collectproto, inforesponse, logout)) {
1336    int hastxt = inforesponse.docInfo[0].metadata["hastxt"].values[0].getint();
1337    int haschildren = inforesponse.docInfo[0].metadata["haschildren"].values[0].getint();
1338   
1339    if (arg_gt == 0) {
1340      output_text (inforesponse.docInfo[0], formatlistptr, queryresponse.termInfo,
1341           OID, highlight, hastxt, wanttext, collection, collectproto,
1342           browsers, disp, outconvert, textout, logout, args);
1343
1344    } else {
1345
1346      ResultDocInfo_t thisdocinfo = inforesponse.docInfo[0];
1347   
1348      // text is to be expanded
1349      text_t exOID = OID;
1350      if (haschildren != 1) exOID = get_parent (OID);
1351      if (exOID.empty()) exOID = OID;
1352   
1353      // if we're not in a document (i.e. we're in a top level classification)
1354      // we need to pass "is_classify = true" to get_contents so that it
1355      // doesn't recurse all the way through each document in the classification
1356      bool is_classify = false;
1357      if (args["d"].empty()) is_classify = true;
1358
1359      get_contents (exOID, is_classify, metadata, collection, args["l"],
1360            collectproto, inforesponse, logout);
1361   
1362      ResultDocInfo_tarray::iterator sechere = inforesponse.docInfo.begin();
1363      ResultDocInfo_tarray::iterator secend = inforesponse.docInfo.end();
1364
1365      if (arg_gt == 1) {
1366    // check if there are more than 10 sections containing text to be expanded -
1367    // if there are output warning message - this isn't a great way to do this
1368    // since the sections may be very large or very small - one day I'll fix it
1369    // -- Stefan.
1370    int seccount = 0;
1371    while (sechere != secend) {
1372      int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
1373      if (shastxt == 1) ++seccount;
1374      if (seccount > 10) break;
1375      ++sechere;
1376    }
1377    if (seccount > 10) {
1378      // more than 10 sections so output warning message and text
1379      // for current section only
1380      textout << outconvert << disp << "<div class=\"warning\">_document:textltwarning_</div>\n";
1381
1382      output_text (thisdocinfo, formatlistptr, queryresponse.termInfo,
1383               OID, highlight, hastxt, wanttext, collection,
1384               collectproto, browsers, disp, outconvert, textout, logout, args);
1385     
1386    }
1387    else arg_gt = 2;
1388      }
1389
1390      if (arg_gt == 2) {
1391    // get the text for each section
1392    sechere = inforesponse.docInfo.begin();
1393    int count = 0;
1394    while (sechere != secend) {
1395      textout << outconvert << disp << "\n<p><a name=\"" << (*sechere).OID << "\"></a>\n";
1396
1397      int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
1398
1399
1400      output_text (*sechere, formatlistptr, queryresponse.termInfo,
1401               (*sechere).OID, highlight, shastxt, wanttext, collection,
1402               collectproto, browsers, disp, outconvert, textout, logout, args);
1403
1404      ++count;
1405      ++sechere;
1406    }
1407      }
1408    }
1409  }
1410  textout << outconvert << "</div>\n";
1411  delete formatlistptr;
1412}
1413
1414void documentaction::output_document_flashxml(const text_t &OID, cgiargsclass &args,
1415                      recptproto *collectproto, browsermapclass *browsermap,
1416                      displayclass &disp, outconvertclass &outconvert,
1417                      ostream &textout, ostream &logout) {
1418    //if this is not at the document level --> do Nothing!!
1419    if (args["d"].empty())
1420        return;
1421       
1422    //if we have a query string and highlighting is turned on we need
1423    //to redo the query to get the terms for highlighting
1424    FilterResponse_t queryresponse;
1425    bool highlight = false;
1426    if (!args["q"].empty() && args.getintarg("hl"))
1427    {
1428        text_t &collection = args["c"];
1429            ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
1430            bool segment = false;
1431            if (cinfo != NULL)
1432        {
1433                segment = cinfo->isSegmented;
1434            }
1435            FilterRequest_t request;
1436            comerror_t err;
1437            request.filterResultOptions = FRmatchTerms;
1438            text_t formattedstring = args["q"];
1439            format_querystring (formattedstring, args.getintarg("b"), segment);
1440            set_fulltext_queryfilter_options (request, formattedstring, args);
1441            args["q"] = formattedstring;    //need to set this here for phrase
1442                                //highlighting, where we look at the querystring
1443            collectproto->filter (args["c"], request, queryresponse, err, logout);
1444            if (err != noError)
1445        {
1446                outconvertclass text_t2ascii;
1447                logout << text_t2ascii
1448                    << "documentaction::output_document: call to QueryFilter failed "
1449                    << "for " << args["c"] << " collection (" << get_comerror_string (err) << ")\n";
1450                highlight = false;
1451            }
1452        else
1453        {
1454                highlight = true;
1455            }
1456    }
1457   
1458    FilterResponse_t response;
1459    bool getParents = false;
1460    text_tset metadata;
1461    text_t classifytype, classification, formatstring;
1462   
1463    //metadata elements needed by recurse_contents
1464    metadata.insert ("Title");
1465    metadata.insert ("gs.allowPrinting");
1466    metadata.insert ("haschildren");
1467
1468    //protocol call
1469    if (!get_info (OID, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
1470            return;
1471
1472    recurse_contents (response.docInfo[0], args, metadata,
1473                getParents, collectproto, disp, outconvert, textout, logout, highlight, queryresponse.termInfo);
1474}
1475
1476void documentaction::recurse_contents(ResultDocInfo_t &section, cgiargsclass &args,
1477                                        text_tset &metadata, bool &getParents,
1478                                        recptproto *collectproto, displayclass &disp,
1479                                        outconvertclass &outconvert, ostream &textout, ostream &logout,
1480                    bool highlight, const TermInfo_tarray &terminfo)
1481{
1482    text_t formatstring;
1483
1484    bool is_classify = false;
1485   
1486    //output this section
1487    text_t classification = "Document";
1488   
1489    textout << outconvert << disp << "<Section>\n";
1490   
1491    //get the title
1492    textout << outconvert << disp << "<Description>\n";
1493
1494    textout << outconvert << disp << "  <Metadata name=\"Title\">";
1495    text_t t_title = section.metadata["Title"].values[0];
1496
1497    //if it is highlighted
1498    /*if (highlight == true)
1499    {
1500        highlighttext(t_title, args, terminfo, disp, outconvert, textout);
1501    }
1502    else
1503    {*/
1504        textout << outconvert << disp << t_title;
1505    //}
1506
1507    textout << outconvert << disp << "</Metadata>\n";
1508
1509    // if top-level document section, add in allowPrint metadata
1510    if (is_top(section.OID)) {
1511      textout << outconvert << disp << "  <Metadata name=\"allowPrint\">";
1512      text_t t_allowprint = "true";
1513
1514      if (section.metadata["gs.allowPrinting"].values.size()>0) {
1515        text_t opt_allowprint = section.metadata["gs.allowPrinting"].values[0];
1516        if (!opt_allowprint.empty()) {
1517          t_allowprint = opt_allowprint;
1518        }
1519      }
1520
1521      textout << outconvert << disp << t_allowprint;
1522      textout << outconvert << disp << "</Metadata>\n";
1523    }
1524
1525    textout << outconvert << disp << "</Description>\n";
1526
1527    //get the text
1528    DocumentRequest_t docrequest;
1529    DocumentResponse_t docresponse;
1530    comerror_t err;
1531    docrequest.OID = section.OID;
1532    text_t &collection = args["c"];
1533    collectproto->get_document(collection, docrequest, docresponse, err, logout);
1534    //if it is highlighted
1535    if (highlight == true)
1536    {
1537        highlighttext(docresponse.doc, args, terminfo, disp, outconvert, textout);
1538    }
1539    else
1540    {
1541        textout << outconvert << disp << docresponse.doc;
1542    }
1543    textout << outconvert << disp << "\n";
1544   
1545    int haschildren = section.metadata["haschildren"].values[0].getint();
1546   
1547    // recurse through children
1548    if (haschildren == 1)
1549    {
1550            FilterResponse_t tmp;
1551            get_children (section.OID, args["c"], args["l"], metadata, getParents, collectproto, tmp, logout);
1552            ResultDocInfo_tarray::iterator thisdoc = tmp.docInfo.begin();
1553            ResultDocInfo_tarray::iterator lastdoc = tmp.docInfo.end();
1554
1555            while (thisdoc != lastdoc)
1556        {
1557                recurse_contents (*thisdoc, args, metadata, getParents, collectproto, disp, outconvert, textout, logout, highlight, terminfo);
1558                ++thisdoc;
1559            }
1560    }
1561   
1562    textout << outconvert << disp << "</Section>\n";
1563}
1564
1565void documentaction::set_arrow_macros (cgiargsclass &args, recptproto *collectproto,
1566                       displayclass &disp, ostream &logout) {
1567
1568  text_tset metadata;
1569  FilterResponse_t response;
1570  FilterResponse_t presponse;
1571
1572  int haschildren = 0;
1573  text_tarray next_siblings;
1574  text_t previous_sibling;
1575  text_t &arg_d = args["d"];
1576
1577  // get info on current section
1578  metadata.insert("haschildren");
1579  if (!get_info(arg_d, args["c"], args["l"], metadata, false, collectproto, response, logout)) {
1580    logout << "error 1 in documentaction::set_arrow_macros\n";
1581    return;
1582  }
1583  haschildren = response.docInfo[0].metadata["haschildren"].values[0].getint();
1584     
1585  // get OIDs of next and previous siblings of current section and
1586  // all it's parents
1587  int parentcount = countchar(arg_d.begin(), arg_d.end(), '.');
1588  text_t thisoid = arg_d;
1589  while (parentcount > 0) {
1590    get_children (get_parent(thisoid), args["c"], args["l"], metadata, false,
1591          collectproto, response, logout);
1592    ResultDocInfo_tarray::iterator this_sibling = response.docInfo.begin();
1593    ResultDocInfo_tarray::iterator last_sibling = response.docInfo.end();
1594    bool first = true;
1595    while (this_sibling != last_sibling) {
1596      if ((*this_sibling).OID == thisoid) {
1597    if (!first && next_siblings.empty()) {
1598      previous_sibling = (*(this_sibling-1)).OID;
1599      int section_has_children = (*(this_sibling-1)).metadata["haschildren"].values[0].getint();
1600      // if previous sibling has children we need to recurse
1601      // down to the last descendant
1602      while (section_has_children) {
1603        get_children (previous_sibling, args["c"], args["l"], metadata, false,
1604              collectproto, presponse, logout);
1605        if (!presponse.docInfo.empty()) {
1606          ResultDocInfo_tarray::iterator it = presponse.docInfo.end() - 1;
1607          previous_sibling = (*it).OID;
1608          section_has_children = (*it).metadata["haschildren"].values[0].getint();
1609        } else {
1610          section_has_children = 0; // this should never happen
1611        }
1612      }
1613    }
1614       
1615    if ((this_sibling+1) != last_sibling) {
1616      next_siblings.push_back((*(this_sibling+1)).OID);
1617    } else {
1618      next_siblings.push_back("");
1619    }
1620    break;
1621      }
1622      ++this_sibling;
1623      first = false;
1624    }
1625    thisoid = get_parent(thisoid);
1626    --parentcount;
1627  }
1628
1629  // work out values for next link
1630  if (haschildren) {
1631#ifndef DOCHANLE
1632    disp.setmacro ("httpnextarrow", "document", "_httpdocument_&amp;cl=" + args["cl"] +
1633           "&amp;d=" + arg_d + ".fc");
1634#else
1635    disp.setmacro ("httpnextarrow", "document", "_httpdocumenthandle_("+args["c"]+","+arg_d + ".fc)";
1636
1637#endif
1638
1639  } else {
1640    text_tarray::const_iterator h = next_siblings.begin();
1641    text_tarray::const_iterator e = next_siblings.end();
1642    while (h != e) {
1643      if (!(*h).empty()) {
1644#ifndef DOCHANLE
1645    disp.setmacro ("httpnextarrow", "document", "_httpdocument_&amp;cl=" + args["cl"] +
1646               "&amp;d=" + *h);
1647#else
1648    disp.setmacro ("httpnextarrow", "document", "_httpdocumenthandle_("+args["c"]+","+*h+")";
1649
1650#endif
1651
1652    break;
1653      }
1654      ++h;
1655    }
1656  }
1657
1658  // work out value for previous link
1659  if (!previous_sibling.empty()) {
1660#ifndef DOCHANDLE
1661    disp.setmacro ("httpprevarrow", "document", "_httpdocument_&amp;cl=" + args["cl"] +
1662           "&amp;d=" + previous_sibling);
1663#else
1664    disp.setmacro ("httpprevarrow", "document", "_httpdocumenthandle_("+args["c"]+","+ previous_sibling+")");
1665
1666#endif
1667
1668  } else {
1669    if (countchar(arg_d.begin(), arg_d.end(), '.')) {
1670#ifndef DOCHANDLE
1671      disp.setmacro ("httpprevarrow", "document", "_httpdocument_&amp;cl=" + args["cl"] +
1672             "&amp;d=" + get_parent(arg_d));
1673#else
1674      disp.setmacro ("httpprevarrow", "document", "_httpdocumenthandle_("+args["c"]+","+get_parent(arg_d)+")");
1675
1676#endif
1677
1678    }
1679  }
1680}
Note: See TracBrowser for help on using the browser.