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

Last change on this file since 4755 was 4755, checked in by kjdon, 21 years ago

no longer use set_gselection_macro and set_fqfselection_macro functions, set_option_macro now takes a boolean parameter display_single. If the arg has only one option, if display_single is true, create teh macro, otherwise dont. have two new cgi args: qf for query form type (used to use the b arg for this, but I've given it its own arg now), and qto for query type options. qto indicates whether there shoudl be form search, plain search or both available to the user (used on prefs page). if qto = 2, there is only form search, and qt may not be set, so now we have to chack qto as well as qt when determining whether we are doing a form search or not.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 49.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 *********************************************************************/
25
26#include "queryaction.h"
27#include "querytools.h"
28#include "formattools.h"
29#include "cgiutils.h"
30#include "OIDtools.h"
31//#include "infodbclass.h"
32#include "fileutil.h"
33#include "text_t.h"
34#include "historydb.h"
35#include "htmlutils.h" // for html_safe in do_action
36#include "gsdltools.h"
37#include <stdlib.h> // for strtol
38#include <assert.h>
39
40void colinfo_t::clear () {
41 formatlistptr = NULL;
42 browserptr = NULL;
43}
44
45void QueryResult_t::clear() {
46 doc.clear();
47 collection.clear();
48}
49
50queryaction::queryaction () {
51
52 recpt = NULL;
53 num_phrases = 0;
54
55 // this action uses cgi variable "a"
56 cgiarginfo arg_ainfo;
57 arg_ainfo.shortname = "a";
58 arg_ainfo.longname = "action";
59 arg_ainfo.multiplechar = true;
60 arg_ainfo.defaultstatus = cgiarginfo::weak;
61 arg_ainfo.argdefault = "q";
62 arg_ainfo.savedarginfo = cgiarginfo::must;
63 argsinfo.addarginfo (NULL, arg_ainfo);
64
65 arg_ainfo.shortname = "xx";
66 arg_ainfo.longname = "xx";
67 arg_ainfo.multiplechar = true;
68 arg_ainfo.multiplevalue = true;
69 arg_ainfo.defaultstatus = cgiarginfo::weak;
70 arg_ainfo.argdefault = "a";
71 arg_ainfo.savedarginfo = cgiarginfo::must;
72 argsinfo.addarginfo (NULL, arg_ainfo);
73
74 // "ct" - 0 = mg, 1 = mgpp
75 arg_ainfo.shortname = "ct";
76 arg_ainfo.longname = "collection type";
77 arg_ainfo.multiplechar = false;
78 arg_ainfo.defaultstatus = cgiarginfo::weak;
79 arg_ainfo.argdefault = "0";
80 arg_ainfo.savedarginfo = cgiarginfo::must;
81 argsinfo.addarginfo (NULL, arg_ainfo);
82
83 // "b" - 0 = simple, 1 = advanced
84 arg_ainfo.shortname = "b";
85 arg_ainfo.longname = "query mode";
86 arg_ainfo.multiplechar = false;
87 arg_ainfo.defaultstatus = cgiarginfo::weak;
88 arg_ainfo.argdefault = "0";
89 arg_ainfo.savedarginfo = cgiarginfo::must;
90 argsinfo.addarginfo (NULL, arg_ainfo);
91
92 // "h"
93 arg_ainfo.shortname = "h";
94 arg_ainfo.longname = "main index";
95 arg_ainfo.multiplechar = true;
96 arg_ainfo.defaultstatus = cgiarginfo::weak;
97 arg_ainfo.argdefault = "";
98 arg_ainfo.savedarginfo = cgiarginfo::must;
99 argsinfo.addarginfo (NULL, arg_ainfo);
100
101 // "h2"
102 arg_ainfo.shortname = "h2";
103 arg_ainfo.longname = "main index for second query";
104 arg_ainfo.multiplechar = true;
105 arg_ainfo.defaultstatus = cgiarginfo::weak;
106 arg_ainfo.argdefault = "";
107 arg_ainfo.savedarginfo = cgiarginfo::must;
108 argsinfo.addarginfo (NULL, arg_ainfo);
109
110 // "j"
111 arg_ainfo.shortname = "j";
112 arg_ainfo.longname = "sub collection index";
113 arg_ainfo.multiplechar = true;
114 arg_ainfo.defaultstatus = cgiarginfo::weak;
115 arg_ainfo.argdefault = "";
116 arg_ainfo.savedarginfo = cgiarginfo::must;
117 argsinfo.addarginfo (NULL, arg_ainfo);
118
119 // "j2"
120 arg_ainfo.shortname = "j2";
121 arg_ainfo.longname = "sub collection index for second query";
122 arg_ainfo.multiplechar = true;
123 arg_ainfo.defaultstatus = cgiarginfo::weak;
124 arg_ainfo.argdefault = "";
125 arg_ainfo.savedarginfo = cgiarginfo::must;
126 argsinfo.addarginfo (NULL, arg_ainfo);
127
128 // "n"
129 arg_ainfo.shortname = "n";
130 arg_ainfo.longname = "language index";
131 arg_ainfo.multiplechar = true;
132 arg_ainfo.defaultstatus = cgiarginfo::weak;
133 arg_ainfo.argdefault = "";
134 arg_ainfo.savedarginfo = cgiarginfo::must;
135 argsinfo.addarginfo (NULL, arg_ainfo);
136
137 // "n2"
138 arg_ainfo.shortname = "n2";
139 arg_ainfo.longname = "language index for second query";
140 arg_ainfo.multiplechar = true;
141 arg_ainfo.defaultstatus = cgiarginfo::weak;
142 arg_ainfo.argdefault = "";
143 arg_ainfo.savedarginfo = cgiarginfo::must;
144 argsinfo.addarginfo (NULL, arg_ainfo);
145
146
147 // "q"
148 arg_ainfo.shortname = "q";
149 arg_ainfo.longname = "query string";
150 arg_ainfo.multiplechar = true;
151 arg_ainfo.defaultstatus = cgiarginfo::weak;
152 arg_ainfo.argdefault = "";
153 arg_ainfo.savedarginfo = cgiarginfo::must;
154 argsinfo.addarginfo (NULL, arg_ainfo);
155
156 // "q2"
157 arg_ainfo.shortname = "q2";
158 arg_ainfo.longname = "query string for second query";
159 arg_ainfo.multiplechar = true;
160 arg_ainfo.defaultstatus = cgiarginfo::weak;
161 arg_ainfo.argdefault = "";
162 arg_ainfo.savedarginfo = cgiarginfo::must;
163 argsinfo.addarginfo (NULL, arg_ainfo);
164
165 // "cq2" ""=don't combine, "and", "or", "not"
166 arg_ainfo.shortname = "cq2";
167 arg_ainfo.longname = "combine queries";
168 arg_ainfo.multiplechar = true;
169 arg_ainfo.defaultstatus = cgiarginfo::weak;
170 arg_ainfo.argdefault = "";
171 arg_ainfo.savedarginfo = cgiarginfo::must;
172 argsinfo.addarginfo (NULL, arg_ainfo);
173
174 // "t" - 1 = ranked 0 = boolean
175 arg_ainfo.shortname = "t";
176 arg_ainfo.longname = "search type";
177 arg_ainfo.multiplechar = false;
178 arg_ainfo.defaultstatus = cgiarginfo::weak;
179 arg_ainfo.argdefault = "1";
180 arg_ainfo.savedarginfo = cgiarginfo::must;
181 argsinfo.addarginfo (NULL, arg_ainfo);
182
183 // "k"
184 arg_ainfo.shortname = "k";
185 arg_ainfo.longname = "casefolding";
186 arg_ainfo.multiplechar = false;
187 arg_ainfo.defaultstatus = cgiarginfo::weak;
188 arg_ainfo.argdefault = "1";
189 arg_ainfo.savedarginfo = cgiarginfo::must;
190 argsinfo.addarginfo (NULL, arg_ainfo);
191
192 // "s"
193 arg_ainfo.shortname = "s";
194 arg_ainfo.longname = "stemming";
195 arg_ainfo.multiplechar = false;
196 arg_ainfo.defaultstatus = cgiarginfo::weak;
197 arg_ainfo.argdefault ="0";
198 arg_ainfo.savedarginfo = cgiarginfo::must;
199 argsinfo.addarginfo (NULL, arg_ainfo);
200
201 // "m"
202 arg_ainfo.shortname = "m";
203 arg_ainfo.longname = "maximum number of documents";
204 arg_ainfo.multiplechar = true;
205 arg_ainfo.defaultstatus = cgiarginfo::weak;
206 arg_ainfo.argdefault = "50";
207 arg_ainfo.savedarginfo = cgiarginfo::must;
208 argsinfo.addarginfo (NULL, arg_ainfo);
209
210 // "o"
211 arg_ainfo.shortname = "o";
212 arg_ainfo.longname = "hits per page";
213 arg_ainfo.multiplechar = true;
214 arg_ainfo.defaultstatus = cgiarginfo::weak;
215 arg_ainfo.argdefault = "20";
216 arg_ainfo.savedarginfo = cgiarginfo::must;
217 argsinfo.addarginfo (NULL, arg_ainfo);
218
219 // "r"
220 arg_ainfo.shortname = "r";
221 arg_ainfo.longname = "start results from";
222 arg_ainfo.multiplechar = true;
223 arg_ainfo.defaultstatus = cgiarginfo::weak;
224 arg_ainfo.argdefault = "1";
225 arg_ainfo.savedarginfo = cgiarginfo::must;
226 argsinfo.addarginfo (NULL, arg_ainfo);
227
228 // "ccs"
229 arg_ainfo.shortname = "ccs";
230 arg_ainfo.longname = "cross collection searching";
231 arg_ainfo.multiplechar = false;
232 arg_ainfo.defaultstatus = cgiarginfo::weak;
233 arg_ainfo.argdefault = "0";
234 arg_ainfo.savedarginfo = cgiarginfo::must;
235 argsinfo.addarginfo (NULL, arg_ainfo);
236
237 // "ccp"
238 arg_ainfo.shortname = "ccp";
239 arg_ainfo.longname = "cross collection page";
240 arg_ainfo.multiplechar = false;
241 arg_ainfo.defaultstatus = cgiarginfo::weak;
242 arg_ainfo.argdefault = "0";
243 arg_ainfo.savedarginfo = cgiarginfo::must;
244 argsinfo.addarginfo (NULL, arg_ainfo);
245
246 // "cc"
247 arg_ainfo.shortname = "cc";
248 arg_ainfo.longname = "collections to search";
249 arg_ainfo.multiplechar = true;
250 arg_ainfo.multiplevalue = true;
251 arg_ainfo.defaultstatus = cgiarginfo::weak;
252 arg_ainfo.argdefault = "";
253 arg_ainfo.savedarginfo = cgiarginfo::must;
254 argsinfo.addarginfo (NULL, arg_ainfo);
255
256 // "hd" history display - search history only displayed when
257 // this var set to something other than 0
258 // this number of records is displayed
259 arg_ainfo.shortname = "hd";
260 arg_ainfo.longname = "history display";
261 arg_ainfo.multiplechar = true;
262 arg_ainfo.multiplevalue = false;
263 arg_ainfo.defaultstatus = cgiarginfo::weak;
264 arg_ainfo.argdefault = "0";
265 arg_ainfo.savedarginfo = cgiarginfo::must;
266 argsinfo.addarginfo (NULL, arg_ainfo);
267
268 // "hs" save - set to 1 in query form, so only save when submit
269 // query
270 // 0 = no save 1 = save
271 arg_ainfo.shortname = "hs";
272 arg_ainfo.longname = "history save";
273 arg_ainfo.multiplechar = false;
274 arg_ainfo.defaultstatus = cgiarginfo::weak;
275 arg_ainfo.argdefault = "0";
276 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
277 argsinfo.addarginfo (NULL, arg_ainfo);
278
279 // "g" - new arg for granularity, for mgpp collections
280 arg_ainfo.shortname = "g";
281 arg_ainfo.longname = "granularity";
282 arg_ainfo.multiplechar = true;
283 arg_ainfo.defaultstatus = cgiarginfo::weak;
284 arg_ainfo.argdefault = "Document";
285 arg_ainfo.savedarginfo = cgiarginfo::must;
286 argsinfo.addarginfo (NULL, arg_ainfo);
287
288 // "ds" - start date
289 arg_ainfo.shortname = "ds";
290 arg_ainfo.longname = "start date";
291 arg_ainfo.multiplechar = true;
292 arg_ainfo.defaultstatus = cgiarginfo::weak;
293 arg_ainfo.argdefault = "";
294 arg_ainfo.savedarginfo = cgiarginfo::must;
295 argsinfo.addarginfo (NULL, arg_ainfo);
296
297 // "de" - end date
298 arg_ainfo.shortname = "de";
299 arg_ainfo.longname = "end date";
300 arg_ainfo.multiplechar = true;
301 arg_ainfo.defaultstatus = cgiarginfo::weak;
302 arg_ainfo.argdefault = "";
303 arg_ainfo.savedarginfo = cgiarginfo::must;
304 argsinfo.addarginfo (NULL, arg_ainfo);
305
306 // "dsbc" - whether or not start date is prechristian
307 arg_ainfo.shortname = "dsbc";
308 arg_ainfo.longname = "start date bc";
309 arg_ainfo.multiplechar = false;
310 arg_ainfo.defaultstatus = cgiarginfo::weak;
311 arg_ainfo.argdefault = "0";
312 arg_ainfo.savedarginfo = cgiarginfo::must;
313 argsinfo.addarginfo (NULL, arg_ainfo);
314
315 // "debc" - whether or not end date is prechristian
316 arg_ainfo.shortname = "debc";
317 arg_ainfo.longname = "end date bc";
318 arg_ainfo.multiplechar = false;
319 arg_ainfo.defaultstatus = cgiarginfo::weak;
320 arg_ainfo.argdefault = "0";
321 arg_ainfo.savedarginfo = cgiarginfo::must;
322 argsinfo.addarginfo (NULL, arg_ainfo);
323
324 // "qt" - 0 = text, 1 = form
325 arg_ainfo.shortname = "qt";
326 arg_ainfo.longname = "query type";
327 arg_ainfo.multiplechar = false;
328 arg_ainfo.defaultstatus = cgiarginfo::weak;
329 arg_ainfo.argdefault = "0";
330 arg_ainfo.savedarginfo = cgiarginfo::must;
331 argsinfo.addarginfo (NULL, arg_ainfo);
332
333 // "qto" - 0 = text only, 1 = form only, 2 = text and form
334 arg_ainfo.shortname = "qto";
335 arg_ainfo.longname = "query type options";
336 arg_ainfo.multiplechar = false;
337 arg_ainfo.defaultstatus = cgiarginfo::weak;
338 arg_ainfo.argdefault = "0";
339 arg_ainfo.savedarginfo = cgiarginfo::must;
340 argsinfo.addarginfo (NULL, arg_ainfo);
341
342 // "qf" - 0= simple, 1 = advanced
343 arg_ainfo.shortname = "qf";
344 arg_ainfo.longname = "query form type";
345 arg_ainfo.multiplechar = false;
346 arg_ainfo.defaultstatus = cgiarginfo::weak;
347 arg_ainfo.argdefault = "0";
348 arg_ainfo.savedarginfo = cgiarginfo::must;
349 argsinfo.addarginfo (NULL, arg_ainfo);
350
351 // "qb" - 0 = regular, 1 = large
352 arg_ainfo.shortname = "qb";
353 arg_ainfo.longname = "query box type";
354 arg_ainfo.multiplechar = false;
355 arg_ainfo.defaultstatus = cgiarginfo::weak;
356 arg_ainfo.argdefault = "0";
357 arg_ainfo.savedarginfo = cgiarginfo::must;
358 argsinfo.addarginfo (NULL, arg_ainfo);
359
360 // "fqn" - number of fields in the query form
361 arg_ainfo.shortname = "fqn";
362 arg_ainfo.longname = "form query num fields";
363 arg_ainfo.multiplechar = true;
364 arg_ainfo.defaultstatus = cgiarginfo::weak;
365 arg_ainfo.argdefault = "4";
366 arg_ainfo.savedarginfo = cgiarginfo::must;
367 argsinfo.addarginfo (NULL, arg_ainfo);
368
369 // "fqf" - the list of field names in the form query
370 // - a comma separated list
371 arg_ainfo.shortname = "fqf";
372 arg_ainfo.longname = "form query fields";
373 arg_ainfo.multiplechar = true;
374 arg_ainfo.defaultstatus = cgiarginfo::weak;
375 arg_ainfo.argdefault = "";
376 arg_ainfo.savedarginfo = cgiarginfo::must;
377 argsinfo.addarginfo (NULL, arg_ainfo);
378
379 // "fqv" - the list of values in the form query
380 // - a comma separated list
381 arg_ainfo.shortname = "fqv";
382 arg_ainfo.longname = "form query values";
383 arg_ainfo.multiplechar = true;
384 arg_ainfo.defaultstatus = cgiarginfo::weak;
385 arg_ainfo.argdefault = "";
386 arg_ainfo.savedarginfo = cgiarginfo::must;
387 argsinfo.addarginfo (NULL, arg_ainfo);
388
389
390 // "fqs" - the list of stemming options in the form query
391 // - a comma separated list
392 arg_ainfo.shortname = "fqs";
393 arg_ainfo.longname = "form query stems";
394 arg_ainfo.multiplechar = true;
395 arg_ainfo.defaultstatus = cgiarginfo::weak;
396 arg_ainfo.argdefault = "";
397 arg_ainfo.savedarginfo = cgiarginfo::must;
398 argsinfo.addarginfo (NULL, arg_ainfo);
399
400
401 // "fqk" - the list of casefolding options in the form query
402 // - a comma separated list
403 arg_ainfo.shortname = "fqk";
404 arg_ainfo.longname = "form query casefolds";
405 arg_ainfo.multiplechar = true;
406 arg_ainfo.defaultstatus = cgiarginfo::weak;
407 arg_ainfo.argdefault = "";
408 arg_ainfo.savedarginfo = cgiarginfo::must;
409 argsinfo.addarginfo (NULL, arg_ainfo);
410
411 // "fqc" - the list of boolean operators in the form query
412 // - a comma separated list
413 arg_ainfo.shortname = "fqc";
414 arg_ainfo.longname = "form query combines";
415 arg_ainfo.multiplechar = true;
416 arg_ainfo.defaultstatus = cgiarginfo::weak;
417 arg_ainfo.argdefault = "";
418 arg_ainfo.savedarginfo = cgiarginfo::must;
419 argsinfo.addarginfo (NULL, arg_ainfo);
420
421 // "fqa" - form query advanced - for "run query"
422 arg_ainfo.shortname = "fqa";
423 arg_ainfo.longname = "form query advanced query";
424 arg_ainfo.multiplechar = false;
425 arg_ainfo.defaultstatus = cgiarginfo::weak;
426 arg_ainfo.argdefault = "0";
427 arg_ainfo.savedarginfo = cgiarginfo::must;
428 argsinfo.addarginfo (NULL, arg_ainfo);
429
430}
431
432void queryaction::configure (const text_t &key, const text_tarray &cfgline) {
433 action::configure (key, cfgline);
434}
435
436bool queryaction::init (ostream &logout) {
437 return action::init (logout);
438}
439
440bool queryaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
441 recptprotolistclass * /*protos*/, ostream &logout) {
442
443 // check t argument
444 int arg_t = args.getintarg("t");
445 if (arg_t != 0 && arg_t != 1) {
446 logout << "Warning: \"t\" argument out of range (" << arg_t << ")\n";
447 cgiarginfo *tinfo = argsinfo.getarginfo ("t");
448 if (tinfo != NULL) args["t"] = tinfo->argdefault;
449 }
450
451 // check k argument
452 int arg_k = args.getintarg("k");
453 if (arg_k != 0 && arg_k != 1) {
454 logout << "Warning: \"k\" argument out of range (" << arg_k << ")\n";
455 cgiarginfo *kinfo = argsinfo.getarginfo ("k");
456 if (kinfo != NULL) args["k"] = kinfo->argdefault;
457 }
458
459 // check s argument
460 int arg_s = args.getintarg("s");
461 if (arg_s != 0 && arg_s != 1) {
462 logout << "Warning: \"s\" argument out of range (" << arg_s << ")\n";
463 cgiarginfo *sinfo = argsinfo.getarginfo ("s");
464 if (sinfo != NULL) args["s"] = sinfo->argdefault;
465 }
466
467 // check m argument
468 int arg_m = args.getintarg("m");
469 if (arg_m < -1) {
470 logout << "Warning: \"m\" argument less than -1 (" << arg_m << ")\n";
471 cgiarginfo *minfo = argsinfo.getarginfo ("m");
472 if (minfo != NULL) args["m"] = minfo->argdefault;
473 }
474
475 // check o argument
476 int arg_o = args.getintarg("o");
477 if (arg_o < -1) {
478 logout << "Warning: \"o\" argument less than -1 (" << arg_o << ")\n";
479 cgiarginfo *oinfo = argsinfo.getarginfo ("o");
480 if (oinfo != NULL) args["o"] = oinfo->argdefault;
481 }
482
483 // check r argument
484 int arg_r = args.getintarg("r");
485 if (arg_r < 1) {
486 logout << "Warning: \"r\" argument less than 1 (" << arg_r << ")\n";
487 cgiarginfo *rinfo = argsinfo.getarginfo ("r");
488 if (rinfo != NULL) args["r"] = rinfo->argdefault;
489 }
490 //check hd argument
491 int arg_hd = args.getintarg("hd");
492 if (arg_hd <0 ) {
493 logout << "Warning: \"hd\" argument less than 0 (" << arg_hd << ")\n";
494 cgiarginfo *hdinfo = argsinfo.getarginfo ("hd");
495 if (hdinfo != NULL) args["hd"] = hdinfo->argdefault;
496 }
497
498 //check hs argument
499 int arg_hs = args.getintarg("hs");
500 if (arg_hs !=0 && arg_hs !=1) {
501 logout << "Warning: \"hs\" argument out of range (" << arg_hs << ")\n";
502 cgiarginfo *hsinfo = argsinfo.getarginfo ("hs");
503 if (hsinfo != NULL) args["hs"] = hsinfo->argdefault;
504 }
505
506 // check ct argument
507 int arg_ct = args.getintarg("ct");
508 if (arg_ct !=0 && arg_ct !=1) {
509 logout << "Warning: \"ct\" argument out of range (" << arg_ct << ")\n";
510 cgiarginfo *ctinfo = argsinfo.getarginfo ("ct");
511 if (ctinfo != NULL) args["ct"] = ctinfo->argdefault;
512 }
513
514 // check qt argument
515 int arg_qt = args.getintarg("qt");
516 if (arg_qt !=0 && arg_qt !=1) {
517 logout << "Warning: \"qt\" argument out of range (" << arg_qt << ")\n";
518 cgiarginfo *qtinfo = argsinfo.getarginfo ("qt");
519 if (qtinfo != NULL) args["qt"] = qtinfo->argdefault;
520 }
521
522 // check qb argument
523 int arg_qb = args.getintarg("qb");
524 if (arg_qb !=0 && arg_qb !=1) {
525 logout << "Warning: \"qb\" argument out of range (" << arg_qb << ")\n";
526 cgiarginfo *qbinfo = argsinfo.getarginfo ("qb");
527 if (qbinfo != NULL) args["qb"] = qbinfo->argdefault;
528 }
529
530 // check fqa argument
531 int arg_fqa = args.getintarg("fqa");
532 if (arg_fqa !=0 && arg_fqa !=1) {
533 logout << "Warning: \"fqa\" argument out of range (" << arg_fqa << ")\n";
534 cgiarginfo *fqainfo = argsinfo.getarginfo ("fqa");
535 if (fqainfo != NULL) args["fqa"] = fqainfo->argdefault;
536 }
537
538 // check fqn argument
539 int arg_fqn = args.getintarg("fqn");
540 if (arg_fqn < -1) {
541 logout << "Warning: \"fqn\" argument less than -1 (" << arg_fqn << ")\n";
542 cgiarginfo *fqninfo = argsinfo.getarginfo ("fqn");
543 if (fqninfo != NULL) args["fqn"] = fqninfo->argdefault;
544 }
545
546 return true;
547}
548
549void queryaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
550 response_t &response, text_t &response_data,
551 ostream &/*logout*/) {
552 response = content;
553 response_data = "text/html";
554}
555
556void queryaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
557 recptprotolistclass * protos,
558 ostream &logout) {
559
560 // define_internal_macros sets the following macros:
561
562 // _quotedquery_ the part of the query string that was quoted for post-processing
563
564
565
566 // The following macros are set later (in define_query_macros) as they can't be set until
567 // the query has been done.
568
569 // _freqmsg_ the term frequency string
570
571 // _resultline_ the "x documents matched the query" string
572
573 // _prevfirst_ these are used when setting up the links to previous/next
574 // _prevlast_ pages of results (_thisfirst_ and _thislast_ are used to set
575 // _nextfirst_ the 'results x-x for query: xxxx' string in the title bar)
576 // _nextlast_
577 // _thisfirst_
578 // _thislast_
579
580 if (args["ct"]==0) { // mg queries only, not mgpp
581 // get the quoted bits of the query string and set _quotedquery_
582 text_tarray phrases;
583 get_phrases (args["q"], phrases);
584 num_phrases = phrases.size();
585 text_tarray::const_iterator phere = phrases.begin();
586 text_tarray::const_iterator pend = phrases.end();
587 bool first = true;
588 text_t quotedquery;
589 while (phere != pend) {
590 if (!first)
591 if ((phere +1) == pend) quotedquery += " and ";
592 else quotedquery += ", ";
593
594 quotedquery += "\"" + *phere + "\"";
595 first = false;
596 phere ++;
597 }
598 if (args.getintarg("s") && !quotedquery.empty()) quotedquery += "_textstemon_";
599 disp.setmacro ("quotedquery", "query", quotedquery);
600 }
601
602 define_form_macros(disp, args, protos, logout);
603
604 define_query_interface(disp, args, protos, logout);
605
606}
607
608void queryaction::define_query_interface(displayclass &disp,
609 cgiargsclass &args,
610 recptprotolistclass * protos,
611 ostream &logout){
612 text_t collection = args["c"];
613
614 //check that the protocol is alive
615 recptproto* colproto = protos->getrecptproto (collection, logout);
616 if(colproto == NULL) {
617 logout << "ERROR: Null collection protocol trying to query"
618 << collection.getcstr() << "\n";
619 return;
620 }
621
622 //check the collection is responding/in place
623 ColInfoResponse_t *colinfo = recpt->get_collectinfo_ptr(colproto, collection,
624 logout);
625 if(colinfo == NULL){
626 logout << "ERROR: Null returned for get_collectinfo_ptr on "
627 << collection.getcstr() << "in queryaction::define_query_interface\n";
628 return;
629 }
630
631
632 text_tmap::iterator check = colinfo->format.find("QueryInterface");
633 if(check != colinfo->format.end()){
634 if((*check).second=="DateSearch"){
635 text_t current = "_basicqueryform_ _datesearch_";
636
637 disp.setmacro("queryformcontent","query",current);
638 }
639 }
640}
641
642
643// sets the selection box macros _hselection_, _jselection_, _nselection_ _gselection_, fqfselection_
644void queryaction::set_option_macro (const text_t &macroname, text_t current_value, bool display_single,
645 const FilterOption_t &option, displayclass &disp) {
646
647 if (option.validValues.empty()) return;
648 if (option.validValues.size() == 1) {
649 if (display_single) {
650 disp.setmacro (macroname + "selection", "Global", "_" + option.defaultValue + "_");
651 }
652 return;
653 }
654 if (option.validValues.size() < 2) return;
655
656 text_t macrovalue = "<select name=\"" + macroname + "\" onChange=\"update"+macroname+"();\">\n";
657
658 if (current_value.empty()) current_value = option.defaultValue;
659
660 text_tarray::const_iterator thisvalue = option.validValues.begin();
661 text_tarray::const_iterator endvalue = option.validValues.end();
662
663 while (thisvalue != endvalue) {
664 macrovalue += "<option value=\"" + *thisvalue + "\"";
665 if (*thisvalue == current_value)
666 macrovalue += " selected";
667 macrovalue += ">_" + *thisvalue + "_\n";
668 thisvalue ++;
669 }
670 macrovalue += "</select>\n";
671 disp.setmacro (macroname + "selection", "Global", macrovalue);
672}
673
674
675
676void queryaction::define_external_macros (displayclass &disp, cgiargsclass &args,
677 recptprotolistclass *protos, ostream &logout) {
678
679 // define_external_macros sets the following macros:
680
681 // some or all of these may not be required to be set
682 // _hselection_, _h2selection_ the selection box for the main part of the index
683 // _jselection_, _j2selection_ the selection box for the subcollection part of the index
684 // _nselection_, _n2selection_ the selection box for the language part of the index
685 // _cq2selection the selection box for combining two queries
686
687 // _gselection_, the selection box forlevels (mgpp)
688 // _fqfselection_, the selection box for index/fields (mgpp)
689 // can't do anything if collectproto is null (i.e. no collection was specified)
690 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
691 if (collectproto == NULL) return;
692
693 comerror_t err;
694 InfoFilterOptionsResponse_t response;
695 InfoFilterOptionsRequest_t request;
696 request.filterName = "QueryFilter";
697
698 collectproto->get_filteroptions (args["c"], request, response, err, logout);
699 if (err == noError) {
700
701 FilterOption_tmap::const_iterator it;
702 FilterOption_tmap::const_iterator end = response.filterOptions.end();
703
704 // _hselection_ and _h2selection_ (Index)
705 it = response.filterOptions.find ("Index");
706 if (it != end) set_option_macro ("h", args["h"], true, (*it).second, disp);
707 if (it != end) set_option_macro ("h2", args["h2"], true,(*it).second, disp);
708
709 // _jselection_ and _j2selection_ (Subcollection)
710 it = response.filterOptions.find ("Subcollection");
711 if (it != end) set_option_macro ("j", args["j"], true,(*it).second, disp);
712 if (it != end) set_option_macro ("j2", args["j2"], true,(*it).second, disp);
713
714 // _nselection_ and _n2selection_ (Language)
715 it = response.filterOptions.find ("Language");
716 if (it != end) set_option_macro ("n", args["n"], true,(*it).second, disp);
717 if (it != end) set_option_macro ("n2", args["n2"], true,(*it).second, disp);
718
719 // _cq2selection_ (CombineQuery)
720 it = response.filterOptions.find ("CombineQuery");
721 if (it != end) set_option_macro ("cq2", args["cq2"], true,(*it).second, disp);
722
723 // _gselection_ (Level) // for mgpp collections
724 it = response.filterOptions.find("Level");
725 if (it!=end) set_option_macro("g", args["g"], false, (*it).second, disp);
726
727 // _fqfselection_ field list, for mgpp collections
728 it = response.filterOptions.find("IndexField");
729 if (it!=end) set_option_macro ("fqf", args["fqf"], true, (*it).second, disp);
730
731 }
732} // define external macros
733
734void queryaction::define_form_macros (displayclass &disp, cgiargsclass &args,
735 recptprotolistclass *protos, ostream &logout) {
736
737 // defines the following macros
738 // _regformlist_
739 // _advformlist_
740
741 if (args["ct"]=="0" || args["qto"]=="1" || (args["qto"]=="3" && args["qt"] == "0") ) // mg, or mgpp with plain only, or mgpp with both, but set to plain
742 return; // dont need these macros
743
744 // mgpp & form query only needs the macros defined
745 text_t form = "";
746 int argfqn = args.getintarg("fqn");
747
748 if (args["qf"] == "1") { // advanced form
749 form += "<tr>_firstadvformelement_</tr>\n";
750 for (int i=1; i<argfqn; i++) {
751 form += "<tr>_advformelement_</tr>\n";
752 }
753 disp.setmacro("advformlist", "query", form);
754 }
755 else { // simple form
756 for (int i=0; i<argfqn; i++) {
757 form += "<tr>_regformelement_</tr>\n";
758 }
759 disp.setmacro("regformlist", "query", form);
760 }
761
762}
763
764void queryaction::define_history_macros (displayclass &disp, cgiargsclass &args,
765 recptprotolistclass *protos, ostream &logout) {
766
767 // defines the following macros
768
769 // _searchhistorylist_
770
771 text_t historylist;
772 int arghd = args.getintarg("hd");
773 if (arghd == 0) {
774 historylist="";
775 }
776 else {
777 historylist = "<!-- Search History List -->\n";
778
779 text_t userid = args["z"];
780 text_tarray entries;
781 if (get_history_info (userid, entries, gdbmhome, logout)) {
782 int count = 1;
783 text_tarray::iterator here = entries.begin();
784 text_tarray::iterator end = entries.end();
785 int numrecords=(int)entries.size();
786 if (numrecords>arghd) { // only display some of them
787 numrecords = arghd;
788 }
789 historylist += "<form name=\"HistoryForm\"><table width=537>\n";
790
791 for (int i=0; i<numrecords;i++) {
792 text_t query;
793 text_t numdocs;
794 text_t cgiargs;
795 text_t userinfo;
796 text_t escquery;
797 split_saved_query(entries[i],numdocs,cgiargs);
798 parse_saved_args(cgiargs, "q", query); // get query string out
799 decode_cgi_arg(query); // un cgisafe it
800 escquery = escape_quotes(query); // escape the quotes and newlines
801 text_t histvalue = "histvalue";
802 histvalue += i;
803 disp.setmacro(histvalue, "query", escquery);
804 format_user_info(cgiargs, userinfo, args, protos, logout);
805
806 historylist += "<tr><td align=right>_imagehistbutton_(";
807 historylist += i;
808 historylist += ")</td>\n";
809 historylist += "<td><nobr><table border=1 cellspacing=0 ";
810 historylist += "cellpadding=0><tr><td width=365 align=left>"
811 + query
812 + "</td></tr></table></td><td width=110 align=center><small>"
813 + numdocs;
814 if (numdocs == 1) historylist += " _texthresult_";
815 else historylist += " _texthresults_";
816 if (!userinfo.empty()) {
817 historylist += "<br>( "+userinfo+" )</small></td>\n";
818 }
819 }
820 historylist+="</table></form>\n\n";
821
822 } // if get history info
823 else {
824 historylist += "_textnohistory_";
825 }
826 historylist += "<p><! ---- end of history list ----->\n";
827 } // else display list
828 disp.setmacro("searchhistorylist", "query", historylist);
829
830} // define history macros
831
832void queryaction::output_ccp (cgiargsclass &args, recptprotolistclass *protos,
833 displayclass &disp, outconvertclass &outconvert,
834 ostream &textout, ostream &logout) {
835
836 ColInfoResponse_t *cinfo = NULL;
837 comerror_t err;
838 InfoFilterOptionsResponse_t fresponse;
839 InfoFilterOptionsRequest_t frequest;
840 frequest.filterName = "QueryFilter";
841
842 text_t &index = args["h"];
843 text_t &subcollection = args["j"];
844 text_t &language = args["n"];
845
846 text_tset collections;
847 text_t arg_cc = args["cc"];
848 decode_cgi_arg (arg_cc);
849 splitchar (arg_cc.begin(), arg_cc.end(), ',', collections);
850
851 textout << outconvert << disp << "_query:header_\n"
852 << "<center>_navigationbar_</center><br>\n"
853 << "<form name=QueryForm method=get action=\"_gwcgi_\">\n"
854 << "<input type=hidden name=a value=\"q\">\n"
855 << "<input type=hidden name=site value=\"_cgiargsite_\"\n"
856 << "<input type=hidden name=e value=\"_compressedoptions_\">\n"
857 << "<input type=hidden name=ccp value=\"1\">\n"
858 << "<center><table width=_pagewidth_><tr valign=top>\n"
859 << "<td>Select collections to search for \"" << args["q"]
860 << "\" <i>(index=" << index << " subcollection=" << subcollection
861 << " language=" << language << ")</i></td>\n"
862 << "<td><input type=\"submit\" value=\"_query:textbeginsearch_\"></td>\n"
863 << "</tr></table></center>\n"
864 << "<center><table width=_pagewidth_>\n"
865 << "<tr><td>\n";
866
867 recptprotolistclass::iterator rprotolist_here = protos->begin();
868 recptprotolistclass::iterator rprotolist_end = protos->end();
869 while (rprotolist_here != rprotolist_end) {
870 if ((*rprotolist_here).p != NULL) {
871
872 text_tarray collist;
873 (*rprotolist_here).p->get_collection_list (collist, err, logout);
874 if (err == noError) {
875 text_tarray::iterator collist_here = collist.begin();
876 text_tarray::iterator collist_end = collist.end();
877 while (collist_here != collist_end) {
878
879 cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
880 // if (err == noError && cinfo.isPublic && (cinfo.buildDate > 0)) {
881 if (cinfo != NULL && (cinfo->buildDate > 0)) {
882
883 (*rprotolist_here).p->get_filteroptions (*collist_here, frequest, fresponse, err, logout);
884 if (err == noError) {
885
886 FilterOption_tmap::const_iterator it;
887 FilterOption_tmap::const_iterator end = fresponse.filterOptions.end();
888 if (!index.empty()) {
889 it = fresponse.filterOptions.find ("Index");
890 if (it == end) {collist_here ++; continue;}
891 text_tarray::const_iterator there = (*it).second.validValues.begin();
892 text_tarray::const_iterator tend = (*it).second.validValues.end();
893 while (there != tend) {
894 if (*there == index) break;
895 there ++;
896 }
897 if (there == tend) {collist_here++; continue;}
898 }
899 if (!subcollection.empty()) {
900 it = fresponse.filterOptions.find ("Subcollection");
901 if (it == end) {collist_here++; continue;}
902 text_tarray::const_iterator there = (*it).second.validValues.begin();
903 text_tarray::const_iterator tend = (*it).second.validValues.end();
904 while (there != tend) {
905 if (*there == subcollection) break;
906 there ++;
907 }
908 if (there == tend) {collist_here++; continue;}
909 }
910 if (!language.empty()) {
911 it = fresponse.filterOptions.find ("Language");
912 if (it == end) {collist_here++; continue;}
913 text_tarray::const_iterator there = (*it).second.validValues.begin();
914 text_tarray::const_iterator tend = (*it).second.validValues.end();
915 while (there != tend) {
916 if (*there == language) break;
917 there ++;
918 }
919 if (there == tend) {collist_here++; continue;}
920 }
921
922 // we've got a matching collection
923 textout << outconvert << "<input type=checkbox";
924
925 text_tset::const_iterator t = collections.find (*collist_here);
926 if (t != collections.end()) textout << outconvert << " checked";
927
928 textout << outconvert
929 << " name=cc value=\"" << *collist_here << "\">";
930
931 if (!cinfo->collectionmeta["collectionname"].empty())
932 textout << outconvert << disp << cinfo->collectionmeta["collectionname"];
933 else
934 textout << outconvert << *collist_here;
935
936 textout << outconvert << "<br>\n";
937
938 }
939 }
940 collist_here ++;
941 }
942 }
943 }
944 rprotolist_here ++;
945 }
946 textout << outconvert << disp
947 << "</td></tr></table></center>\n"
948 << "</form>\n"
949 << "_query:footer_\n";
950
951}
952
953bool queryaction::do_action (cgiargsclass &args, recptprotolistclass *protos,
954 browsermapclass *browsers, displayclass &disp,
955 outconvertclass &outconvert, ostream &textout,
956 ostream &logout) {
957
958 if (recpt == NULL) {
959 logout << "ERROR (queryaction::do_action): This action does not contain information\n"
960 << " about any receptionists. The method set_receptionist was probably\n"
961 << " not called from the module which instantiated this action.\n";
962 return true;
963 }
964
965
966
967 if (args["ccs"] == "1") {
968 if (!args["cc"].empty()) {
969 // query the selected collections
970 text_t::const_iterator b = args["cc"].begin();
971 text_t::const_iterator e = args["cc"].end();
972 if (findchar (b, e, ',') != e) {
973 if (!search_multiple_collections (args, protos, browsers, disp, outconvert,
974 textout, logout)) return false;
975 return true;
976 } else {
977 if (!search_single_collection (args, args["cc"], protos, browsers, disp,
978 outconvert, textout, logout)) return false;
979 return true;
980 }
981 }
982 }
983
984 // simply query the current collection
985 if (!search_single_collection (args, args["c"], protos, browsers, disp,
986 outconvert, textout, logout)) return false;
987 return true;
988}
989
990bool queryaction::search_multiple_collections (cgiargsclass &args, recptprotolistclass *protos,
991 browsermapclass *browsers, displayclass &disp,
992 outconvertclass &outconvert, ostream &textout,
993 ostream &logout) {
994
995 text_tarray collections;
996
997 text_t arg_cc = args["cc"];
998 decode_cgi_arg (arg_cc);
999 splitchar (arg_cc.begin(), arg_cc.end(), ',', collections);
1000
1001 if (collections.empty()) {
1002 logout << "queryaction::search_multiple_collections: No collections "
1003 << "set for doing multiple query - will search current collection\n";
1004 textout << outconvert << disp << "_query:textwarningnocollections_\n";
1005 return search_single_collection (args, args["c"], protos, browsers, disp,
1006 outconvert, textout, logout);
1007 }
1008
1009 // queryaction uses "VList" browser to display results,
1010 // a queries clasification is "Search"
1011 text_t browsertype = "VList";
1012 text_t classification = "Search";
1013
1014 QueryResult_tset results;
1015 map<text_t, colinfo_t, lttext_t> colinfomap;
1016
1017 ColInfoResponse_t *cinfo = NULL;
1018 recptproto *collectproto = NULL;
1019 comerror_t err;
1020 FilterRequest_t request;
1021 FilterResponse_t response;
1022 request.filterResultOptions = FROID | FRmetadata | FRtermFreq | FRranking;
1023 text_t freqmsg = "_textfreqmsg1_";
1024 int numdocs = 0;
1025 isapprox isApprox = Exact;
1026
1027 text_t formattedstring = "";
1028 get_formatted_query_string(formattedstring, args, disp, logout);
1029
1030 if (formattedstring.empty()) {
1031 // dont bother doing a query if no query string
1032 define_history_macros (disp, args, protos, logout);
1033 textout << outconvert << disp << "_query:header_\n"
1034 << "_query:content_";
1035 textout << outconvert << disp << "_query:footer_";
1036
1037 return true;
1038 }
1039 bool syntax_error = false;
1040
1041 set_queryfilter_options (request, formattedstring, args);
1042
1043 // need to retrieve maxdocs matches for each collection
1044 // (will eventually want to tidy this up, do so caching etc.)
1045 OptionValue_t option;
1046 option.name = "StartResults";
1047 option.value = "1";
1048 request.filterOptions.push_back (option);
1049
1050 option.name = "EndResults";
1051 option.value = args["m"];
1052 request.filterOptions.push_back (option);
1053
1054 text_tarray::iterator col_here = collections.begin();
1055 text_tarray::iterator col_end = collections.end();
1056
1057 map<text_t, int, lttext_t> termfreqs;
1058 while (col_here != col_end) {
1059
1060 request.fields.erase (request.fields.begin(), request.fields.end());
1061 request.getParents = false;
1062
1063 collectproto = protos->getrecptproto (*col_here, logout);
1064 if (collectproto == NULL) {
1065 logout << outconvert << "queryaction::search_multiple_collections: " << *col_here
1066 << " collection has a NULL collectproto, ignoring\n";
1067 col_here ++;
1068 continue;
1069 }
1070 cinfo = recpt->get_collectinfo_ptr (collectproto, *col_here, logout);
1071 if (cinfo == NULL) {
1072 logout << "ERROR (query_action::search_multiple_collections): get_collectinfo_ptr returned NULL\n";
1073 col_here ++;
1074 continue;
1075 }
1076
1077 browserclass *bptr = browsers->getbrowser (browsertype);
1078
1079 // get the formatstring if there is one
1080 text_t formatstring;
1081 if (!get_formatstring (classification, browsertype,
1082 cinfo->format, formatstring))
1083 formatstring = bptr->get_default_formatstring();
1084
1085 bptr->load_metadata_defaults (request.fields);
1086
1087 format_t *formatlistptr = new format_t();
1088 parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
1089
1090 colinfo_t thiscolinfo;
1091 thiscolinfo.formatlistptr = formatlistptr;
1092 thiscolinfo.browserptr = bptr;
1093 colinfomap[*col_here] = thiscolinfo;
1094
1095 // do the query
1096 collectproto->filter (*col_here, request, response, err, logout);
1097 if (err != noError && err != syntaxError) {
1098 outconvertclass text_t2ascii;
1099 logout << text_t2ascii
1100 << "queryaction::search_multiple_collections: call to QueryFilter failed "
1101 << "for " << *col_here << " collection (" << get_comerror_string (err) << ")\n";
1102 return false;
1103 }
1104
1105 if (err == syntaxError) {
1106 syntax_error = true;
1107 freqmsg = "_textinvalidquery_";
1108 // assume the syntax will be invalid for all colls
1109 break;
1110 }
1111 if (isApprox == Exact)
1112 isApprox = response.isApprox;
1113 else if (isApprox == MoreThan)
1114 if (response.isApprox == Approximate)
1115 isApprox = response.isApprox;
1116
1117 TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
1118 TermInfo_tarray::const_iterator end_term = response.termInfo.end();
1119 while (this_term != end_term) {
1120 termfreqs[(*this_term).term] += (*this_term).freq;
1121 if ((col_here+1) == col_end) {
1122 freqmsg += (*this_term).term + ": " + termfreqs[(*this_term).term];
1123 if ((this_term+1) != end_term) freqmsg += ", ";
1124 }
1125 this_term ++;
1126 }
1127
1128 if (response.numDocs > 0) {
1129 numdocs += response.numDocs;
1130
1131 QueryResult_t thisresult;
1132 thisresult.collection = *col_here;
1133 ResultDocInfo_tarray::iterator doc_here = response.docInfo.begin();
1134 ResultDocInfo_tarray::iterator doc_end = response.docInfo.end();
1135 while (doc_here != doc_end) {
1136 thisresult.doc = *doc_here;
1137 results.insert (thisresult);
1138 doc_here ++;
1139 }
1140 }
1141 col_here ++;
1142 } // for each coll
1143
1144 disp.setmacro ("freqmsg", "query", freqmsg);
1145
1146 define_query_macros( args, disp, numdocs, isApprox);
1147 // save the query if appropriate
1148 save_search_history(args, numdocs, isApprox);
1149 define_history_macros (disp, args, protos, logout);
1150
1151 textout << outconvert << disp << "_query:header_\n"
1152 << "_query:content_";
1153
1154 if (!syntax_error) {
1155
1156 // now go through each result and output it
1157 QueryResult_tset::iterator res_here = results.begin();
1158 QueryResult_tset::iterator res_end = results.end();
1159 text_tset metadata; // empty !!
1160 bool getParents = false; // don't care !!
1161 bool use_table;
1162 ResultDocInfo_t thisdoc;
1163 format_t *formatlistptr = NULL;
1164 browserclass *browserptr = NULL;
1165
1166 int count = 1;
1167 int firstdoc = args.getintarg("r");
1168 int hitsperpage = args.getintarg("o");
1169 int thislast = firstdoc + (hitsperpage - 1);
1170
1171 // output results
1172 while (res_here != res_end) {
1173 if (count < firstdoc) {count ++; res_here ++; continue;}
1174 if (count > thislast) break;
1175 formatlistptr = colinfomap[(*res_here).collection].formatlistptr;
1176 browserptr = colinfomap[(*res_here).collection].browserptr;
1177 thisdoc = (*res_here).doc;
1178 use_table = is_table_content (formatlistptr);
1179
1180 collectproto = protos->getrecptproto ((*res_here).collection, logout);
1181 if (collectproto == NULL) {
1182 logout << outconvert << "queryaction::search_multiple_collections: " << (*res_here).collection
1183 << " collection has a NULL collectproto, ignoring results\n";
1184 res_here ++;
1185 continue;
1186 }
1187
1188 browserptr->output_section_group (thisdoc, args, (*res_here).collection, 0,
1189 formatlistptr, use_table, metadata, getParents,
1190 collectproto, disp, outconvert, textout, logout);
1191 // textout << outconvert << "(ranking: " << (*res_here).doc.ranking << ")\n";
1192 res_here ++;
1193 count ++;
1194 }
1195 }
1196 textout << outconvert << disp << "_query:footer_";
1197
1198 // clean up the format_t pointers
1199 map<text_t, colinfo_t, lttext_t>::iterator here = colinfomap.begin();
1200 map<text_t, colinfo_t, lttext_t>::iterator end = colinfomap.end();
1201 while (here != end) {
1202 delete ((*here).second.formatlistptr);
1203 here ++;
1204 }
1205 return true;
1206}
1207
1208bool queryaction::search_single_collection (cgiargsclass &args, const text_t &collection,
1209 recptprotolistclass *protos, browsermapclass *browsers,
1210 displayclass &disp, outconvertclass &outconvert,
1211 ostream &textout, ostream &logout) {
1212
1213 recptproto *collectproto = protos->getrecptproto (collection, logout);
1214 if (collectproto == NULL) {
1215 logout << outconvert << "queryaction::search_single_collection: " << collection
1216 << " collection has a NULL collectproto\n";
1217 return false;
1218 }
1219
1220 // queryaction uses "VList" browser to display results,
1221 // a queries clasification is "Search"
1222 text_t browsertype = "VList";
1223 text_t classification = "Search";
1224
1225 comerror_t err;
1226 ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
1227
1228 if (cinfo == NULL) {
1229 logout << "ERROR (query_action::search_single_collection): get_collectinfo_ptr returned NULL\n";
1230 return false;
1231 }
1232
1233 browserclass *bptr = browsers->getbrowser (browsertype);
1234
1235 // get the formatstring if there is one
1236 text_t formatstring;
1237 if (!get_formatstring (classification, browsertype,
1238 cinfo->format, formatstring)) {
1239 formatstring = bptr->get_default_formatstring();
1240 }
1241 FilterRequest_t request;
1242 FilterResponse_t response;
1243 bptr->set_filter_options (request, args);
1244 bptr->load_metadata_defaults (request.fields);
1245
1246 format_t *formatlistptr = new format_t();
1247 parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
1248
1249 // do the query
1250 request.filterResultOptions = FROID | FRmetadata | FRtermFreq;
1251 text_t formattedstring = "";
1252 get_formatted_query_string(formattedstring, args, disp, logout);
1253
1254
1255 if (!formattedstring.empty()) { // do the query
1256 // note! formattedstring is in unicode! mg and mgpp must convert!
1257 set_queryfilter_options (request, formattedstring, args);
1258 collectproto->filter (collection, request, response, err, logout);
1259 if (err != noError && err != syntaxError) {
1260 outconvertclass text_t2ascii;
1261 logout << text_t2ascii
1262 << "queryaction::search_single_collections: call to QueryFilter failed "
1263 << "for " << collection << " collection (" << get_comerror_string (err) << ")\n";
1264 return false;
1265 }
1266
1267 bool syntax_error = false;
1268 if (err == syntaxError) syntax_error = true;
1269 //return false;
1270 define_query_macros (args, disp, response.numDocs, response.isApprox);
1271 define_single_query_macros(args, disp, response, syntax_error);
1272
1273 // save the query if appropriate
1274 save_search_history(args, response.numDocs, response.isApprox);
1275 }
1276 define_history_macros (disp, args, protos, logout);
1277
1278 textout << outconvert << disp << "_query:header_\n"
1279 << "_query:content_";
1280
1281 // output the results
1282 bool use_table = is_table_content (formatlistptr);
1283 bptr->output_section_group (response, args, collection, 0, formatlistptr,
1284 use_table, request.fields, request.getParents,
1285 collectproto, disp, outconvert, textout, logout);
1286
1287
1288 textout << outconvert << disp << "_query:footer_";
1289
1290 delete (formatlistptr);
1291
1292 return true;
1293}
1294
1295// does the formatting of the query string - either uses q for a text search
1296// or the form values for an form search
1297// also adds dates if appropriate in text search
1298void queryaction::get_formatted_query_string (text_t &formattedstring,
1299 cgiargsclass &args,
1300 displayclass &disp,
1301 ostream &logout) {
1302 if (args["qt"]=="0" && args["qto"] != "2") { // normal text search
1303 formattedstring = args["q"];
1304 // remove & | ! for simple search, insert spaces for chinese
1305 format_querystring (formattedstring, args.getintarg("b"));
1306 if (args["ct"]=="1") { // mgpp - we need to add in the field info
1307 format_field_info(formattedstring, args["fqf"]);
1308 }
1309 add_dates(formattedstring, args.getintarg("ds"), args.getintarg("de"),
1310 args.getintarg("dsbc"), args.getintarg("debc"));
1311 }
1312 else if (args["qt"]=="1" || args["qto"]=="2"){ // form search
1313
1314 if (args["qf"]=="1" && args["fqa"]=="1") { // explicit query
1315 formattedstring = args["q"];
1316 }
1317 else { // form search
1318 if (args["qf"]=="0") { // regular form
1319 parse_reg_query_form(formattedstring, args);
1320 }
1321 else { // advanced form
1322 parse_adv_query_form(formattedstring, args);
1323 }
1324 args["q"] = formattedstring;
1325
1326 // reset the cgiargfqv macro - need to escape any quotes in it
1327 disp.setmacro("cgiargfqv", "query", escape_quotes(args["fqv"]));
1328
1329 // also reset the _cgiargq_ macro as it has changed now
1330 disp.setmacro("cgiargq", "Global", html_safe(args["q"]));
1331
1332 // reset the compressed options to include the q arg
1333 text_t compressedoptions = recpt->get_compressed_arg(args, logout);
1334 if (!compressedoptions.empty()) {
1335 disp.setmacro ("compressedoptions", "Global", dm_safe(compressedoptions));
1336 // need a decoded version of compressedoptions for use within forms
1337 // as browsers encode values from forms before sending to server
1338 // (e.g. %25 becomes %2525)
1339 decode_cgi_arg (compressedoptions);
1340 disp.setmacro ("decodedcompressedoptions", "Global", dm_safe(compressedoptions));
1341 }
1342 } // form search
1343 } // args["qt"]=1
1344 else {
1345 logout << "ERROR (query_action::get_formatted_query_string): querytype not defined\n";
1346 }
1347}
1348
1349
1350// define_query_macros sets the macros that couldn't be set until the
1351// query had been done. Those macros are
1352// _resultline_, _nextfirst_, _nextlast_, _prevfirst_, _prevlast_,
1353// _thisfirst_, and _thislast_
1354// this has been simplified so it can be used with both search_single_coll
1355// and search_multiple_coll
1356void queryaction::define_query_macros (cgiargsclass &args, displayclass &disp,
1357 int numdocs, isapprox isApprox) {
1358
1359 // set up _resultline_ macro
1360 text_t resline;
1361 int maxdocs = args.getintarg("m");
1362 if (num_phrases > 0) isApprox = Exact;
1363 if (maxdocs == -1) maxdocs = numdocs;
1364 else if (numdocs > maxdocs) {
1365 numdocs = maxdocs;
1366 isApprox = MoreThan;
1367 }
1368
1369 if (isApprox == Approximate) resline = "_textapprox_";
1370 else if (isApprox == MoreThan) resline = "_textmorethan_";
1371
1372 if (numdocs == 0) resline = "_textnodocs_";
1373 else if (numdocs == 1) resline += "_text1doc_";
1374 else resline += text_t(numdocs) + " _textlotsdocs_";
1375
1376 disp.setmacro("resultline", "query", resline);
1377
1378 int firstdoc = args.getintarg("r");
1379 int hitsperpage = args.getintarg("o");
1380 if (hitsperpage == -1) hitsperpage = numdocs;
1381
1382 // set up _thisfirst_ and _thislast_ macros
1383 disp.setmacro ("thisfirst", "query", firstdoc);
1384 int thislast = firstdoc + (hitsperpage - 1);
1385 if (thislast > numdocs) thislast = numdocs;
1386 disp.setmacro ("thislast", "query", thislast);
1387
1388 // set up _prevfirst_ and _prevlast_ macros
1389 if (firstdoc > 1) {
1390 disp.setmacro ("prevlast", "query", firstdoc - 1);
1391 int prevfirst = firstdoc - hitsperpage;
1392 if (prevfirst < 1) prevfirst = 1;
1393 disp.setmacro ("prevfirst", "query", prevfirst);
1394 }
1395
1396 // set up _nextfirst_ and _nextlast_ macros
1397 if (thislast < numdocs) {
1398 disp.setmacro ("nextfirst", "query", thislast + 1);
1399 int nextlast = thislast + hitsperpage;
1400 if (nextlast > numdocs) nextlast = numdocs;
1401 disp.setmacro ("nextlast", "query", nextlast);
1402 }
1403}
1404
1405// define_single_query_macros sets the extra macros for search_single_coll
1406// that couldn't be set until the query had been done. Those macros are
1407// _freqmsg_, _quotedquery_
1408void queryaction::define_single_query_macros (cgiargsclass &args,
1409 displayclass &disp,
1410 const FilterResponse_t &response,
1411 bool syntax_error) {
1412 // set up _freqmsg_ and _quotedquery_ macros
1413
1414 text_t freqmsg = "";
1415 if (syntax_error) {
1416 freqmsg = "_textinvalidquery_";
1417 } else {
1418 freqmsg = "_textfreqmsg1_";
1419 TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
1420 TermInfo_tarray::const_iterator end_term = response.termInfo.end();
1421 while (this_term != end_term) {
1422 freqmsg += (*this_term).term + ": " + (*this_term).freq;
1423 if ((this_term + 1) != end_term)
1424 freqmsg += ", ";
1425 this_term ++;
1426 }
1427 }
1428 disp.setmacro ("freqmsg", "query", freqmsg);
1429}
1430
1431// should this change for cross coll search??
1432bool queryaction::save_search_history (cgiargsclass &args, int numdocs,
1433 isapprox isApprox) {
1434 if (args["q"]=="") return true; // null query, dont save
1435 if (args["hs"]=="0") return true; // only save when submit query pressed
1436
1437 // get userid
1438 text_t userid = args["z"];
1439
1440 // the number of docs goes on the front of the query string
1441 text_t query = text_t(numdocs);
1442 if (isApprox==MoreThan) { // there were more docs found
1443 query.push_back('+');
1444 }
1445 query += "c="+args["c"];
1446 query += "&h="+args["h"];
1447 query += "&t="+args["t"];
1448 query += "&b="+args["b"];
1449 query += "&j="+args["j"];
1450 query += "&n="+args["n"];
1451 query += "&s="+args["s"];
1452 query += "&k="+args["k"];
1453 query += "&g="+args["g"];
1454
1455 text_t qstring = args["q"];
1456 text_t formattedquery =cgi_safe(qstring);
1457 query += "&q="+formattedquery;
1458
1459 bool display=false;
1460 int hd = args.getintarg("hd");
1461 if (hd > 0) display=true;
1462 if (set_history_info(userid, query, gdbmhome, display)) return true;
1463 else return false;
1464
1465
1466}
1467
Note: See TracBrowser for help on using the repository browser.