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

Last change on this file since 5633 was 5633, checked in by davidb, 21 years ago

Macro name used by date search updated to fit in with restrutured
web form for mgpp built collections.

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