source: main/trunk/greenstone2/runtime-src/src/recpt/queryaction.cpp@ 23420

Last change on this file since 23420 was 23420, checked in by max, 13 years ago

qt argument can be in the range 0..2 these days (support for sql based querying)

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