source: trunk/gsdl/src/recpt/queryaction.cpp@ 1270

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

Receptionist now caches collection information to avoid making multiple
get_collectinfo calls to collection server

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 41.7 KB
Line 
1/**********************************************************************
2 *
3 * queryaction.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: queryaction.cpp 1270 2000-07-05 21:49:36Z sjboddie $
25 *
26 *********************************************************************/
27
28/*
29 $Log$
30 Revision 1.37 2000/07/05 21:49:34 sjboddie
31 Receptionist now caches collection information to avoid making multiple
32 get_collectinfo calls to collection server
33
34 Revision 1.36 2000/02/21 21:57:48 sjboddie
35 actions are now configured with gsdlhome
36
37 Revision 1.35 2000/02/17 02:35:04 sjboddie
38 tidied up search history stuff a bit - replaced strings with macros
39
40 Revision 1.34 2000/02/15 22:53:52 kjm18
41 search history stuff added.
42
43 Revision 1.33 2000/01/24 22:57:59 sjboddie
44 fixed bug in cross-collection searching, tidied up a bit
45
46 Revision 1.32 1999/12/13 02:54:11 davidb
47 Support for cross collection searching (CCS)
48
49 Revision 1.31 1999/12/05 21:22:33 sjboddie
50 tidied up cross-collection searching a bit
51
52 Revision 1.30 1999/11/08 20:26:37 sjboddie
53 added multiplevalue option to cgiarginfo
54
55 Revision 1.29 1999/11/04 20:29:53 sjboddie
56 small change to cross-collection searching
57
58 Revision 1.28 1999/11/03 22:49:50 sjboddie
59 A few changes to cross-collection searching for fao
60
61 Revision 1.27 1999/11/01 21:53:27 sjboddie
62 added cross-collection searching capability - still needs lots of
63 work but the basic functionality is there
64
65 Revision 1.26 1999/10/10 08:14:10 sjboddie
66 - metadata now returns mp rather than array
67 - redesigned browsing support (although it's not finished so
68 won't currently work ;-)
69
70 Revision 1.25 1999/09/24 04:49:39 sjboddie
71 fixed up the query selection boxes to display properly if there's only
72 a single index/sub-collection
73
74 Revision 1.24 1999/09/22 03:44:31 sjboddie
75 EndResults query filter option may now take '-1' for 'all'
76
77 Revision 1.23 1999/09/21 11:34:42 sjboddie
78 added Maxdocs queryfilter option which may be -1 for 'all'
79
80 Revision 1.22 1999/09/07 23:08:51 rjmcnab
81 removed some compiler warnings
82
83 Revision 1.21 1999/09/07 04:56:57 sjboddie
84 added GPL notice
85
86 Revision 1.20 1999/08/25 04:47:55 sjboddie
87 added advanced search option - other minor changes
88
89 Revision 1.19 1999/08/13 04:17:24 sjboddie
90 small change to do with new collection-level metadata
91
92 Revision 1.18 1999/08/10 22:46:33 sjboddie
93 changed format option result to QueryResults and added QueryLinks option
94
95 Revision 1.17 1999/07/30 02:24:42 sjboddie
96 added collectinfo argument to some functions
97
98 Revision 1.16 1999/07/19 00:16:58 sjboddie
99 no longer display documents that don't match all phrases in query string
100
101 Revision 1.15 1999/07/16 08:33:36 rjmcnab
102 Changed the logic for getting the results string slightly
103
104 Revision 1.14 1999/07/16 03:41:29 sjboddie
105 changed isApprox
106
107 Revision 1.13 1999/07/16 00:19:01 sjboddie
108 some changes to the way quoted queries are handled
109
110 Revision 1.12 1999/07/09 02:17:55 rjmcnab
111 Setting macros needed for a second query.
112
113 Revision 1.11 1999/07/07 06:13:10 rjmcnab
114 Added ability to combine two independant queries.
115
116 Revision 1.10 1999/07/07 05:49:35 sjboddie
117 had another crack at the format string code - created a new formattools
118 module. It can now handle {If} and {Or} statements although there's a
119 bug preventing nested if's and or's.
120
121 Revision 1.9 1999/07/01 22:48:46 sjboddie
122 had a go at getting a query result format string working
123
124 Revision 1.8 1999/06/27 22:02:11 sjboddie
125 author is added to queryresults if there is one
126
127 Revision 1.7 1999/06/26 01:10:18 rjmcnab
128 Made h, i, and n arguments saved in the compressed arguments.
129
130 Revision 1.6 1999/06/24 05:12:25 sjboddie
131 lots of small changes
132
133 Revision 1.5 1999/06/16 04:03:48 sjboddie
134 Now sets "cl" arg to "search" when going to a document from a search
135 results page. This allows the close book icon (in hierarchy toc) to
136 take you back to the results page if that's where you came from.
137 If you got to the document page somehow other than from a
138 classification or a search (i.e. if "cl" isn't set) then the close
139 book icon is disabled
140
141 Revision 1.4 1999/06/16 02:08:38 sjboddie
142 got queryaction working
143
144 Revision 1.3 1999/03/25 03:06:45 sjboddie
145
146 altered receptionist slightly so it now passes *collectproto to
147 define_internal_macros and define_external_macros - need it
148 for browseaction
149
150 Revision 1.2 1999/03/03 20:26:50 rjmcnab
151
152 Modified stuff.
153
154 Revision 1.1 1999/02/28 22:45:21 rjmcnab
155
156 Initial revision.
157
158 */
159
160
161#include "queryaction.h"
162#include "querytools.h"
163#include "formattools.h"
164#include "cgiutils.h"
165#include "OIDtools.h"
166//#include "infodbclass.h"
167#include "fileutil.h"
168#include "text_t.h"
169#include "historydb.h"
170
171void colinfo_t::clear () {
172 formatlistptr = NULL;
173 browserptr = NULL;
174}
175
176void QueryResult_t::clear() {
177 doc.clear();
178 collection.clear();
179}
180
181queryaction::queryaction () {
182
183 recpt = NULL;
184 num_phrases = 0;
185
186 // this action uses cgi variable "a"
187 cgiarginfo arg_ainfo;
188 arg_ainfo.shortname = "a";
189 arg_ainfo.longname = "action";
190 arg_ainfo.multiplechar = true;
191 arg_ainfo.defaultstatus = cgiarginfo::weak;
192 arg_ainfo.argdefault = "q";
193 arg_ainfo.savedarginfo = cgiarginfo::must;
194 argsinfo.addarginfo (NULL, arg_ainfo);
195
196 // "b" - 0 = simple, 1 = advanced
197 arg_ainfo.shortname = "b";
198 arg_ainfo.longname = "query mode";
199 arg_ainfo.multiplechar = false;
200 arg_ainfo.defaultstatus = cgiarginfo::weak;
201 arg_ainfo.argdefault = "0";
202 arg_ainfo.savedarginfo = cgiarginfo::must;
203 argsinfo.addarginfo (NULL, arg_ainfo);
204
205 // "h"
206 arg_ainfo.shortname = "h";
207 arg_ainfo.longname = "main index";
208 arg_ainfo.multiplechar = true;
209 arg_ainfo.defaultstatus = cgiarginfo::weak;
210 arg_ainfo.argdefault = "";
211 arg_ainfo.savedarginfo = cgiarginfo::must;
212 argsinfo.addarginfo (NULL, arg_ainfo);
213
214 // "h2"
215 arg_ainfo.shortname = "h2";
216 arg_ainfo.longname = "main index for second query";
217 arg_ainfo.multiplechar = true;
218 arg_ainfo.defaultstatus = cgiarginfo::weak;
219 arg_ainfo.argdefault = "";
220 arg_ainfo.savedarginfo = cgiarginfo::must;
221 argsinfo.addarginfo (NULL, arg_ainfo);
222
223 // "j"
224 arg_ainfo.shortname = "j";
225 arg_ainfo.longname = "sub collection index";
226 arg_ainfo.multiplechar = true;
227 arg_ainfo.defaultstatus = cgiarginfo::weak;
228 arg_ainfo.argdefault = "";
229 arg_ainfo.savedarginfo = cgiarginfo::must;
230 argsinfo.addarginfo (NULL, arg_ainfo);
231
232 // "j2"
233 arg_ainfo.shortname = "j2";
234 arg_ainfo.longname = "sub collection index for second query";
235 arg_ainfo.multiplechar = true;
236 arg_ainfo.defaultstatus = cgiarginfo::weak;
237 arg_ainfo.argdefault = "";
238 arg_ainfo.savedarginfo = cgiarginfo::must;
239 argsinfo.addarginfo (NULL, arg_ainfo);
240
241 // "n"
242 arg_ainfo.shortname = "n";
243 arg_ainfo.longname = "language index";
244 arg_ainfo.multiplechar = true;
245 arg_ainfo.defaultstatus = cgiarginfo::weak;
246 arg_ainfo.argdefault = "";
247 arg_ainfo.savedarginfo = cgiarginfo::must;
248 argsinfo.addarginfo (NULL, arg_ainfo);
249
250 // "n2"
251 arg_ainfo.shortname = "n2";
252 arg_ainfo.longname = "language index for second query";
253 arg_ainfo.multiplechar = true;
254 arg_ainfo.defaultstatus = cgiarginfo::weak;
255 arg_ainfo.argdefault = "";
256 arg_ainfo.savedarginfo = cgiarginfo::must;
257 argsinfo.addarginfo (NULL, arg_ainfo);
258
259 // "q"
260 arg_ainfo.shortname = "q";
261 arg_ainfo.longname = "query string";
262 arg_ainfo.multiplechar = true;
263 arg_ainfo.defaultstatus = cgiarginfo::weak;
264 arg_ainfo.argdefault = "";
265 arg_ainfo.savedarginfo = cgiarginfo::must;
266 argsinfo.addarginfo (NULL, arg_ainfo);
267
268 // "q2"
269 arg_ainfo.shortname = "q2";
270 arg_ainfo.longname = "query string for second query";
271 arg_ainfo.multiplechar = true;
272 arg_ainfo.defaultstatus = cgiarginfo::weak;
273 arg_ainfo.argdefault = "";
274 arg_ainfo.savedarginfo = cgiarginfo::must;
275 argsinfo.addarginfo (NULL, arg_ainfo);
276
277 // "cq2" ""=don't combine, "and", "or", "not"
278 arg_ainfo.shortname = "cq2";
279 arg_ainfo.longname = "combine queries";
280 arg_ainfo.multiplechar = true;
281 arg_ainfo.defaultstatus = cgiarginfo::weak;
282 arg_ainfo.argdefault = "";
283 arg_ainfo.savedarginfo = cgiarginfo::must;
284 argsinfo.addarginfo (NULL, arg_ainfo);
285
286 // "t" - 1 = ranked 0 = boolean
287 arg_ainfo.shortname = "t";
288 arg_ainfo.longname = "search type";
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 // "k"
296 arg_ainfo.shortname = "k";
297 arg_ainfo.longname = "casefolding";
298 arg_ainfo.multiplechar = false;
299 arg_ainfo.defaultstatus = cgiarginfo::weak;
300 arg_ainfo.argdefault = "1";
301 arg_ainfo.savedarginfo = cgiarginfo::must;
302 argsinfo.addarginfo (NULL, arg_ainfo);
303
304 // "s"
305 arg_ainfo.shortname = "s";
306 arg_ainfo.longname = "stemming";
307 arg_ainfo.multiplechar = false;
308 arg_ainfo.defaultstatus = cgiarginfo::weak;
309 arg_ainfo.argdefault ="0";
310 arg_ainfo.savedarginfo = cgiarginfo::must;
311 argsinfo.addarginfo (NULL, arg_ainfo);
312
313 // "m"
314 arg_ainfo.shortname = "m";
315 arg_ainfo.longname = "maximum number of documents";
316 arg_ainfo.multiplechar = true;
317 arg_ainfo.defaultstatus = cgiarginfo::weak;
318 arg_ainfo.argdefault = "50";
319 arg_ainfo.savedarginfo = cgiarginfo::must;
320 argsinfo.addarginfo (NULL, arg_ainfo);
321
322 // "o"
323 arg_ainfo.shortname = "o";
324 arg_ainfo.longname = "hits per page";
325 arg_ainfo.multiplechar = true;
326 arg_ainfo.defaultstatus = cgiarginfo::weak;
327 arg_ainfo.argdefault = "20";
328 arg_ainfo.savedarginfo = cgiarginfo::must;
329 argsinfo.addarginfo (NULL, arg_ainfo);
330
331 // "r"
332 arg_ainfo.shortname = "r";
333 arg_ainfo.longname = "start results from";
334 arg_ainfo.multiplechar = true;
335 arg_ainfo.defaultstatus = cgiarginfo::weak;
336 arg_ainfo.argdefault = "1";
337 arg_ainfo.savedarginfo = cgiarginfo::must;
338 argsinfo.addarginfo (NULL, arg_ainfo);
339
340 // "ccs"
341 arg_ainfo.shortname = "ccs";
342 arg_ainfo.longname = "cross collection searching";
343 arg_ainfo.multiplechar = false;
344 arg_ainfo.defaultstatus = cgiarginfo::weak;
345 arg_ainfo.argdefault = "0";
346 arg_ainfo.savedarginfo = cgiarginfo::must;
347 argsinfo.addarginfo (NULL, arg_ainfo);
348
349 // "ccp"
350 arg_ainfo.shortname = "ccp";
351 arg_ainfo.longname = "cross collection page";
352 arg_ainfo.multiplechar = false;
353 arg_ainfo.defaultstatus = cgiarginfo::weak;
354 arg_ainfo.argdefault = "0";
355 arg_ainfo.savedarginfo = cgiarginfo::must;
356 argsinfo.addarginfo (NULL, arg_ainfo);
357
358 // "cc"
359 arg_ainfo.shortname = "cc";
360 arg_ainfo.longname = "collections to search";
361 arg_ainfo.multiplechar = true;
362 arg_ainfo.multiplevalue = true;
363 arg_ainfo.defaultstatus = cgiarginfo::weak;
364 arg_ainfo.argdefault = "";
365 arg_ainfo.savedarginfo = cgiarginfo::must;
366 argsinfo.addarginfo (NULL, arg_ainfo);
367
368 // "hd" history display - search history only displayed when
369 // this var set.
370 arg_ainfo.shortname = "hd";
371 arg_ainfo.longname = "history display";
372 arg_ainfo.multiplechar = false;
373 arg_ainfo.multiplevalue = false;
374 arg_ainfo.defaultstatus = cgiarginfo::weak;
375 arg_ainfo.argdefault = "0";
376 arg_ainfo.savedarginfo = cgiarginfo::must;
377 argsinfo.addarginfo (NULL, arg_ainfo);
378
379
380 // "hs" save - set to 1 in query form, so only save when submit
381 // query
382 // 0 = no save 1 = save
383 arg_ainfo.shortname = "hs";
384 arg_ainfo.longname = "history save";
385 arg_ainfo.multiplechar = false;
386 arg_ainfo.defaultstatus = cgiarginfo::weak;
387 arg_ainfo.argdefault = "0";
388 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
389 argsinfo.addarginfo (NULL, arg_ainfo);
390
391
392 // "hcl" compress the list (show only the last 5)
393 // 0 = expand, 1 = compress
394
395 arg_ainfo.shortname = "hcl";
396 arg_ainfo.longname = "history compress list";
397 arg_ainfo.multiplechar = false;
398 arg_ainfo.defaultstatus = cgiarginfo::weak;
399 arg_ainfo.argdefault = "1";
400 arg_ainfo.savedarginfo = cgiarginfo::must;
401 argsinfo.addarginfo (NULL, arg_ainfo);
402
403
404
405}
406
407void queryaction::configure (const text_t &key, const text_tarray &cfgline) {
408 action::configure (key, cfgline);
409}
410
411bool queryaction::init (ostream &logout) {
412 return action::init (logout);
413}
414
415bool queryaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
416 ostream &logout) {
417
418 // check t argument
419 int arg_t = args.getintarg("t");
420 if (arg_t != 0 && arg_t != 1) {
421 logout << "Warning: \"t\" argument out of range (" << arg_t << ")\n";
422 cgiarginfo *tinfo = argsinfo.getarginfo ("t");
423 if (tinfo != NULL) args["t"] = tinfo->argdefault;
424 }
425
426 // check k argument
427 int arg_k = args.getintarg("k");
428 if (arg_k != 0 && arg_k != 1) {
429 logout << "Warning: \"k\" argument out of range (" << arg_k << ")\n";
430 cgiarginfo *kinfo = argsinfo.getarginfo ("k");
431 if (kinfo != NULL) args["k"] = kinfo->argdefault;
432 }
433
434 // check s argument
435 int arg_s = args.getintarg("s");
436 if (arg_s != 0 && arg_s != 1) {
437 logout << "Warning: \"s\" argument out of range (" << arg_s << ")\n";
438 cgiarginfo *sinfo = argsinfo.getarginfo ("s");
439 if (sinfo != NULL) args["s"] = sinfo->argdefault;
440 }
441
442 // check m argument
443 int arg_m = args.getintarg("m");
444 if (arg_m < -1) {
445 logout << "Warning: \"m\" argument less than -1 (" << arg_m << ")\n";
446 cgiarginfo *minfo = argsinfo.getarginfo ("m");
447 if (minfo != NULL) args["m"] = minfo->argdefault;
448 }
449
450 // check o argument
451 int arg_o = args.getintarg("o");
452 if (arg_o < -1) {
453 logout << "Warning: \"o\" argument less than -1 (" << arg_o << ")\n";
454 cgiarginfo *oinfo = argsinfo.getarginfo ("o");
455 if (oinfo != NULL) args["o"] = oinfo->argdefault;
456 }
457
458 // check r argument
459 int arg_r = args.getintarg("r");
460 if (arg_r < 1) {
461 logout << "Warning: \"r\" argument less than 1 (" << arg_r << ")\n";
462 cgiarginfo *rinfo = argsinfo.getarginfo ("r");
463 if (rinfo != NULL) args["r"] = rinfo->argdefault;
464 }
465 //check hd argument
466 int arg_hd = args.getintarg("hd");
467 if (arg_hd !=0 && arg_hd !=1) {
468 logout << "Warning: \"hd\" argument out of range (" << arg_hd << ")\n";
469 cgiarginfo *hdinfo = argsinfo.getarginfo ("hd");
470 if (hdinfo != NULL) args["hd"] = hdinfo->argdefault;
471 }
472 //check hs argument
473 int arg_hs = args.getintarg("hs");
474 if (arg_hs !=0 && arg_hs !=1) {
475 logout << "Warning: \"hs\" argument out of range (" << arg_hs << ")\n";
476 cgiarginfo *hsinfo = argsinfo.getarginfo ("hs");
477 if (hsinfo != NULL) args["hs"] = hsinfo->argdefault;
478 }
479
480 // chech hcl argument
481 int arg_hcl = args.getintarg("hcl");
482 if (arg_hcl !=0 && arg_hcl !=1) {
483 logout << "Warning: \"hcl\" argument out of range (" << arg_hcl << ")\n";
484 cgiarginfo *hclinfo = argsinfo.getarginfo ("hcl");
485 if (hclinfo != NULL) args["hcl"] = hclinfo->argdefault;
486 }
487
488 return true;
489}
490
491void queryaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
492 response_t &response, text_t &response_data,
493 ostream &/*logout*/) {
494 response = content;
495 response_data = "text/html";
496}
497
498void queryaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
499 recptprotolistclass * /*protos*/,
500 ostream &/*logout*/) {
501
502 // define_internal_macros sets the following macros:
503
504 // _quotedquery_ the part of the query string that was quoted for post-processing
505
506
507
508 // The following macros are set later (in define_query_macros) as they can't be set until
509 // the query has been done.
510
511 // _freqmsg_ the term frequency string
512
513 // _resultline_ the "x documents matched the query" string
514
515 // _prevfirst_ these are used when setting up the links to previous/next
516 // _prevlast_ pages of results (_thisfirst_ and _thislast_ are used to set
517 // _nextfirst_ the 'results x-x for query: xxxx' string in the title bar)
518 // _nextlast_
519 // _thisfirst_
520 // _thislast_
521
522
523 // get the quoted bits of the query string and set _quotedquery_
524 text_tarray phrases;
525 get_phrases (args["q"], phrases);
526 num_phrases = phrases.size();
527 text_tarray::const_iterator phere = phrases.begin();
528 text_tarray::const_iterator pend = phrases.end();
529 bool first = true;
530 text_t quotedquery;
531 while (phere != pend) {
532 if (!first)
533 if ((phere +1) == pend) quotedquery += " and ";
534 else quotedquery += ", ";
535
536 quotedquery += "\"" + *phere + "\"";
537 first = false;
538 phere ++;
539 }
540 if (args.getintarg("s")) quotedquery += "_textstemon_";
541 disp.setmacro ("quotedquery", "query", quotedquery);
542}
543
544// sets the selection box macros _hselection_, _jselection_, and _nselection_.
545void queryaction::set_option_macro (const text_t &macroname, text_t current_value,
546 const FilterOption_t &option, displayclass &disp) {
547
548 if (option.validValues.empty()) return;
549 else if (option.validValues.size() == 1) {
550 disp.setmacro (macroname + "selection", "Global", "_" + option.defaultValue + "_");
551 return;
552 }
553 if (option.validValues.size() < 2) return;
554
555 text_t macrovalue = "<select name=\"" + macroname + "\">\n";
556
557 if (current_value.empty()) current_value = option.defaultValue;
558
559 text_tarray::const_iterator thisvalue = option.validValues.begin();
560 text_tarray::const_iterator endvalue = option.validValues.end();
561
562 while (thisvalue != endvalue) {
563 macrovalue += "<option value=\"" + *thisvalue + "\"";
564 if (*thisvalue == current_value)
565 macrovalue += " selected";
566 macrovalue += ">_" + *thisvalue + "_\n";
567 thisvalue ++;
568 }
569 macrovalue += "</select>\n";
570 disp.setmacro (macroname + "selection", "Global", macrovalue);
571}
572
573void queryaction::define_external_macros (displayclass &disp, cgiargsclass &args,
574 recptprotolistclass *protos, ostream &logout) {
575
576 // define_external_macros sets the following macros:
577
578 // some or all of these may not be required to be set
579 // _hselection_, _h2selection_ the selection box for the main part of the index
580 // _jselection_, _j2selection_ the selection box for the subcollection part of the index
581 // _nselection_, _n2selection_ the selection box for the language part of the index
582 // _cq2selection the selection box for combining two queries
583
584
585 // can't do anything if collectproto is null (i.e. no collection was specified)
586 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
587 if (collectproto == NULL) return;
588
589 comerror_t err;
590 InfoFilterOptionsResponse_t response;
591 InfoFilterOptionsRequest_t request;
592 request.filterName = "QueryFilter";
593
594 collectproto->get_filteroptions (args["c"], request, response, err, logout);
595 if (err == noError) {
596
597 FilterOption_tmap::const_iterator it;
598 FilterOption_tmap::const_iterator end = response.filterOptions.end();
599
600 // _hselection_ and _h2selection_ (Index)
601 it = response.filterOptions.find ("Index");
602 if (it != end) set_option_macro ("h", args["h"], (*it).second, disp);
603 if (it != end) set_option_macro ("h2", args["h2"], (*it).second, disp);
604
605 // _jselection_ and _j2selection_ (Subcollection)
606 it = response.filterOptions.find ("Subcollection");
607 if (it != end) set_option_macro ("j", args["j"], (*it).second, disp);
608 if (it != end) set_option_macro ("j2", args["j2"], (*it).second, disp);
609
610 // _nselection_ and _n2selection_ (Language)
611 it = response.filterOptions.find ("Language");
612 if (it != end) set_option_macro ("n", args["n"], (*it).second, disp);
613 if (it != end) set_option_macro ("n2", args["n2"], (*it).second, disp);
614
615 // _cq2selection_ (CombineQuery)
616 it = response.filterOptions.find ("CombineQuery");
617 if (it != end) set_option_macro ("cq2", args["cq2"], (*it).second, disp);
618
619 // define_history_macros(disp, args, protos, logout);
620 }
621} // define external macros
622
623void queryaction::define_history_macros (displayclass &disp, cgiargsclass &args,
624 recptprotolistclass *protos, ostream &logout) {
625
626 // defines the following macros
627
628 // _searchhistorylist_
629
630 text_t historylist;
631 int arghd = args.getintarg("hd");
632 if (arghd != 1) {
633 historylist="";
634 }
635 else {
636 historylist = "<!-- Search History List -->\n";
637
638 text_t userid = args["z"];
639 text_tarray entries;
640 if (get_history_info (userid, entries, gsdlhome, logout)) {
641 int count = 1;
642 text_tarray::iterator here = entries.begin();
643 text_tarray::iterator end = entries.end();
644 int size=(int)entries.size();
645 if (args["hcl"]==1&&size>5) { // compress the list
646 here = end-5;
647 count=size-4;
648 }
649 historylist += "<table align=center width=500 border=0>\n";
650 historylist += "<tr><td width=300 align=center>";
651 historylist += "<a href=\"_httpclearhistory_\">_textclearhistory_</a></td>\n";
652
653 if (size>5&&args["hcl"]==1) { //compress the list, show the expand button
654
655 historylist += "<td><a href=\"_gwcgi_?e=_compressedoptions_&a=q&hcl=0\">_textexpand_</a></td>\n";
656 }
657 else if (size >5 && args["hcl"]==0) { // expand the list, show contract button
658 historylist += "<td><a href=\"_gwcgi_?e=_compressedoptions_&a=q&hcl=1\">_textcontract_</a></td>\n";
659 }
660 historylist += "</table>\n";
661 historylist += "<table align=center width=500 border=1>\n<tr><th colspan=4 align=center>";
662 historylist += "_textsearchhistory_</th></tr>\n";
663 historylist += "<tr><th width=40>#</th>\n<th width=340>_textquery_</th>\n";
664 historylist += "<th width=60>_textresults_</th><th width=60>_textview_</th></tr>\n";
665
666 while (here !=end ) {
667 text_t c;
668 text_t query;
669 text_t numdocs;
670 text_t cgiargs;
671 text_t userinfo;
672 split_saved_query(*here,c, numdocs, cgiargs);
673 parse_saved_args(cgiargs, "q", query); // get query string out
674 decode_cgi_arg(query); // un cgisafe it
675
676 format_user_info(cgiargs, userinfo, protos, logout);
677
678 historylist += "<tr> <td width=40 align=center>"+c+"</td>\n";
679 historylist += "<td width=340 align=left>"+query+"</td><td width=60 align=center>"+numdocs+"</td>\n";
680 historylist += "<td width=60 align=center><a href=\"_gwcgi_?e=_compressedoptions_&";
681 historylist += *here+"\"><img name=\"display\" src=\"_httpicondisplay_\" width=_widthdisplay_ ";
682 historylist += "height=_heightdisplay_ border=\"0\" alt=\"" + userinfo +"\"></a></td></tr>\n";
683 here++;
684 count++;
685 }
686 historylist+="</table>\n\n";
687
688 } // if
689 else {
690 historylist += "_textnohistory_";
691 }
692 historylist += "<p><! ---- end of history list ----->\n";
693 } // else display list
694 disp.setmacro("searchhistorylist", "query", historylist);
695
696} // define history macros
697
698void queryaction::output_ccp (cgiargsclass &args, recptprotolistclass *protos,
699 displayclass &disp, outconvertclass &outconvert,
700 ostream &textout, ostream &logout) {
701
702 ColInfoResponse_t *cinfo = NULL;
703 comerror_t err;
704 InfoFilterOptionsResponse_t fresponse;
705 InfoFilterOptionsRequest_t frequest;
706 frequest.filterName = "QueryFilter";
707
708 text_t &index = args["h"];
709 text_t &subcollection = args["j"];
710 text_t &language = args["n"];
711
712 text_tset collections;
713 text_t arg_cc = args["cc"];
714 decode_cgi_arg (arg_cc);
715 splitchar (arg_cc.begin(), arg_cc.end(), ',', collections);
716
717 textout << outconvert << disp << "_query:header_\n"
718 << "<center>_navigationbar_</center><br>\n"
719 << "<form name=QueryForm method=get action=\"_gwcgi_\">\n"
720 << "<input type=hidden name=a value=\"q\">\n"
721 << "<input type=hidden name=e value=\"_compressedoptions_\">\n"
722 << "<input type=hidden name=ccp value=\"1\">\n"
723 << "<center><table width=_pagewidth_><tr valign=top>\n"
724 << "<td>Select collections to search for \"" << args["q"]
725 << "\" <i>(index=" << index << " subcollection=" << subcollection
726 << " language=" << language << ")</i></td>\n"
727 << "<td><input type=\"submit\" value=\"_query:textbeginsearch_\"></td>\n"
728 << "</tr></table></center>\n"
729 << "<center><table width=_pagewidth_>\n"
730 << "<tr><td>\n";
731
732 recptprotolistclass::iterator rprotolist_here = protos->begin();
733 recptprotolistclass::iterator rprotolist_end = protos->end();
734 while (rprotolist_here != rprotolist_end) {
735 if ((*rprotolist_here).p != NULL) {
736
737 text_tarray collist;
738 (*rprotolist_here).p->get_collection_list (collist, err, logout);
739 if (err == noError) {
740 text_tarray::iterator collist_here = collist.begin();
741 text_tarray::iterator collist_end = collist.end();
742 while (collist_here != collist_end) {
743
744 cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
745 // if (err == noError && cinfo.isPublic && (cinfo.buildDate > 0)) {
746 if (cinfo != NULL && (cinfo->buildDate > 0)) {
747
748 (*rprotolist_here).p->get_filteroptions (*collist_here, frequest, fresponse, err, logout);
749 if (err == noError) {
750
751 FilterOption_tmap::const_iterator it;
752 FilterOption_tmap::const_iterator end = fresponse.filterOptions.end();
753 if (!index.empty()) {
754 it = fresponse.filterOptions.find ("Index");
755 if (it == end) {collist_here ++; continue;}
756 text_tarray::const_iterator there = (*it).second.validValues.begin();
757 text_tarray::const_iterator tend = (*it).second.validValues.end();
758 while (there != tend) {
759 if (*there == index) break;
760 there ++;
761 }
762 if (there == tend) {collist_here++; continue;}
763 }
764 if (!subcollection.empty()) {
765 it = fresponse.filterOptions.find ("Subcollection");
766 if (it == end) {collist_here++; continue;}
767 text_tarray::const_iterator there = (*it).second.validValues.begin();
768 text_tarray::const_iterator tend = (*it).second.validValues.end();
769 while (there != tend) {
770 if (*there == subcollection) break;
771 there ++;
772 }
773 if (there == tend) {collist_here++; continue;}
774 }
775 if (!language.empty()) {
776 it = fresponse.filterOptions.find ("Language");
777 if (it == end) {collist_here++; continue;}
778 text_tarray::const_iterator there = (*it).second.validValues.begin();
779 text_tarray::const_iterator tend = (*it).second.validValues.end();
780 while (there != tend) {
781 if (*there == language) break;
782 there ++;
783 }
784 if (there == tend) {collist_here++; continue;}
785 }
786
787 // we've got a matching collection
788 textout << "<input type=checkbox";
789
790 text_tset::const_iterator t = collections.find (*collist_here);
791 if (t != collections.end()) textout << " checked";
792
793 textout << outconvert
794 << " name=cc value=\"" << *collist_here << "\">";
795
796 if (!cinfo->collectionmeta["collectionname"].empty())
797 textout << outconvert << disp << cinfo->collectionmeta["collectionname"];
798 else
799 textout << outconvert << *collist_here;
800
801 textout << "<br>\n";
802
803 }
804 }
805 collist_here ++;
806 }
807 }
808 }
809 rprotolist_here ++;
810 }
811 textout << outconvert << disp
812 << "</td></tr></table></center>\n"
813 << "</form>\n"
814 << "_query:footer_\n";
815
816}
817
818bool queryaction::do_action (cgiargsclass &args, recptprotolistclass *protos,
819 browsermapclass *browsers, displayclass &disp,
820 outconvertclass &outconvert, ostream &textout,
821 ostream &logout) {
822
823 if (recpt == NULL) {
824 logout << "ERROR (queryaction::do_action): This action does not contain information\n"
825 << " about any receptionists. The method set_receptionist was probably\n"
826 << " not called from the module which instantiated this action.\n";
827 return true;
828 }
829
830
831 if (args["ccs"] == "1") {
832 if (!args["cc"].empty()) {
833 // query the selected collections
834 text_t::const_iterator b = args["cc"].begin();
835 text_t::const_iterator e = args["cc"].end();
836 if (findchar (b, e, ',') != e) {
837 if (!search_multiple_collections (args, protos, browsers, disp, outconvert,
838 textout, logout)) return false;
839 return true;
840 } else {
841 if (!search_single_collection (args, args["cc"], protos, browsers, disp,
842 outconvert, textout, logout)) return false;
843 return true;
844 }
845 }
846 }
847
848 // simply query the current collection
849 if (!search_single_collection (args, args["c"], protos, browsers, disp,
850 outconvert, textout, logout)) return false;
851 return true;
852}
853
854bool queryaction::search_multiple_collections (cgiargsclass &args, recptprotolistclass *protos,
855 browsermapclass *browsers, displayclass &disp,
856 outconvertclass &outconvert, ostream &textout,
857 ostream &logout) {
858
859 text_tarray collections;
860
861 text_t arg_cc = args["cc"];
862 decode_cgi_arg (arg_cc);
863 splitchar (arg_cc.begin(), arg_cc.end(), ',', collections);
864
865 if (collections.empty()) {
866 logout << "queryaction::search_multiple_collections: No collections "
867 << "set for doing multiple query - will search current collection\n";
868 textout << outconvert << disp << "_query:textwarningnocollections_\n";
869 return search_single_collection (args, args["c"], protos, browsers, disp,
870 outconvert, textout, logout);
871 }
872
873 // queryaction uses "VList" browser to display results,
874 // a queries clasification is "Search"
875 text_t browsertype = "VList";
876 text_t classification = "Search";
877
878 QueryResult_tset results;
879 map<text_t, colinfo_t, lttext_t> colinfomap;
880
881 ColInfoResponse_t *cinfo = NULL;
882 comerror_t err;
883 FilterRequest_t request;
884 FilterResponse_t response;
885 request.filterResultOptions = FROID | FRmetadata | FRtermFreq | FRranking;
886 text_t formattedstring = args["q"];
887 text_t freqmsg = "_textfreqmsg1_";
888 int numdocs = 0;
889 isapprox isApprox = Exact;
890
891 format_querystring (formattedstring, args.getintarg("b"));
892 set_queryfilter_options (request, formattedstring, args);
893
894 // need to retrieve maxdocs matches for each collection
895 // (will eventually want to tidy this up, do so caching etc.)
896 OptionValue_t option;
897 option.name = "StartResults";
898 option.value = "1";
899 request.filterOptions.push_back (option);
900
901 option.name = "EndResults";
902 option.value = args["m"];
903 request.filterOptions.push_back (option);
904
905 text_tarray::iterator col_here = collections.begin();
906 text_tarray::iterator col_end = collections.end();
907
908 map<text_t, int, lttext_t> termfreqs;
909 while (col_here != col_end) {
910
911 request.fields.erase (request.fields.begin(), request.fields.end());
912 request.getParents = false;
913
914 recptproto *collectproto = protos->getrecptproto (*col_here, logout);
915 if (collectproto == NULL) {
916 logout << outconvert << "queryaction::search_multiple_collections: " << *col_here
917 << " collection has a NULL collectproto, ignoring\n";
918 col_here ++;
919 continue;
920 }
921 cinfo = recpt->get_collectinfo_ptr (collectproto, *col_here, logout);
922 if (cinfo == NULL) {
923 logout << "ERROR (query_action::search_multiple_collections): get_collectinfo_ptr returned NULL\n";
924 col_here ++;
925 continue;
926 }
927
928 browserclass *bptr = browsers->getbrowser (browsertype);
929
930 // get the formatstring if there is one
931 text_t formatstring;
932 if (!get_formatstring (classification, browsertype,
933 cinfo->format, formatstring))
934 formatstring = bptr->get_default_formatstring();
935
936 bptr->load_metadata_defaults (request.fields);
937
938 format_t *formatlistptr = new format_t();
939 parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
940
941 colinfo_t thiscolinfo;
942 thiscolinfo.formatlistptr = formatlistptr;
943 thiscolinfo.browserptr = bptr;
944 colinfomap[*col_here] = thiscolinfo;
945
946 // do the query
947 collectproto->filter (*col_here, request, response, err, logout);
948 if (err != noError) {
949 outconvertclass text_t2ascii;
950 logout << text_t2ascii
951 << "queryaction::search_multiple_collections: call to QueryFilter failed "
952 << "for " << *col_here << " collection (" << get_comerror_string (err) << ")\n";
953 return false;
954 }
955
956 if (isApprox == Exact)
957 isApprox = response.isApprox;
958 else if (isApprox == MoreThan)
959 if (response.isApprox == Approximate)
960 isApprox = response.isApprox;
961
962 TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
963 TermInfo_tarray::const_iterator end_term = response.termInfo.end();
964 while (this_term != end_term) {
965 termfreqs[(*this_term).term] += (*this_term).freq;
966 if ((col_here+1) == col_end) {
967 freqmsg += (*this_term).term + ": " + termfreqs[(*this_term).term];
968 if ((this_term+1) != end_term) freqmsg += ", ";
969 }
970 this_term ++;
971 }
972
973 if (response.numDocs > 0) {
974 numdocs += response.numDocs;
975
976 QueryResult_t thisresult;
977 thisresult.collection = *col_here;
978 ResultDocInfo_tarray::iterator doc_here = response.docInfo.begin();
979 ResultDocInfo_tarray::iterator doc_end = response.docInfo.end();
980 while (doc_here != doc_end) {
981 thisresult.doc = *doc_here;
982 results.insert (thisresult);
983 doc_here ++;
984 }
985 }
986 col_here ++;
987 }
988
989 disp.setmacro ("freqmsg", "query", freqmsg);
990
991 text_t resline;
992 if (num_phrases > 0) isApprox = Exact;
993 if (isApprox == Approximate) resline = "_textapprox_";
994 else if (isApprox == MoreThan) resline = "_textmorethan_";
995
996 if (numdocs == 0) resline = "_textnodocs_";
997 else if (numdocs == 1) resline += "_text1doc_";
998 else resline += text_t(numdocs) + " _textlotsdocs_";
999 disp.setmacro("resultline", "query", resline);
1000
1001 QueryResult_tset::iterator res_here = results.begin();
1002 QueryResult_tset::iterator res_end = results.end();
1003 text_tset metadata; // empty !!
1004 bool getParents = false; // don't care !!
1005 recptproto *collectproto = NULL;
1006 bool use_table;
1007 ResultDocInfo_t thisdoc;
1008 format_t *formatlistptr = NULL;
1009 browserclass *browserptr = NULL;
1010
1011 int maxdocs = args.getintarg("m");
1012 int firstdoc = args.getintarg("r");
1013 int hitsperpage = args.getintarg("o");
1014 if (numdocs > maxdocs) numdocs = maxdocs;
1015 if (hitsperpage == -1) hitsperpage = numdocs;
1016
1017 // set up _thisfirst_ and _thislast_ macros
1018 disp.setmacro ("thisfirst", "query", firstdoc);
1019 int thislast = firstdoc + (hitsperpage - 1);
1020 if (thislast > numdocs) thislast = numdocs;
1021 disp.setmacro ("thislast", "query", thislast);
1022
1023 // set up _prevfirst_ and _prevlast_ macros
1024 if (firstdoc > 1) {
1025 disp.setmacro ("prevlast", "query", firstdoc - 1);
1026 int prevfirst = firstdoc - hitsperpage;
1027 if (prevfirst < 1) prevfirst = 1;
1028 disp.setmacro ("prevfirst", "query", prevfirst);
1029 }
1030
1031 // set up _nextfirst_ and _nextlast_ macros
1032 if (thislast < numdocs) {
1033 disp.setmacro ("nextfirst", "query", thislast + 1);
1034 int nextlast = thislast + hitsperpage;
1035 if (nextlast > numdocs) nextlast = numdocs;
1036 disp.setmacro ("nextlast", "query", nextlast);
1037 }
1038
1039 textout << outconvert << disp << "_query:header_\n"
1040 << "_query:content_";
1041
1042 int count = 1;
1043
1044 // output results
1045 while (res_here != res_end) {
1046 if (count < firstdoc) {count ++; res_here ++; continue;}
1047 if (count > thislast) break;
1048 formatlistptr = colinfomap[(*res_here).collection].formatlistptr;
1049 browserptr = colinfomap[(*res_here).collection].browserptr;
1050 thisdoc = (*res_here).doc;
1051 use_table = is_table_content (formatlistptr);
1052 browserptr->output_section_group (thisdoc, args, (*res_here).collection, 0,
1053 formatlistptr, use_table, metadata, getParents,
1054 collectproto, disp, outconvert, textout, logout);
1055 // textout << outconvert << "(ranking: " << (*res_here).doc.ranking << ")\n";
1056 res_here ++;
1057 count ++;
1058 }
1059
1060 textout << outconvert << disp << "_query:footer_";
1061
1062 // clean up the format_t pointers
1063 map<text_t, colinfo_t, lttext_t>::iterator here = colinfomap.begin();
1064 map<text_t, colinfo_t, lttext_t>::iterator end = colinfomap.end();
1065 while (here != end) {
1066 delete ((*here).second.formatlistptr);
1067 here ++;
1068 }
1069 return true;
1070}
1071
1072bool queryaction::search_single_collection (cgiargsclass &args, const text_t &collection,
1073 recptprotolistclass *protos, browsermapclass *browsers,
1074 displayclass &disp, outconvertclass &outconvert,
1075 ostream &textout, ostream &logout) {
1076
1077 recptproto *collectproto = protos->getrecptproto (collection, logout);
1078 if (collectproto == NULL) {
1079 logout << outconvert << "queryaction::search_single_collection: " << collection
1080 << " collection has a NULL collectproto\n";
1081 return false;
1082 }
1083
1084 // queryaction uses "VList" browser to display results,
1085 // a queries clasification is "Search"
1086 text_t browsertype = "VList";
1087 text_t classification = "Search";
1088
1089 comerror_t err;
1090 ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
1091
1092 if (cinfo == NULL) {
1093 logout << "ERROR (query_action::search_single_collection): get_collectinfo_ptr returned NULL\n";
1094 return false;
1095 }
1096
1097 browserclass *bptr = browsers->getbrowser (browsertype);
1098
1099 // get the formatstring if there is one
1100 text_t formatstring;
1101 if (!get_formatstring (classification, browsertype,
1102 cinfo->format, formatstring))
1103 formatstring = bptr->get_default_formatstring();
1104
1105 FilterRequest_t request;
1106 FilterResponse_t response;
1107 bptr->set_filter_options (request, args);
1108 bptr->load_metadata_defaults (request.fields);
1109
1110 format_t *formatlistptr = new format_t();
1111 parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
1112
1113 // do the query
1114 request.filterResultOptions = FROID | FRmetadata | FRtermFreq;
1115 text_t formattedstring = args["q"];
1116 if (!combine_query (args["z"], formattedstring, gsdlhome)) {
1117 args["q"]=formattedstring;
1118 }
1119 format_querystring (formattedstring, args.getintarg("b"));
1120 set_queryfilter_options (request, formattedstring, args);
1121 collectproto->filter (collection, request, response, err, logout);
1122 if (err != noError) {
1123 outconvertclass text_t2ascii;
1124 logout << text_t2ascii
1125 << "queryaction::search_single_collections: call to QueryFilter failed "
1126 << "for " << collection << " collection (" << get_comerror_string (err) << ")\n";
1127 return false;
1128 }
1129
1130
1131 define_query_macros (args, disp, response);
1132
1133 // save the query if appropriate
1134 if (!save_search_history(args, response))
1135 logout << "save failed";
1136
1137 define_history_macros (disp, args, protos, logout);
1138
1139 textout << outconvert << disp << "_query:header_\n"
1140 << "_query:content_";
1141
1142 // output the results
1143 bool use_table = is_table_content (formatlistptr);
1144 bptr->output_section_group (response, args, collection, 0, formatlistptr,
1145 use_table, request.fields, request.getParents,
1146 collectproto, disp, outconvert, textout, logout);
1147
1148
1149 textout << outconvert << disp << "_query:footer_";
1150
1151 delete (formatlistptr);
1152
1153 return true;
1154}
1155
1156// define_query_macros sets the macros that couldn't be set until the
1157// query had been done. Those macros are _freqmsg_, _quotedquery_,
1158// _resultline_, _nextfirst_, _nextlast_, _prevfirst_, _prevlast_,
1159// _thisfirst_, and _thislast_
1160void queryaction::define_query_macros (cgiargsclass &args, displayclass &disp,
1161 const FilterResponse_t &response) {
1162
1163 // set up _freqmsg_ and _quotedquery_ macros
1164 text_t freqmsg = "_textfreqmsg1_";
1165 TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
1166 TermInfo_tarray::const_iterator end_term = response.termInfo.end();
1167 while (this_term != end_term) {
1168 freqmsg += (*this_term).term + ": " + (*this_term).freq;
1169 if ((this_term + 1) != end_term)
1170 freqmsg += ", ";
1171 this_term ++;
1172 }
1173
1174 disp.setmacro ("freqmsg", "query", freqmsg);
1175
1176
1177 // set up _resultline_ macro
1178 text_t resline;
1179 int maxdocs = args.getintarg("m");
1180 int numdocs = response.numDocs;
1181 if (maxdocs == -1) maxdocs = response.numDocs;
1182 isapprox isApprox = response.isApprox;
1183
1184 // if there were phrases (post-processing) we're not going to include
1185 // those documents that didn't match
1186 if (num_phrases > 0) isApprox = Exact;
1187
1188 if (isApprox == Approximate) resline = "_textapprox_";
1189 else if (isApprox == MoreThan) resline = "_textmorethan_";
1190
1191 if (numdocs == 0) resline = "_textnodocs_";
1192 else if (numdocs == 1) resline += "_text1doc_";
1193 else resline += text_t(numdocs) + " _textlotsdocs_";
1194
1195 disp.setmacro("resultline", "query", resline);
1196
1197 int firstdoc = args.getintarg("r");
1198 int hitsperpage = args.getintarg("o");
1199 if (hitsperpage == -1) hitsperpage = numdocs;
1200
1201 // set up _thisfirst_ and _thislast_ macros
1202 disp.setmacro ("thisfirst", "query", firstdoc);
1203 int thislast = firstdoc + (hitsperpage - 1);
1204 if (thislast > numdocs) thislast = numdocs;
1205 disp.setmacro ("thislast", "query", thislast);
1206
1207 // set up _prevfirst_ and _prevlast_ macros
1208 if (firstdoc > 1) {
1209 disp.setmacro ("prevlast", "query", firstdoc - 1);
1210 int prevfirst = firstdoc - hitsperpage;
1211 if (prevfirst < 1) prevfirst = 1;
1212 disp.setmacro ("prevfirst", "query", prevfirst);
1213 }
1214
1215 // set up _nextfirst_ and _nextlast_ macros
1216 if (thislast < numdocs) {
1217 disp.setmacro ("nextfirst", "query", thislast + 1);
1218 int nextlast = thislast + hitsperpage;
1219 if (nextlast > numdocs) nextlast = numdocs;
1220 disp.setmacro ("nextlast", "query", nextlast);
1221 }
1222}
1223
1224bool queryaction::save_search_history (cgiargsclass &args, const FilterResponse_t &response)
1225{
1226 if (args["q"]=="") return true; // null query, dont save
1227 if (args["hs"]=="0") return true; // only save when submit query
1228
1229 // get userid
1230 text_t userid = args["z"];
1231
1232 // the number of docs goes on the front of the query string
1233 int numdocs= response.numDocs;
1234 text_t query = text_t(numdocs);
1235 if (response.isApprox==MoreThan) { // there were more docs found
1236 query.push_back('+');
1237 }
1238 query += "a=q";
1239 query += "&c="+args["c"];
1240 query += "&h="+args["h"];
1241 query += "&t="+args["t"];
1242 query += "&b="+args["b"];
1243 query += "&j="+args["j"];
1244 query += "&n="+args["n"];
1245 query += "&s="+args["s"];
1246 query += "&k="+args["k"];
1247
1248 text_t qstring = args["q"];
1249 text_t formattedquery =cgi_safe(qstring);
1250 query += "&q="+formattedquery;
1251
1252 if (set_history_info(userid, query, gsdlhome)) return true;
1253 else return false;
1254
1255
1256}
1257
1258
1259
1260
1261
Note: See TracBrowser for help on using the repository browser.