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

Last change on this file since 1148 was 1148, checked in by sjboddie, 24 years ago

attempting to get end-user collection building to work under windows

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 37.1 KB
Line 
1/**********************************************************************
2 *
3 * documentaction.cpp --
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 * $Id: documentaction.cpp 1148 2000-05-04 05:18:46Z sjboddie $
25 *
26 *********************************************************************/
27
28/*
29 $Log$
30 Revision 1.38 2000/05/04 05:18:46 sjboddie
31 attempting to get end-user collection building to work under windows
32
33 Revision 1.37 2000/04/07 04:40:44 sjboddie
34 Reverted back to old DocumentHeader, DocumentTitles, DocumentImages etc.
35 from DocumentColumns stuff. I'll move the DocumentColumns stuff to a
36 separate development branch (New_Config_Format-branch) for now. The plan
37 is to redesign the configuration file format a bit and limit the number of
38 distributions floating around that take different configuration formats).
39
40 Revision 1.34 2000/02/15 22:53:49 kjm18
41 search history stuff added.
42
43 Revision 1.33 2000/02/13 20:40:05 sjboddie
44 now dm_safe _thisOID_ macro
45
46 Revision 1.32 2000/01/25 22:39:15 sjboddie
47 added DocumentUseHTML - tidied some things up (and messed up some others)
48
49 Revision 1.31 1999/11/13 08:57:00 sjboddie
50 fixed bug in last changes
51
52 Revision 1.30 1999/11/01 21:54:27 sjboddie
53 changes for cross-collection searching - changes to arguments
54 of many functions
55
56 Revision 1.29 1999/10/24 07:23:40 sjboddie
57 added FullTOC option
58
59 Revision 1.28 1999/10/19 03:23:42 davidb
60 Collection building support through web pages
61 and internal and external link handling for collection documents
62
63 Revision 1.27 1999/10/14 23:00:53 sjboddie
64 finished changes to browsing support
65
66 Revision 1.26 1999/10/10 08:14:06 sjboddie
67 - metadata now returns mp rather than array
68 - redesigned browsing support (although it's not finished so
69 won't currently work ;-)
70
71 Revision 1.25 1999/09/17 04:46:05 sjboddie
72 fixed a couple of problems with 'unknown' classifier
73
74 Revision 1.24 1999/09/17 04:00:26 sjboddie
75 tidied up navigation bar to produce a default "unknown" button if
76 it comes across metadata it can't display
77
78 Revision 1.23 1999/09/07 04:56:54 sjboddie
79 added GPL notice
80
81 Revision 1.22 1999/08/20 01:00:22 sjboddie
82 split some of the larger functions up to simplify the creation of
83 collection specific receptionists
84
85 Revision 1.21 1999/08/11 23:28:03 sjboddie
86 -added support for html classifier
87 - removed _random_ macro - now use _blank for detach page
88
89 Revision 1.20 1999/08/10 23:16:39 sjboddie
90 a couple of small changes to get format options DocumentArrowsBottom
91 and DocumentArrowsTop working correctly
92
93 Revision 1.19 1999/08/10 22:40:01 sjboddie
94 added some more format options including the ability to format the
95 document text
96
97 Revision 1.18 1999/08/09 04:25:18 sjboddie
98 moved OID translation stuff from documentaction::define_external_macros
99 to receptionist
100
101 Revision 1.17 1999/08/09 02:13:53 sjboddie
102 fixed small bug in ShowSectionTitles
103
104 Revision 1.16 1999/08/03 03:30:47 sjboddie
105 a few small changes related to new format options
106
107 Revision 1.15 1999/07/30 02:18:49 sjboddie
108 -added collectinfo argument to some functions
109 -caught up with changes to browsetools (allowing nested classifications)
110 -added showtoppage format option
111
112 Revision 1.14 1999/07/21 05:01:09 sjboddie
113 fixed up wrapping of classificationlinks
114
115 Revision 1.13 1999/07/20 02:59:54 sjboddie
116 List and AZList classifications now use format strings
117
118 Revision 1.12 1999/07/16 00:19:01 sjboddie
119 some changes to the way quoted queries are handled
120
121 Revision 1.11 1999/07/07 05:47:41 sjboddie
122 changed around the way browsetools works
123
124 Revision 1.10 1999/06/29 01:46:44 sjboddie
125 now sets a _navigationbar_ macro even if there aren't any
126 classifications (it will just have the 'search' button
127
128 Revision 1.9 1999/06/27 22:05:58 sjboddie
129 now set a _thisOID_ macro for use in displaying images
130
131 Revision 1.8 1999/06/24 05:12:20 sjboddie
132 lots of small changes
133
134 Revision 1.7 1999/06/17 03:06:58 sjboddie
135 got detach button working properly - the close book icon is now disabled
136 when page is detached as the javascript close() function I was using is
137 too unreliable over different browsers
138 note that in my last comment I meant the "cl" arg (not the "c" arg).
139
140 Revision 1.6 1999/06/16 23:53:15 sjboddie
141 tidied a few things up. documentaction::define_external_macros now
142 resets the "c" arg if it's set to something stupid by the .xx suffixes
143
144 Revision 1.5 1999/06/16 03:10:49 sjboddie
145 define_internal_macros() now sets _pagetitle_ macro to document's title
146 (including parents of current document)
147
148 Revision 1.4 1999/06/15 01:55:29 sjboddie
149 - got text highlighting working
150 - got multiple collections working (now outputs error message if an
151 attempt is made to get a document when the "c" arg isn't set.
152
153 Revision 1.3 1999/06/08 04:29:37 sjboddie
154 added argsinfo to the call to check_cgiargs to make it easy to set
155 args to their default if they're found to be screwed up
156
157 Revision 1.2 1999/05/10 03:40:35 sjboddie
158 lots of changes - slowly getting document action sorted out
159
160 Revision 1.1 1999/04/30 01:59:40 sjboddie
161 lots of stuff - getting documentaction working (documentaction replaces
162 old browseaction)
163
164 Revision 1.2 1999/03/29 02:14:27 sjboddie
165
166 More changes to browseaction
167
168 Revision 1.1 1999/03/25 03:09:40 sjboddie
169
170 subjectbrowseaction became browseaction
171
172
173 */
174
175
176#include <string.h>
177#include "documentaction.h"
178#include "browsetools.h"
179#include "OIDtools.h"
180#include "querytools.h"
181#include "unitool.h"
182#include "gsdltools.h"
183
184documentaction::documentaction () {
185
186 // this action uses cgi variables "a", "d", "cl",
187 // "x", "gc", "gt", "gp", and "hl"
188 cgiarginfo arg_ainfo;
189 arg_ainfo.shortname = "a";
190 arg_ainfo.longname = "action";
191 arg_ainfo.multiplechar = true;
192 arg_ainfo.defaultstatus = cgiarginfo::weak;
193 arg_ainfo.argdefault = "p";
194 arg_ainfo.savedarginfo = cgiarginfo::must;
195 argsinfo.addarginfo (NULL, arg_ainfo);
196
197 arg_ainfo.shortname = "d";
198 arg_ainfo.longname = "document OID";
199 arg_ainfo.multiplechar = true;
200 arg_ainfo.defaultstatus = cgiarginfo::none;
201 arg_ainfo.argdefault = "";
202 arg_ainfo.savedarginfo = cgiarginfo::can;
203 argsinfo.addarginfo (NULL, arg_ainfo);
204
205 // whether or not a document should be retrieved from the
206 // library or the Web.
207 arg_ainfo.shortname = "il";
208 arg_ainfo.longname = "internal link preference";
209 arg_ainfo.multiplechar = false;
210 arg_ainfo.defaultstatus = cgiarginfo::weak;
211 arg_ainfo.argdefault = "l";
212 arg_ainfo.savedarginfo = cgiarginfo::must;
213 argsinfo.addarginfo (NULL, arg_ainfo);
214
215 arg_ainfo.shortname = "cl";
216 arg_ainfo.longname = "classification OID";
217 arg_ainfo.multiplechar = true;
218 arg_ainfo.defaultstatus = cgiarginfo::none;
219 arg_ainfo.argdefault = "";
220 arg_ainfo.savedarginfo = cgiarginfo::can;
221 argsinfo.addarginfo (NULL, arg_ainfo);
222
223 // in this action "gc" controls the expand/contract
224 // contents function
225 arg_ainfo.shortname = "gc";
226 arg_ainfo.longname = "expand contents";
227 arg_ainfo.multiplechar = false;
228 arg_ainfo.defaultstatus = cgiarginfo::weak;
229 arg_ainfo.argdefault = "0";
230 arg_ainfo.savedarginfo = cgiarginfo::can;
231 argsinfo.addarginfo (NULL, arg_ainfo);
232
233 // in this action "gt" controls the expand/contract
234 // text function 0 = not expanded, 1 = expand unless
235 // there are more than 10 sections containing text,
236 // 2 = expand all
237 arg_ainfo.shortname = "gt";
238 arg_ainfo.longname = "expand text";
239 arg_ainfo.multiplechar = false;
240 arg_ainfo.defaultstatus = cgiarginfo::weak;
241 arg_ainfo.argdefault = "0";
242 arg_ainfo.savedarginfo = cgiarginfo::can;
243 argsinfo.addarginfo (NULL, arg_ainfo);
244
245 // in this action "gp" is the "go to page" control
246 // used by the Book type of toc
247 arg_ainfo.shortname = "gp";
248 arg_ainfo.longname = "go to page";
249 arg_ainfo.multiplechar = true;
250 arg_ainfo.defaultstatus = cgiarginfo::none;
251 arg_ainfo.argdefault = "";
252 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
253 argsinfo.addarginfo (NULL, arg_ainfo);
254
255 // in this action "hl" is the "highlighting on/
256 // highlighting off control
257 arg_ainfo.shortname = "hl";
258 arg_ainfo.longname = "highlighting on/off";
259 arg_ainfo.multiplechar = false;
260 arg_ainfo.defaultstatus = cgiarginfo::weak;
261 arg_ainfo.argdefault = "1";
262 arg_ainfo.savedarginfo = cgiarginfo::must;
263 argsinfo.addarginfo (NULL, arg_ainfo);
264
265 // "x" is 0 normally or 1 if page
266 // has been "detached"
267 arg_ainfo.shortname = "x";
268 arg_ainfo.longname = "detached page";
269 arg_ainfo.multiplechar = false;
270 arg_ainfo.defaultstatus = cgiarginfo::weak;
271 arg_ainfo.argdefault = "0";
272 arg_ainfo.savedarginfo = cgiarginfo::must;
273 argsinfo.addarginfo (NULL, arg_ainfo);
274
275 // f arg is set to 1 if document is to
276 // be displayed in a frame
277 arg_ainfo.shortname = "f";
278 arg_ainfo.longname = "frame";
279 arg_ainfo.multiplechar = false;
280 arg_ainfo.defaultstatus = cgiarginfo::weak;
281 arg_ainfo.argdefault = "0";
282 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
283 argsinfo.addarginfo (NULL, arg_ainfo);
284
285 // fc arg is "1" if search bar is to be included (i.e. if "fc" == 1
286 // the httpdocument macro will include "&f=1"
287 arg_ainfo.shortname = "fc";
288 arg_ainfo.longname = "include search bar";
289 arg_ainfo.multiplechar = false;
290 arg_ainfo.defaultstatus = cgiarginfo::weak;
291 arg_ainfo.argdefault = "1";
292 arg_ainfo.savedarginfo = cgiarginfo::must;
293 argsinfo.addarginfo (NULL, arg_ainfo);
294}
295
296documentaction::~documentaction () {
297}
298
299bool documentaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
300 ostream &logout) {
301
302 // check gc argument
303 int arg_gc = args.getintarg("gc");
304 if (arg_gc != 0 && arg_gc != 1) {
305 logout << "Warning: \"gc\" argument out of range (" << arg_gc << ")\n";
306 cgiarginfo *gcinfo = argsinfo.getarginfo ("gc");
307 if (gcinfo != NULL) args["gc"] = gcinfo->argdefault;
308 }
309
310 // check gt argument (may be either 0, 1 or 2)
311 int arg_gt = args.getintarg("gt");
312 if (arg_gt != 0 && arg_gt != 1 && arg_gt != 2) {
313 logout << "Warning: \"gt\" argument out of range (" << arg_gt << ")\n";
314 cgiarginfo *gtinfo = argsinfo.getarginfo ("gt");
315 if (gtinfo != NULL) args["gt"] = gtinfo->argdefault;
316 }
317
318 // check hl argument
319 int arg_hl = args.getintarg("hl");
320 if (arg_hl != 0 && arg_hl != 1) {
321 logout << "Warning: \"hl\" argument out of range (" << arg_hl << ")\n";
322 cgiarginfo *hlinfo = argsinfo.getarginfo ("hl");
323 if (hlinfo != NULL) args["hl"] = hlinfo->argdefault;
324 }
325
326 // check x argument
327 int arg_x = args.getintarg("x");
328 if (arg_x != 0 && arg_x != 1) {
329 logout << "Warning: \"x\" argument out of range (" << arg_x << ")\n";
330 cgiarginfo *xinfo = argsinfo.getarginfo ("x");
331 if (xinfo != NULL) args["x"] = xinfo->argdefault;
332 }
333
334 return true;
335}
336
337void documentaction::get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
338 response_t &response,text_t &response_data,
339 ostream &logout) {
340
341 if ((args["il"] == "w") && (!args["d"].empty())) {
342
343 recptproto* collectproto = protos->getrecptproto (args["c"], logout);
344 if (collectproto != NULL) {
345
346 text_tset metadata;
347 FilterResponse_t filt_response;
348 text_t top;
349
350 metadata.insert ("URL");
351
352 // get metadata for parent document
353 get_top (args["d"], top);
354 if (get_info (top, args["c"], metadata, false, collectproto, filt_response, logout)) {
355 text_t url = filt_response.docInfo[0].metadata["URL"].values[0];
356
357 response = location;
358 response_data = url;
359 return;
360 } else {
361 // error, no URL
362 logout << "Error: documentaction::get_cgihead_info failed on get_info" << endl;
363 }
364 }
365 }
366 response = content;
367 response_data = "text/html";
368}
369
370// set_widthtspace calculates how wide the spaces in the nav bar should
371// be and sets the appropriate macro
372void documentaction::set_spacemacro (displayclass &disp, FilterResponse_t &response) {
373
374 text_t width;
375 int twidth, swidth, iwidth = 0;
376
377 int numc = response.docInfo.size();
378 ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
379 ResultDocInfo_tarray::iterator docend = response.docInfo.end();
380
381 disp.expandstring ("Global", "_pagewidth_", width);
382 twidth = width.getint();
383
384 disp.expandstring ("query", "_searchwidth_", width);
385 iwidth += width.getint();
386
387
388
389 while (dochere != docend) {
390 const text_t &title = (*dochere).metadata["Title"].values[0];
391
392 disp.expandstring ("document", "_" + title + "width_", width);
393 if (width == ("_" + title + "width_"))
394 disp.expandstring ("document", "_defaultwidth_", width);
395 iwidth += width.getint();
396 dochere ++;
397 }
398 if ((twidth - iwidth) < numc) swidth = 2;
399 else {
400 swidth = twidth - iwidth;
401 if (numc > 0) swidth = swidth / numc;
402 }
403 disp.setmacro ("widthtspace", "Global", swidth);
404}
405
406// set_navbarmacros sets _navigationbar_, _javaimagesnavbar_ and _httpbrowseXXX_ macros
407// reponse contains 1 metadata field (Title)
408void documentaction::set_navbarmacros (displayclass &disp, FilterResponse_t &response,
409 cgiargsclass &args) {
410
411 text_t javaimagesnavbar, topparent;
412 text_t &arg_d = args["d"];
413 text_t navigationbar = "<!-- Navigation Bar -->\n";
414
415 get_top (args["cl"], topparent);
416 int numc = response.docInfo.size();
417 ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
418 ResultDocInfo_tarray::iterator docend = response.docInfo.end();
419
420 navigationbar += "<nobr>\n";
421 if (args["a"] == "q") {
422 navigationbar += "_icontabsearchgreen_";
423 } else {
424 navigationbar += "_imagesearch_";
425 javaimagesnavbar = "_javasearch_";
426 }
427
428
429 if (numc == 0) navigationbar += "_imagespacer_";
430
431 while (dochere != docend) {
432 text_t title = (*dochere).metadata["Title"].values[0];
433
434 bool unknown = false;
435
436 // test the _XXXwidth_ macro to see if image macros are
437 // defined for this type of classification - if not we'll
438 // just display the text
439 text_t tmpwidth;
440 disp.expandstring ("document", "_" + title + "width_", tmpwidth);
441 if (tmpwidth == ("_" + title + "width_")) unknown = true;
442
443 // if we're inside a document all the classification buttons should be enabled
444 if (arg_d.empty() && ((*dochere).OID == topparent)) {
445 if (unknown) navigationbar += "_imagespacer_&nbsp;" + title + "&nbsp;";
446 else navigationbar += "_imagespacer__icontab" + title + "green_";
447 } else {
448
449 // set the _httpbrowseXXX_ macro for this classification
450 if (unknown) navigationbar += "_imagespacer_&nbsp;<a href=\"_httpdocument_&cl=" +
451 (*dochere).OID + "\">" + title + "</a>&nbsp;";
452 else {
453 navigationbar += "_imagespacer__image" + title + "_";
454 disp.setmacro ("httpbrowse" + title, "Global", "_httpdocument_&cl=" + (*dochere).OID);
455 }
456 }
457 if (!unknown) javaimagesnavbar += "_java" + title + "_";
458 dochere ++;
459 }
460 navigationbar += "\n</nobr>\n";
461 navigationbar += "<!-- End of Navigation Bar -->\n";
462 disp.setmacro ("navigationbar", "Global", navigationbar);
463 if (args.getintarg("v") == 0)
464 disp.setmacro ("javaimagesnavbar", "Global", javaimagesnavbar);
465}
466
467// define all the macros which might be used by other actions
468// to produce pages.
469void documentaction::define_external_macros (displayclass &disp, cgiargsclass &args,
470 recptprotolistclass *protos, ostream &logout) {
471
472 // define_external_macros sets the following macros:
473
474 // _navigationbar_ this is the navigation bar containing the search button
475 // and any classification buttons - it goes at the top of
476 // most pages. for now we're assuming that there'll always
477 // be a search button - we should probably check that there
478 // is a query action before making this assumption
479
480 // _httpbrowseXXX_ the http macros for each classification (i.e. if there
481 // are Title and Creator classifications _httpbrowseTitle_
482 // and _httpbrowseCreator_ will be set
483
484 // _javaimagesnavbar_ this is the javascript code to shove in to make the
485 // flashy images used by _navigationbar_ work
486
487 // _widthtspace_ the width of the spacers between buttons in navigation
488 // bar
489
490 // _httpdocument_ has '&f=1' added if displaying document inside a frame
491
492 // _gsdltop_ macro to replace _top targets with
493
494 // _httppagehome_ overridden home url if html collections have own homepage
495
496 // must have a valid collection server to continue
497 text_t &collection = args["c"];
498 if (collection.empty()) return;
499 recptproto *collectproto = protos->getrecptproto (collection, logout);
500 if (collectproto == NULL) return;
501
502 outconvertclass text_t2ascii;
503 comerror_t err;
504 InfoFiltersResponse_t filterinfo;
505 FilterResponse_t response;
506 text_tset metadata;
507
508
509 // get info on current collection and load up formatinfo
510 // I'd prefer not to do this here as we're getting
511 // collection info every time (and probably also getting
512 // it in other places some of the time) - One day I'll
513 // fix it ... maybe - Stefan.
514 ColInfoResponse_t cinfo;
515 collectproto->get_collectinfo (collection, cinfo, err, logout);
516 load_formatinfo (cinfo.format, args.getintarg("gt"));
517
518 if (formatinfo.DocumentUseHTML) {
519
520 // frame stuff
521 if (args["fc"] == "1") {
522 text_t httpdocument;
523 disp.expandstring ("Global", "_httpdocument_", httpdocument);
524 httpdocument += "&f=1";
525 disp.setmacro ("httpdocument", "Global", httpdocument);
526 disp.setmacro ("gsdltop", "Global", "documenttop");
527 }
528 text_tmap::iterator it = cinfo.format.find ("homepage");
529 if (it != cinfo.format.end()) {
530 text_t httppagehome;
531 if (get_link (args, protos, (*it).second, httppagehome, logout))
532 disp.setmacro ("httppagehome", "Global", httppagehome);
533 }
534 }
535
536 // don't want navigation bar if page is 'detached'
537 if (!args.getintarg("x")) {
538
539 collectproto->get_filterinfo (collection, filterinfo, err, logout);
540 if (err == noError) {
541 // check that there's a browse filter
542 if (filterinfo.filterNames.find ("BrowseFilter") != filterinfo.filterNames.end()) {
543
544 metadata.insert ("Title");
545 bool getParents = false;
546 get_children ("", collection, metadata, getParents, collectproto, response, logout);
547
548 // calculate width of spacers and set _widthtspace_ macro
549 if (args.getintarg("v") == 0) set_spacemacro (disp, response);
550
551 // set _navigationbar_ and _javaimagesnavbar_ macros
552 set_navbarmacros (disp, response, args);
553
554 }
555 } else {
556 logout << text_t2ascii
557 << "Error (documentaction::define_external_macros()) in call to get_filterinfo() "
558 << get_comerror_string (err);
559 }
560 }
561}
562
563bool documentaction::get_link (cgiargsclass &args, recptprotolistclass *protos,
564 const text_t &inlink, text_t &outlink, ostream &logout) {
565
566 FilterResponse_t response;
567 text_tset metadata;
568 metadata.insert ("section");
569
570 // check current collection first
571 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
572
573 if (get_info (inlink, args["c"], metadata, false, collectproto, response, logout)) {
574 if (!response.docInfo[0].metadata["section"].values[0].empty()) {
575 outlink = "_httpdocument_&d=" + response.docInfo[0].metadata["section"].values[0];
576 return true;
577 }
578 }
579
580 // check all the other enabled collections
581
582 if (args["ccs"] == "1" && !args["cc"].empty()) {
583 text_tarray collections;
584 splitchar (args["cc"].begin(), args["cc"].end(), ',', collections);
585
586 text_tarray::const_iterator col_here = collections.begin();
587 text_tarray::const_iterator col_end = collections.end();
588
589 while (col_here != col_end) {
590
591 // don't need to check current collection again
592 if (*col_here == args["c"]) {col_here ++; continue;}
593
594 collectproto = protos->getrecptproto (*col_here, logout);
595
596 if (get_info (inlink, *col_here, metadata, false, collectproto, response, logout)) {
597 if (!response.docInfo[0].metadata["section"].values[0].empty()) {
598 outlink = "_httpdocument_&c=" + *col_here + "&d=" +
599 response.docInfo[0].metadata["section"].values[0];
600 return true;
601 }
602 }
603 col_here ++;
604 }
605 }
606 return false;
607}
608
609void documentaction::load_formatinfo (const text_tmap &colformat, int gt) {
610
611 formatinfo.clear();
612 text_tmap::const_iterator format_here = colformat.begin();
613 text_tmap::const_iterator format_end = colformat.end();
614
615 while (format_here != format_end) {
616 if (((*format_here).first == "DocumentImages") &&
617 ((*format_here).second == "true"))
618 formatinfo.DocumentImages = true;
619 else if (((*format_here).first == "DocumentTitles") &&
620 ((*format_here).second == "false"))
621 formatinfo.DocumentTitles = false;
622 else if ((*format_here).first == "DocumentHeading")
623 formatinfo.DocumentHeading = (*format_here).second;
624 else if (((*format_here).first == "DocumentContents") &&
625 ((*format_here).second == "false"))
626 formatinfo.DocumentContents = false;
627 else if (((*format_here).first == "DocumentArrowsBottom") &&
628 ((*format_here).second == "false"))
629 formatinfo.DocumentArrowsBottom = false;
630 else if ((*format_here).first == "DocumentButtons")
631 splitchar ((*format_here).second.begin(), (*format_here).second.end(),
632 '|', formatinfo.DocumentButtons);
633 else if ((*format_here).first == "DocumentText")
634 formatinfo.DocumentText = (*format_here).second;
635 else if (((*format_here).first == "DocumentUseHTML") &&
636 ((*format_here).second == "true"))
637 formatinfo.DocumentUseHTML = true;
638 else
639 formatinfo.formatstrings[(*format_here).first] = (*format_here).second;
640
641 format_here ++;
642 }
643
644 // never want arrows when text is expanded
645 if (gt) formatinfo.DocumentArrowsBottom = false;
646}
647
648void documentaction::set_java_macros (cgiargsclass &args, displayclass &disp) {
649
650 text_t javaimagescontent = "_javaextras_";
651
652 int arg_gt = args.getintarg("gt");
653 int arg_gc = args.getintarg("gc");
654 int arg_hl = args.getintarg("hl");
655
656 text_tarray::const_iterator button_here = formatinfo.DocumentButtons.begin();
657 text_tarray::const_iterator button_end = formatinfo.DocumentButtons.end();
658
659 while (button_here != button_end) {
660 if (*button_here == "Detach")
661 javaimagescontent += "_javadetach_";
662 else if (*button_here == "Expand Text") {
663 if (arg_gt == 1)
664 javaimagescontent += "_javacontracttext__javacontinue_";
665 else if (arg_gt == 2)
666 javaimagescontent += "_javacontracttext_";
667 else
668 javaimagescontent += "_javaexpandtext_";
669 } else if (*button_here == "Expand Contents") {
670 if (arg_gc == 1)
671 javaimagescontent += "_javacontractcontents_";
672 else
673 javaimagescontent += "_javaexpandcontents_";
674 } else if (*button_here == "Highlight") {
675 if (arg_hl == 1)
676 javaimagescontent += "_javanohighlighting_";
677 else
678 javaimagescontent += "_javahighlighting_";
679 }
680 button_here ++;
681 }
682 disp.setmacro ("javaimagescontent", "document", javaimagescontent);
683}
684
685
686// define all the macros which are related to pages generated
687// by this action. we also load up the formatinfo structure
688// here (it's used in do_action as well as here)
689void documentaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
690 recptprotolistclass *protos, ostream &logout) {
691
692 // define_internal_macros sets the following macros:
693
694 // _pagetitle_ the title to be displayed at the top of the browser window
695
696 // _imagethispage_ the title image to be displayed at top right of page
697
698 // _navarrows_ this may be overridden to "" when format option
699 // DocumentArrowsBottom is false
700
701 // _header_ the header macro is overridden if we're not at a top level
702 // classification to remove the title block
703
704 // _javaimagescontent_ this is the javascript code to shove in to make the
705 // flashy buttons work
706
707 // _thisOID_ the OID (directory) of the current document - this corresponds
708 // to the archivedir metadata element
709
710 // must have a valid collection server to continue
711 text_t &collection = args["c"];
712 if (collection.empty()) return;
713 recptproto *collectproto = protos->getrecptproto (collection, logout);
714 if (collectproto == NULL) return;
715
716 text_tset metadata;
717 FilterResponse_t response;
718 text_t &arg_d = args["d"];
719 text_t &arg_cl = args["cl"];
720
721 if (!formatinfo.DocumentArrowsBottom)
722 disp.setmacro("navarrows", "document", "");
723
724 metadata.insert ("Title");
725
726 bool fulltoc = false;
727
728 if (args["cl"] != "search") {
729 // see if there's a FullTOC string
730 text_t cl_top, full_toc;
731 get_top (arg_cl, cl_top);
732 if (get_formatstring (cl_top, "FullTOC", formatinfo.formatstrings, full_toc))
733 if (full_toc == "true") fulltoc = true;
734 }
735
736 if (!arg_d.empty() && !fulltoc) {
737 // we're at document level
738
739 metadata.insert ("archivedir");
740
741 // get metadata for this document and it's parents
742 if (get_info (arg_d, collection, metadata, true, collectproto, response, logout)) {
743 disp.setmacro ("header", "document", "_textheader_");
744
745 text_tarray pagetitlearray;
746 if (!response.docInfo[0].metadata["Title"].values[0].empty())
747 pagetitlearray.push_back (response.docInfo[0].metadata["Title"].values[0]);
748 if (args["gt"] != "1") {
749 MetadataInfo_t *parenttitle = response.docInfo[0].metadata["Title"].parent;
750 while (parenttitle != NULL) {
751 if (!parenttitle->values[0].empty())
752 pagetitlearray.push_back (parenttitle->values[0]);
753 parenttitle = parenttitle->parent;
754 }
755 }
756 reverse (pagetitlearray.begin(), pagetitlearray.end());
757 text_t pagetitle;
758 joinchar (pagetitlearray, ": ", pagetitle);
759 disp.setmacro ("pagetitle", "document", pagetitle);
760
761 if (is_top (arg_d))
762 disp.setmacro ("thisOID", "Global", dm_safe(response.docInfo[0].metadata["archivedir"].values[0]));
763 else {
764 MetadataInfo_t *parentad = response.docInfo[0].metadata["archivedir"].parent;
765 text_t thisOID;
766 while (parentad != NULL) {
767 thisOID = parentad->values[0];
768 parentad = parentad->parent;
769 }
770 disp.setmacro ("thisOID", "Global", dm_safe(thisOID));
771 }
772
773 if (args["u"] != "1")
774 set_java_macros (args, disp);
775
776 }
777 } else {
778 if (!arg_cl.empty()) {
779
780 // get metadata for top level classification
781 text_t classtop;
782 get_top (arg_cl, classtop);
783 if (get_info (classtop, collection, metadata, false, collectproto, response, logout)) {
784
785 text_t &title = response.docInfo[0].metadata["Title"].values[0];
786 bool unknown = false;
787
788 // test the _XXXwidth_ macro to see if image macros are
789 // defined for this type of classification - if not we'll
790 // just display the text
791 text_t tmp;
792 disp.expandstring ("document", "_" + title + "width_", tmp);
793 if (tmp == ("_" + title + "width_")) unknown = true;
794
795 if (unknown) {
796 disp.setmacro ("pagetitle", "document", title);
797 disp.setmacro ("imagethispage", "document", "<h2>" + title + "</h2>");
798 } else {
799 disp.setmacro ("pagetitle", "document", "_text" + title + "page_");
800 disp.setmacro ("imagethispage", "document", "_icon" + title + "page_");
801 }
802 }
803 }
804 }
805}
806
807
808bool documentaction::do_action (cgiargsclass &args, recptprotolistclass *protos,
809 browsermapclass *browsers, displayclass &disp,
810 outconvertclass &outconvert, ostream &textout,
811 ostream &logout) {
812
813
814 // must have a valid collection server
815 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
816 if (collectproto == NULL) {
817 logout << "documentaction::do_action called with NULL collectproto\n";
818 textout << outconvert << disp << "_document:header_\n"
819 << "Error: Attempt to get document without setting collection\n"
820 << "_document:footer_\n";
821 } else {
822
823 text_t OID = args["d"];
824 if (OID.empty()) OID = args["cl"];
825 if (OID.empty()) {
826 textout << outconvert << disp << "Document contains no data_document:footer_\n";
827 return true;
828 }
829
830 if (formatinfo.DocumentUseHTML) {
831
832 if (!args["d"].empty()) {
833 if (args["f"] == "1") {
834 textout << outconvert << disp
835 << "<html><head></head>\n"
836 << "<frameset rows=\"68,*\" noresize border=0>\n"
837 << "<frame scrolling=no frameborder=0 src=\"_gwcgi_?e=_compressedoptions_&a=p&p=nav\">\n"
838 << "<frame name=\"documenttop\" frameborder=0 src=\"_gwcgi_?e=_compressedoptions_&a=d&d="
839 << args["d"] << "\">"
840 << "<noframes>\n"
841 << "<p>You must have a frame enabled browser to view this.</p>\n"
842 << "</noframes>\n"
843 << "</frameset>\n"
844 << "</html>\n";
845 } else {
846 output_document (OID, args, collectproto, disp, outconvert, textout, logout);
847 }
848 return true;
849 }
850 }
851
852 textout << outconvert << disp << "_document:header_\n"
853 << "_document:content_\n";
854
855 // output the table of contents
856 output_toc (args, browsers, formatinfo, collectproto,
857 disp, outconvert, textout, logout);
858
859 // output the document text
860 textout << "<p>\n";
861 output_document (OID, args, collectproto, disp, outconvert, textout, logout);
862
863 textout << outconvert << disp << "_document:footer_\n";
864 }
865 return true;
866}
867
868void documentaction::output_text (ResultDocInfo_t &docinfo, format_t *formatlistptr,
869 const TermInfo_tarray &terminfo, const text_t &OID,
870 bool highlight, int hastxt, int wanttext,
871 text_t &collection, recptproto *collectproto,
872 displayclass &disp, outconvertclass &outconvert,
873 ostream &textout, ostream &logout) {
874
875 DocumentRequest_t docrequest;
876 DocumentResponse_t docresponse;
877 comerror_t err;
878
879 if (hastxt == 1) {
880
881 if (wanttext) {
882 // get the text
883 docrequest.OID = OID;
884 collectproto->get_document (collection, docrequest, docresponse, err, logout);
885
886 // cut down on overhead by not using formattools if we only want the text
887 // (wanttext will equal 2 if we want text and other stuff too)
888 if (wanttext == 1)
889 if (highlight)
890 highlighttext(docresponse.doc, terminfo, disp, outconvert, textout, logout);
891 else
892 textout << outconvert << disp << docresponse.doc;
893 }
894
895 if (wanttext != 1) {
896 text_t doctext = get_formatted_string (docinfo, formatlistptr, docresponse.doc);
897
898 if (highlight)
899 highlighttext(doctext, terminfo, disp, outconvert, textout, logout);
900 else
901 textout << outconvert << disp << doctext;
902 }
903 }
904}
905
906
907void documentaction::output_document (const text_t &OID, cgiargsclass &args,
908 recptproto *collectproto, displayclass &disp,
909 outconvertclass &outconvert, ostream &textout,
910 ostream &logout) {
911 FilterResponse_t inforesponse;
912 FilterResponse_t queryresponse;
913 text_tset metadata;
914 bool getParents = false;
915 bool highlight = false;
916 int wanttext = 0;
917 int arg_gt = args.getintarg("gt");
918 text_t &collection = args["c"];
919
920 // if we have a query string and highlighting is turned on we need
921 // to redo the query to get the terms for highlighting
922 if (!args["q"].empty() && args.getintarg("hl")) {
923 FilterRequest_t request;
924 comerror_t err;
925 request.filterResultOptions = FRmatchTerms;
926 text_t formattedstring = args["q"];
927 format_querystring (formattedstring, args.getintarg("b"));
928 set_queryfilter_options (request, formattedstring, args);
929 collectproto->filter (args["c"], request, queryresponse, err, logout);
930 if (err != noError) {
931 outconvertclass text_t2ascii;
932 logout << text_t2ascii
933 << "documentaction::output_document: call to QueryFilter failed "
934 << "for " << args["c"] << " collection (" << get_comerror_string (err) << ")\n";
935 highlight = false;
936 } else {
937 highlight = true;
938 }
939 }
940
941 format_t *formatlistptr = new format_t();
942 parse_formatstring (formatinfo.DocumentText, formatlistptr, metadata, getParents);
943
944 metadata.insert ("hastxt");
945 metadata.insert ("haschildren");
946
947 if (formatinfo.DocumentText == "[Text]")
948 wanttext = 1;
949 else {
950 char *docformat = formatinfo.DocumentText.getcstr();
951 if (strstr (docformat, "[Text]") != NULL)
952 wanttext = 2;
953 delete docformat;
954 }
955
956 if (get_info (OID, collection, metadata, getParents, collectproto, inforesponse, logout)) {
957 int hastxt = inforesponse.docInfo[0].metadata["hastxt"].values[0].getint();
958 int haschildren = inforesponse.docInfo[0].metadata["haschildren"].values[0].getint();
959
960 if (arg_gt == 0) {
961 output_text (inforesponse.docInfo[0], formatlistptr, queryresponse.termInfo,
962 OID, highlight, hastxt, wanttext, collection, collectproto,
963 disp, outconvert, textout, logout);
964
965
966 } else {
967
968 ResultDocInfo_t thisdocinfo = inforesponse.docInfo[0];
969
970 // text is to be expanded
971 text_t exOID = OID;
972 if (haschildren != 1) exOID = get_parent (OID);
973 if (exOID.empty()) exOID = OID;
974
975 // if we're not in a document (i.e. we're in a top level classification)
976 // we need to pass "is_classify = true" to get_contents so that it
977 // doesn't recurse all the way through each document in the classification
978 bool is_classify = false;
979 if (args["d"].empty()) is_classify = true;
980
981 get_contents (exOID, is_classify, metadata, collection,
982 collectproto, inforesponse, logout);
983
984 ResultDocInfo_tarray::iterator sechere = inforesponse.docInfo.begin();
985 ResultDocInfo_tarray::iterator secend = inforesponse.docInfo.end();
986
987 if (arg_gt == 1) {
988 // check if there are more than 10 sections containing text to be expanded -
989 // if there are output warning message - this isn't a great way to do this
990 // since the sections may be very large or very small - one day I'll fix it
991 // -- Stefan.
992 int seccount = 0;
993 while (sechere != secend) {
994 int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
995 if (shastxt == 1) seccount ++;
996 if (seccount > 10) break;
997 sechere ++;
998 }
999 if (seccount > 10) {
1000 // more than 10 sections so output warning message and text
1001 // for current section only
1002 textout << outconvert << disp << "_document:textltwarning_";
1003
1004 output_text (thisdocinfo, formatlistptr, queryresponse.termInfo,
1005 OID, highlight, hastxt, wanttext, collection,
1006 collectproto, disp, outconvert, textout, logout);
1007
1008 }
1009 else arg_gt = 2;
1010 }
1011
1012 if (arg_gt == 2) {
1013 // get the text for each section
1014 sechere = inforesponse.docInfo.begin();
1015 int count = 0;
1016 while (sechere != secend) {
1017 textout << outconvert << disp << "\n<p><a name=" << count << "></a>\n";
1018
1019 int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
1020
1021 output_text (*sechere, formatlistptr, queryresponse.termInfo,
1022 (*sechere).OID, highlight, shastxt, wanttext, collection,
1023 collectproto, disp, outconvert, textout, logout);
1024 count ++;
1025 sechere ++;
1026 }
1027 }
1028 }
1029 }
1030 delete formatlistptr;
1031}
1032
1033// highlighttext highlights query terms in text string and outputs the resulting text string
1034void documentaction::highlighttext(text_t &text, const TermInfo_tarray &terms,
1035 displayclass &disp, outconvertclass &outconvert,
1036 ostream &textout, ostream &/*logout*/) {
1037
1038 text_tmap allterms;
1039 text_tmap::const_iterator it;
1040
1041 // first load all the term variations into a map
1042 TermInfo_tarray::const_iterator this_term = terms.begin();
1043 TermInfo_tarray::const_iterator last_term = terms.end();
1044 while (this_term != last_term) {
1045 text_tarray::const_iterator this_var = (*this_term).matchTerms.begin();
1046 text_tarray::const_iterator last_var = (*this_term).matchTerms.end();
1047 while (this_var != last_var) {
1048 allterms[*this_var] = 1;
1049 this_var ++;
1050 }
1051 this_term ++;
1052 }
1053
1054 // get the text to start and end a hightlight
1055 text_t starthighlight = "<b><u>";
1056 text_t endhighlight = "</u></b>";
1057 if (disp.isdefaultmacro("Global", "starthighlight"))
1058 disp.expandstring("Global", "_starthighlight_", starthighlight);
1059 if (disp.isdefaultmacro("Global", "endhighlight"))
1060 disp.expandstring("Global", "_endhighlight_", endhighlight);
1061
1062
1063 text_t::iterator here = text.begin();
1064 text_t::iterator end = text.end();
1065 text_t word, buffer;
1066 while (here != end) {
1067 if (is_unicode_letdig(*here)) {
1068 // not word boundary
1069 word.push_back(*here);
1070 here++;
1071
1072 } else {
1073 // found word boundary
1074 // add last word if there was one
1075 if (!word.empty()) {
1076 it = allterms.find(word);
1077 if (it != allterms.end()) {
1078 word = starthighlight + word + endhighlight;
1079 }
1080 buffer += word;
1081 word.clear();
1082 }
1083
1084 if (*here == '<') {
1085 // skip over rest of html tag
1086 while ((here != end) && (*here != '>')) {
1087 buffer.push_back(*here);
1088 here++;
1089 }
1090 }
1091
1092 buffer.push_back(*here);
1093 here++;
1094
1095 if (buffer.size() > 1024) {
1096 textout << outconvert << disp << buffer;
1097 buffer.clear();
1098 }
1099 }
1100 }
1101 textout << outconvert << disp << buffer;
1102}
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
Note: See TracBrowser for help on using the repository browser.