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

Last change on this file since 12082 was 12044, checked in by sjboddie, 18 years ago

Wrapped browsetools up into a class and renamed it browsetoolsclass. The
intention of this change is only to make it easier to customise, and it
shouldn't make any functional difference. One exception to this is the
removal of some old code (notably some code for RelatedDocs) which is
now obsolete (I hope).

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