source: branches/z3950-branch/gsdl/src/recpt/queryaction.cpp@ 1174

Last change on this file since 1174 was 1174, checked in by johnmcp, 24 years ago

checkpoint - can now connect and get status information from a z39.50 server.
Still need to get queries and data retrieval working.

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