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

Last change on this file since 11539 was 11539, checked in by kjdon, 18 years ago

when deciding if a classifier is a datelist or not, now we check childtype rather than Title - someone may want to change the title of their datelist.

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