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

Last change on this file since 11152 was 11152, checked in by jrm21, 18 years ago

we now use the page title where the banner image used to be... this means
we can now remove all the images for "about" "titles a-z" etc that were
shown on the top right hand side.

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