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

Revision 27363, 57.0 KB (checked in by ak19, 6 years ago)

If you add in the line 'format AllowUserComments? true' into a collection's collect.cfg, you can now control whether the User Comments section appears on a document page or not. The runtime-src/src/recpt/documentaction.cpp defines an internal macro for the document package called allowusercomments and this is then checked for in macros/document.dm.

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