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

Last change on this file since 12380 was 12380, checked in by mdewsnip, 18 years ago

Now shows the stopwords removed by Lucene, many thanks to Me and DL Consulting Ltd.

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