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

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

the call to filter gets an err of syntaxError if the query was invalid. in this case, we set the freqmsg macro to say invalid query syntax, rather than word count: ... and dont bother to display the results.

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