source: main/trunk/greenstone2/runtime-src/src/recpt/basequeryaction.cpp@ 22984

Last change on this file since 22984 was 22984, checked in by ak19, 14 years ago
  1. Undoing commit of 22934 where decode_commas was called on stem and fold comma separated list: previously separated due to url-encoding of commas. Now that the problem has been fixed at the source, the decode_commas hack is no longer necessary. 2. Commas in stem and fold are no longer url-encoded because the multiple_value field of the continuously-reused struct arg_ainfo is always set back to the default false after ever being set to true. So it no longer subtly stays at true to affect Greenstone functioning in unforeseen ways (such as suddenly and unnecessarily URL-encoding commas where this is not wanted).
File size: 26.5 KB
Line 
1/**********************************************************************
2 *
3 * basequeryaction.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 "basequeryaction.h"
27#include "querytools.h"
28#include "formattools.h"
29#include "cgiutils.h"
30#include "OIDtools.h"
31#include "fileutil.h"
32#include "text_t.h"
33#include "historydb.h"
34#include "htmlutils.h" // for html_safe in do_action
35#include "gsdltools.h"
36#include "phrases.h" // for get_phrases
37#include <stdlib.h> // for strtol
38#include <assert.h>
39
40void colinfo_t::clear () {
41 formatlistptr = NULL;
42 browserptr = NULL;
43}
44
45void QueryResult_t::clear() {
46 doc.clear();
47 collection.clear();
48}
49
50basequeryaction::basequeryaction () {
51
52 recpt = NULL;
53
54 cgiarginfo arg_ainfo;
55
56 // "q"
57 arg_ainfo.shortname = "q";
58 arg_ainfo.longname = "query string";
59 arg_ainfo.multiplechar = true;
60 arg_ainfo.multiplevalue = false;
61 arg_ainfo.defaultstatus = cgiarginfo::weak;
62 arg_ainfo.argdefault = g_EmptyText;
63 arg_ainfo.savedarginfo = cgiarginfo::must;
64 argsinfo.addarginfo (NULL, arg_ainfo);
65
66 // "q2"
67 arg_ainfo.shortname = "q2";
68 arg_ainfo.longname = "query string for second query";
69 arg_ainfo.multiplechar = true;
70 arg_ainfo.multiplevalue = false;
71 arg_ainfo.defaultstatus = cgiarginfo::weak;
72 arg_ainfo.argdefault = g_EmptyText;
73 arg_ainfo.savedarginfo = cgiarginfo::must;
74 argsinfo.addarginfo (NULL, arg_ainfo);
75
76 // "cq2" ""=don't combine, "and", "or", "not"
77 arg_ainfo.shortname = "cq2";
78 arg_ainfo.longname = "combine queries";
79 arg_ainfo.multiplechar = true;
80 arg_ainfo.multiplevalue = false;
81 arg_ainfo.defaultstatus = cgiarginfo::weak;
82 arg_ainfo.argdefault = g_EmptyText;
83 arg_ainfo.savedarginfo = cgiarginfo::must;
84 argsinfo.addarginfo (NULL, arg_ainfo);
85
86
87 // "m"
88 arg_ainfo.shortname = "m";
89 arg_ainfo.longname = "maximum number of documents";
90 arg_ainfo.multiplechar = true;
91 arg_ainfo.multiplevalue = false;
92 arg_ainfo.defaultstatus = cgiarginfo::weak;
93 arg_ainfo.argdefault = "50";
94 arg_ainfo.savedarginfo = cgiarginfo::must;
95 argsinfo.addarginfo (NULL, arg_ainfo);
96
97 // "o"
98 arg_ainfo.shortname = "o";
99 arg_ainfo.longname = "hits per page";
100 arg_ainfo.multiplechar = true;
101 arg_ainfo.multiplevalue = false;
102 arg_ainfo.defaultstatus = cgiarginfo::weak;
103 arg_ainfo.argdefault = "20";
104 arg_ainfo.savedarginfo = cgiarginfo::must;
105 argsinfo.addarginfo (NULL, arg_ainfo);
106
107 // "r"
108 arg_ainfo.shortname = "r";
109 arg_ainfo.longname = "start results from";
110 arg_ainfo.multiplechar = true;
111 arg_ainfo.multiplevalue = false;
112 arg_ainfo.defaultstatus = cgiarginfo::weak;
113 arg_ainfo.argdefault = "1";
114 arg_ainfo.savedarginfo = cgiarginfo::must;
115 argsinfo.addarginfo (NULL, arg_ainfo);
116
117
118 // "ifl" - I'm feeling lucky! (Go directly to a matching document)
119 arg_ainfo.shortname = "ifl";
120 arg_ainfo.longname = "i'm feeling lucky";
121 arg_ainfo.multiplechar = false;
122 arg_ainfo.multiplevalue = false;
123 arg_ainfo.defaultstatus = cgiarginfo::weak;
124 arg_ainfo.argdefault = g_EmptyText;
125 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
126 argsinfo.addarginfo (NULL, arg_ainfo);
127
128 // "ifln" - I'm feeling lucky number (Go directly to the nth matching document)
129 arg_ainfo.shortname = "ifln";
130 arg_ainfo.longname = "i'm feeling lucky number";
131 arg_ainfo.multiplechar = true;
132 arg_ainfo.multiplevalue = false;
133 arg_ainfo.defaultstatus = cgiarginfo::weak;
134 arg_ainfo.argdefault = "1";
135 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
136 argsinfo.addarginfo (NULL, arg_ainfo);
137
138 // "srn" - the next search result
139 arg_ainfo.shortname = "srn";
140 arg_ainfo.longname = "the next search result number";
141 arg_ainfo.multiplechar = true;
142 arg_ainfo.multiplevalue = false;
143 arg_ainfo.defaultstatus = cgiarginfo::weak;
144 arg_ainfo.argdefault = "0";
145 arg_ainfo.savedarginfo = cgiarginfo::must;
146 argsinfo.addarginfo (NULL, arg_ainfo);
147
148 // "srp" - the previous search result
149 arg_ainfo.shortname = "srp";
150 arg_ainfo.longname = "the previous search result number";
151 arg_ainfo.multiplechar = true;
152 arg_ainfo.multiplevalue = false;
153 arg_ainfo.defaultstatus = cgiarginfo::weak;
154 arg_ainfo.argdefault = "0";
155 arg_ainfo.savedarginfo = cgiarginfo::must;
156 argsinfo.addarginfo (NULL, arg_ainfo);
157
158 // "sf" - Sort field. Set to field to be used for sorting search reult
159 // set (only implemented for lucene collections at present).
160 arg_ainfo.shortname = "sf";
161 arg_ainfo.longname = "sort field";
162 arg_ainfo.multiplechar = true;
163 arg_ainfo.multiplevalue = false;
164 arg_ainfo.defaultstatus = cgiarginfo::weak;
165 arg_ainfo.argdefault = g_EmptyText;
166 arg_ainfo.savedarginfo = cgiarginfo::must;
167 argsinfo.addarginfo (NULL, arg_ainfo);
168
169
170 // "fqn" - number of fields in the query form
171 arg_ainfo.shortname = "fqn";
172 arg_ainfo.longname = "form query num fields";
173 arg_ainfo.multiplechar = true;
174 arg_ainfo.multiplevalue = false;
175 arg_ainfo.defaultstatus = cgiarginfo::weak;
176 arg_ainfo.argdefault = "4";
177 arg_ainfo.savedarginfo = cgiarginfo::must;
178 argsinfo.addarginfo (NULL, arg_ainfo);
179
180 // "fqf" - the list of field names in the form query
181 // - a comma separated list
182 arg_ainfo.shortname = "fqf";
183 arg_ainfo.longname = "form query fields";
184 arg_ainfo.multiplechar = true;
185 arg_ainfo.multiplevalue = false;
186 arg_ainfo.defaultstatus = cgiarginfo::weak;
187 arg_ainfo.argdefault = g_EmptyText;
188 arg_ainfo.savedarginfo = cgiarginfo::must;
189 argsinfo.addarginfo (NULL, arg_ainfo);
190
191 // "fqv" - the list of values in the form query
192 // - a comma separated list
193 arg_ainfo.shortname = "fqv";
194 arg_ainfo.longname = "form query values";
195 arg_ainfo.multiplechar = true;
196 arg_ainfo.multiplevalue = false;
197 arg_ainfo.defaultstatus = cgiarginfo::weak;
198 arg_ainfo.argdefault = g_EmptyText;
199 arg_ainfo.savedarginfo = cgiarginfo::must;
200 argsinfo.addarginfo (NULL, arg_ainfo);
201
202
203 // "fqc" - the list of boolean operators in the form query
204 // - a comma separated list
205 arg_ainfo.shortname = "fqc";
206 arg_ainfo.longname = "form query combines";
207 arg_ainfo.multiplechar = true;
208 arg_ainfo.multiplevalue = false;
209 arg_ainfo.defaultstatus = cgiarginfo::weak;
210 arg_ainfo.argdefault = g_EmptyText;
211 arg_ainfo.savedarginfo = cgiarginfo::must;
212 argsinfo.addarginfo (NULL, arg_ainfo);
213
214 // "fqa" - form query advanced - for "run query"
215 arg_ainfo.shortname = "fqa";
216 arg_ainfo.longname = "form query advanced query";
217 arg_ainfo.multiplechar = false;
218 arg_ainfo.multiplevalue = false;
219 arg_ainfo.defaultstatus = cgiarginfo::weak;
220 arg_ainfo.argdefault = "0";
221 arg_ainfo.savedarginfo = cgiarginfo::must;
222 argsinfo.addarginfo (NULL, arg_ainfo);
223
224 // "fuzziness" controls how closely the search terms must match
225 // 100 = exact match, 0 = very inexact match (only implemented for Lucene)
226 arg_ainfo.shortname = "fuzziness";
227 arg_ainfo.longname = "Lucene fuzziness value";
228 arg_ainfo.multiplechar = true;
229 arg_ainfo.multiplevalue = false;
230 arg_ainfo.defaultstatus = cgiarginfo::weak;
231 arg_ainfo.argdefault = g_EmptyText;
232 arg_ainfo.savedarginfo = cgiarginfo::must;
233 argsinfo.addarginfo (NULL, arg_ainfo);
234
235 // "hd" history display - search history only displayed when
236 // this var set to something other than 0
237 // this number of records is displayed
238 arg_ainfo.shortname = "hd";
239 arg_ainfo.longname = "history display";
240 arg_ainfo.multiplechar = true;
241 arg_ainfo.multiplevalue = false;
242 arg_ainfo.defaultstatus = cgiarginfo::weak;
243 arg_ainfo.argdefault = "0";
244 arg_ainfo.savedarginfo = cgiarginfo::must;
245 argsinfo.addarginfo (NULL, arg_ainfo);
246
247 // "hs" save - set to 1 in query form, so only save when submit
248 // query
249 // 0 = no save 1 = save
250 arg_ainfo.shortname = "hs";
251 arg_ainfo.longname = "history save";
252 arg_ainfo.multiplechar = false;
253 arg_ainfo.multiplevalue = false;
254 arg_ainfo.defaultstatus = cgiarginfo::weak;
255 arg_ainfo.argdefault = "0";
256 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
257 argsinfo.addarginfo (NULL, arg_ainfo);
258}
259
260void basequeryaction::configure (const text_t &key, const text_tarray &cfgline) {
261 action::configure (key, cfgline);
262}
263
264bool basequeryaction::init (ostream &logout) {
265 return action::init (logout);
266}
267
268bool basequeryaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
269 recptprotolistclass * /*protos*/, ostream &logout) {
270
271
272 // check m argument
273 int arg_m = args.getintarg("m");
274 if (arg_m < -1) {
275 logout << "Warning: \"m\" argument less than -1 (" << arg_m << ")\n";
276 cgiarginfo *minfo = argsinfo.getarginfo ("m");
277 if (minfo != NULL) args["m"] = minfo->argdefault;
278 }
279
280 // check o argument
281 int arg_o = args.getintarg("o");
282 if (arg_o < -1) {
283 logout << "Warning: \"o\" argument less than -1 (" << arg_o << ")\n";
284 cgiarginfo *oinfo = argsinfo.getarginfo ("o");
285 if (oinfo != NULL) args["o"] = oinfo->argdefault;
286 }
287
288 // check r argument
289 int arg_r = args.getintarg("r");
290 if (arg_r < 1) {
291 logout << "Warning: \"r\" argument less than 1 (" << arg_r << ")\n";
292 cgiarginfo *rinfo = argsinfo.getarginfo ("r");
293 if (rinfo != NULL) args["r"] = rinfo->argdefault;
294 }
295
296 //check hd argument
297 int arg_hd = args.getintarg("hd");
298 if (arg_hd <0 ) {
299 logout << "Warning: \"hd\" argument less than 0 (" << arg_hd << ")\n";
300 cgiarginfo *hdinfo = argsinfo.getarginfo ("hd");
301 if (hdinfo != NULL) args["hd"] = hdinfo->argdefault;
302 }
303
304 //check hs argument
305 int arg_hs = args.getintarg("hs");
306 if (arg_hs !=0 && arg_hs !=1) {
307 logout << "Warning: \"hs\" argument out of range (" << arg_hs << ")\n";
308 cgiarginfo *hsinfo = argsinfo.getarginfo ("hs");
309 if (hsinfo != NULL) args["hs"] = hsinfo->argdefault;
310 }
311
312 return true;
313}
314
315void basequeryaction::get_cgihead_info (cgiargsclass &args, recptprotolistclass * /*protos*/,
316 response_t &response, text_t &response_data,
317 ostream &/*logout*/) {
318 // If this is an "I'm feeling lucky" request, we don't know the target location until later
319 if (!args["ifl"].empty()) {
320 response = undecided_location;
321 return;
322 }
323
324 response = content;
325 response_data = "text/html";
326}
327
328
329
330
331void basequeryaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
332 recptprotolistclass * protos,
333 ostream &logout)
334{
335 // The following macros are set later (in define_query_macros) as they can't be set until
336 // the query has been done.
337 // _quotedquery_ the part of the query string that was quoted for post-processing
338 // _freqmsg_ the term frequency string
339
340 // _resultline_ the "x documents matched the query" string
341
342 // _prevfirst_ these are used when setting up the links to previous/next
343 // _prevlast_ pages of results (_thisfirst_ and _thislast_ are used to set
344 // _nextfirst_ the 'results x-x for query: xxxx' string in the title bar)
345 // _nextlast_
346 // _thisfirst_
347 // _thislast_
348
349
350 define_form_macros(disp, args, protos, logout);
351}
352
353
354
355
356
357// define_query_macros sets the macros that couldn't be set until the
358// query had been done. Those macros are
359// _resultline_, _nextfirst_, _nextlast_, _prevfirst_, _prevlast_,
360// _thisfirst_, and _thislast_ and _quotedquery_
361// this has been simplified so it can be used with both search_single_coll
362// and search_multiple_coll
363void basequeryaction::define_query_macros (cgiargsclass &args,
364 displayclass &disp,
365 int numdocs, isapprox isApprox) {
366
367 // set up _resultline_ macro
368 text_t resline;
369 int maxdocs = args.getintarg("m");
370 if (maxdocs == -1) maxdocs = numdocs;
371 else if (numdocs > maxdocs) {
372 numdocs = maxdocs;
373 isApprox = MoreThan;
374 }
375
376 if (isApprox == Approximate) resline = "_textapprox_";
377 else if (isApprox == MoreThan) resline = "_textmorethan_";
378
379 if (numdocs == 0) resline = "_textnodocs_";
380 else if (numdocs == 1) resline += "_text1doc_";
381 else resline += text_t(numdocs) + " _textlotsdocs_";
382
383 disp.setmacro("resultline", "query", resline);
384
385 int firstdoc = args.getintarg("r");
386 int hitsperpage = args.getintarg("o");
387 if (hitsperpage == -1) hitsperpage = numdocs;
388
389 // set up _thisfirst_ and _thislast_ macros
390 disp.setmacro ("thisfirst", "query", firstdoc);
391 int thislast = firstdoc + (hitsperpage - 1);
392 if (thislast > numdocs) thislast = numdocs;
393 disp.setmacro ("thislast", "query", thislast);
394
395 // set up _prevfirst_ and _prevlast_ macros
396 if (firstdoc > 1) {
397 disp.setmacro ("prevlast", "query", firstdoc - 1);
398 int prevfirst = firstdoc - hitsperpage;
399 if (prevfirst < 1) prevfirst = 1;
400 disp.setmacro ("prevfirst", "query", prevfirst);
401 }
402
403 // set up _nextfirst_ and _nextlast_ macros
404 if (thislast < numdocs) {
405 disp.setmacro ("nextfirst", "query", thislast + 1);
406 int nextlast = thislast + hitsperpage;
407 if (nextlast > numdocs) nextlast = numdocs;
408 disp.setmacro ("nextlast", "query", nextlast);
409 }
410}
411
412
413// sets the selection box macros such as:
414// _hselection_, _jselection_, _nselection_ _gselection_, _fqfselection_
415
416void basequeryaction::set_option_macro (const text_t &macroname,
417 text_t current_value,
418 bool display_single,
419 bool add_js_update,
420 const FilterOption_t &option,
421 displayclass &disp)
422{
423 if (option.validValues.empty()) return;
424 if (option.validValues.size() == 1) {
425 if (display_single) {
426 disp.setmacro (macroname + "selection", displayclass::defaultpackage, "_" + option.defaultValue + "_");
427 }
428 return;
429 }
430 if (option.validValues.size() < 2) return;
431
432 text_t macrovalue = "<select name=\"" + macroname + "\"";
433 if (add_js_update) {
434 macrovalue += " onChange=\"update"+macroname+"();\"";
435 }
436 macrovalue += ">\n";
437
438 if (current_value.empty()) current_value = option.defaultValue;
439
440 text_tarray::const_iterator thisvalue = option.validValues.begin();
441 text_tarray::const_iterator endvalue = option.validValues.end();
442
443 while (thisvalue != endvalue) {
444 macrovalue += "<option value=\"" + *thisvalue + "\"";
445 if (*thisvalue == current_value)
446 macrovalue += " selected";
447 macrovalue += ">_" + *thisvalue + "_\n";
448 ++thisvalue;
449 }
450 macrovalue += "</select>\n";
451 disp.setmacro (macroname + "selection", displayclass::defaultpackage, macrovalue);
452}
453
454
455
456// sets the selection box macros such as:
457// _sqlfqfselection_
458
459void basequeryaction::set_option_macro (const text_t &macroname,
460 text_t current_value,
461 bool display_single,
462 bool add_js_update,
463 const FilterOption_t &option_domain,
464 const FilterOption_t &option_range,
465 displayclass &disp)
466{
467 // this should probably be moved to sqlqueryaction.cpp // *****
468
469 if (option_domain.validValues.empty()) return;
470 if (option_range.validValues.empty()) return;
471
472 if (option_range.validValues.size() == 1) {
473 if (display_single) {
474 disp.setmacro (macroname + "selection",
475 displayclass::defaultpackage, "_" + option_range.defaultValue + "_");
476 }
477 return;
478 }
479 if (option_domain.validValues.size() < 2) return;
480 if (option_range.validValues.size() < 2) return;
481
482 text_t macrovalue = "<select name=\"" + macroname + "\"";
483 if (add_js_update) {
484 macrovalue += " onChange=\"update"+macroname+"();\"";
485 }
486 macrovalue += ">\n";
487
488 if (current_value.empty()) current_value = option_domain.defaultValue;
489
490 text_tarray::const_iterator dom_thisvalue = option_domain.validValues.begin();
491 text_tarray::const_iterator dom_endvalue = option_domain.validValues.end();
492
493 text_tarray::const_iterator ran_thisvalue = option_range.validValues.begin();
494 text_tarray::const_iterator ran_endvalue = option_range.validValues.end();
495
496
497 while ((dom_thisvalue != dom_endvalue) && (ran_thisvalue != ran_endvalue)) {
498 if (*ran_thisvalue != "ZZ" && *ran_thisvalue != "TX") {
499
500 text_t option_val = *dom_thisvalue;
501 option_val.replace(",","/");
502 macrovalue += "<option value=\"" + option_val + "\"";
503
504 if (*dom_thisvalue == current_value)
505 macrovalue += " selected";
506 macrovalue += ">_" + *ran_thisvalue + "_\n";
507 }
508
509 ++dom_thisvalue;
510 ++ran_thisvalue;
511 }
512 macrovalue += "</select>\n";
513 disp.setmacro (macroname + "selection", displayclass::defaultpackage, macrovalue);
514}
515
516
517
518
519// define_single_query_macros sets the extra macros for search_single_coll
520// that couldn't be set until the query had been done. Those macros are
521// _freqmsg_ and _stopwordsmsg_
522void basequeryaction::define_single_query_macros (cgiargsclass &args,
523 displayclass &disp,
524 const FilterResponse_t &response) {
525 // set up _freqmsg_ and _stopwordsmsg_ macros
526
527 text_t freqmsg = "";
528 freqmsg = "_textfreqmsg1_";
529 TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
530 TermInfo_tarray::const_iterator end_term = response.termInfo.end();
531 while (this_term != end_term) {
532 freqmsg += (*this_term).term + ": " + (*this_term).freq;
533 if ((this_term + 1) != end_term)
534 freqmsg += ", ";
535 ++this_term;
536 }
537 disp.setmacro ("freqmsg", "query", freqmsg);
538
539 text_tset::const_iterator this_stopword = response.stopwords.begin();
540 text_tset::const_iterator end_stopword = response.stopwords.end();
541 if (this_stopword != end_stopword) {
542 text_t stopwordsmsg = "_textstopwordsmsg_ ";
543 while (this_stopword != end_stopword) {
544 if (stopwordsmsg != "_textstopwordsmsg_ ") {
545 stopwordsmsg += ", ";
546 }
547 stopwordsmsg += (*this_stopword);
548 ++this_stopword;
549 }
550 disp.setmacro("stopwordsmsg", "query", stopwordsmsg);
551 }
552}
553
554
555
556void basequeryaction::define_history_macros (displayclass &disp,
557 cgiargsclass &args,
558 recptprotolistclass *protos,
559 ostream &logout)
560{
561
562 // defines the following macros
563 // _searchhistorylist_
564
565 text_t historylist;
566 int arghd = args.getintarg("hd");
567 if (arghd == 0) {
568 historylist="";
569 }
570 else {
571 historylist = "<!-- Search History List -->\n";
572
573 text_t userid = args["z"];
574 text_tarray entries;
575 if (get_history_info (userid, entries, dbhome, logout)) {
576 int count = 1;
577 text_tarray::iterator here = entries.begin();
578 text_tarray::iterator end = entries.end();
579 int numrecords=(int)entries.size();
580 if (numrecords>arghd) { // only display some of them
581 numrecords = arghd;
582 }
583 historylist += "<form action=\"_gwcgi_\" name=\"HistoryForm\"><table width=\"537\">\n";
584
585 for (int i=0; i<numrecords;++i) {
586 text_t query;
587 text_t numdocs;
588 text_t cgiargs;
589 text_t userinfo;
590 text_t escquery;
591 split_saved_query(entries[i],numdocs,cgiargs);
592 parse_saved_args(cgiargs, "q", query); // get query string out
593 decode_cgi_arg(query); // un cgisafe it
594 escquery = escape_quotes(query); // escape the quotes and newlines
595 text_t histvalue = "histvalue";
596 histvalue += i;
597 disp.setmacro(histvalue, "query", escquery);
598 format_user_info(cgiargs, userinfo, args, protos, logout);
599
600 historylist += "<tr><td align=\"right\">_imagehistbutton_(";
601 historylist += i;
602 historylist += ")</td>\n";
603 historylist += "<td><table border=\"1\" cellspacing=\"0\" ";
604 historylist += "cellpadding=\"0\"><tr><td width=\"365\" align=\"left\">"
605 + query
606 + "</td></tr></table></td><td width=\"110\" align=\"center\"><small>"
607 + numdocs;
608 if (numdocs == 1) historylist += " _texthresult_";
609 else historylist += " _texthresults_";
610 if (!userinfo.empty()) {
611 historylist += "<br>( "+userinfo+" )";
612 }
613 historylist += "</small></td>\n";
614 }
615 historylist+="</table></form>\n\n";
616
617 } // if get history info
618 else {
619 historylist += "_textnohistory_";
620 }
621 historylist += "<! ---- end of history list ----->\n";
622 } // else display list
623 disp.setmacro("searchhistorylist", "query", historylist);
624
625} // define history macros
626
627
628
629// **** check to see if this version is identical to that in
630// queryaction.cpp and remove queryaction.cpp version if it is
631
632bool basequeryaction::search_single_collection (cgiargsclass& args,
633 const text_t& collection,
634 recptprotolistclass *protos,
635 browsermapclass* browsers,
636 displayclass& disp,
637 outconvertclass& outconvert,
638 ostream& textout,
639 ostream& logout)
640{
641 recptproto *collectproto = protos->getrecptproto (collection, logout);
642 if (collectproto == NULL) {
643 logout << outconvert << "basequeryaction::search_single_collection: " << collection
644 << " collection has a NULL collectproto\n";
645
646 // Display the "this collection is not installed on this system" page
647 disp.setmacro("cvariable", displayclass::defaultpackage, collection);
648 disp.setmacro("content", "query", "<p>_textbadcollection_<p>");
649
650 textout << outconvert << disp << "_query:header_\n"
651 << "_query:content_\n" << "_query:footer_\n";
652 return true;
653 }
654
655 // (.*)queryaction uses "VList" browser to display results,
656 // a queries clasification is "Search"
657 text_t browsertype = "VList";
658 text_t classification = "Search";
659
660 comerror_t err;
661 ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
662
663 if (cinfo == NULL) {
664 logout << "ERROR (query_action::search_single_collection): get_collectinfo_ptr returned NULL\n";
665 return false;
666 }
667
668 bool segment = cinfo->isSegmented;
669 browserclass *bptr = browsers->getbrowser (browsertype);
670
671 // get the formatstring if there is one
672 text_t formatstring;
673 if (!get_formatstring (classification, browsertype,
674 cinfo->format, formatstring)) {
675 formatstring = bptr->get_default_formatstring();
676 }
677 FilterRequest_t request;
678 FilterResponse_t response;
679
680 text_t hits_per_page_old = args["o"];
681 text_t start_results_from_old = args["r"];
682
683 // if the "ifl" argument is set to 1, we only want to get one document
684 // this may be the first search result (from "I feel lucky") or maybe a
685 // specified search result (from next/prev search result link)
686 if (args["ifl"] == "1") {
687 args["r"] = args["ifln"]; // the document number we want
688 args["o"] = "1";
689 }
690
691 bptr->set_filter_options (request, args);
692 bptr->load_metadata_defaults (request.fields);
693
694 format_t *formatlistptr = new format_t();
695 parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
696
697 // do the query
698 request.filterResultOptions = FROID | FRmetadata | FRtermFreq;
699 text_t formattedstring = "";
700 get_formatted_query_string(formattedstring, segment, args, disp, logout);
701
702
703 if (!formattedstring.empty()) { // do the query
704 // note! formattedstring is in unicode! mg and mgpp must convert!
705 set_queryfilter_options (request, formattedstring, args);
706
707 collectproto->filter (collection, request, response, err, logout);
708
709 if (err != noError) {
710 outconvertclass text_t2ascii;
711 logout << text_t2ascii
712 << "basequeryaction::search_single_collections: call to "
713 << query_filter_name() << " failed "
714 << "for " << collection << " collection (" << get_comerror_string (err) << ")\n";
715
716 }
717
718 // Perform the "I'm feeling lucky" trick if the "ifl" argument is set
719 if (err == noError && !args["ifl"].empty()) {
720 //Restore the "r" and "o" arg
721 args["r"] = start_results_from_old;
722 args["o"] = hits_per_page_old;
723
724 //Find whether DocumentSearchResultLinks is enabled
725 bool show_links = false;
726 text_tmap::const_iterator format_here = cinfo->format.begin();
727 text_tmap::const_iterator format_end = cinfo->format.end();
728
729 while (format_here != format_end) {
730 if (((*format_here).first == "DocumentSearchResultLinks") &&
731 ((*format_here).second == "true")){
732 show_links = true;
733 break;
734 }
735 ++format_here;
736 }
737
738 if (args["ifl"] == 1 || (args["ifl"] == 2 && response.numDocs == 1)) {
739
740 // The first search result is the one we want
741 if (response.docInfo.begin() != response.docInfo.end()) {
742
743 ResultDocInfo_tarray::iterator section = response.docInfo.begin();
744
745 // We still need to set "srn" and "srp" values (next and prev search result numbers) if we are showing them
746 int srn = 0;
747 int srp = 0;
748 if (show_links) {
749 int ifln = args["ifln"].getint();
750 srn = ifln + 1;
751 if (srn > response.numDocs) {
752 srn = 0;
753 }
754 srp = ifln - 1;
755 if (srp < 0) {
756 srp = 0;
757 }
758 }
759
760 textout << outconvert << disp
761 << "Location: _gwcgi_?e=_compressedoptions_&a=d&c="
762 << collection << "&cl=search&d=" << (*section).OID
763 << "&srn=" << srn << "&srp=" << srp << "\n\n";
764 textout << flush;
765
766 return true;
767 }
768 }
769
770 // There weren't enough (or any) matching documents
771 // We'll just carry on as if ifl wasn't set. The only catch is that get_cgihead_info won't have
772 // done the right thing (because ifl was set), so we need to make sure the output is html
773 textout << "Content-type: text/html\n\n";
774
775 }
776
777 if (err != noError) {
778 disp.setmacro("resultline", "query", "_textnodocs_");
779 if (err == syntaxError) {
780 disp.setmacro ("freqmsg", "query", "_textinvalidquery_");
781 } else {
782 disp.setmacro ("freqmsg", "query", "");
783 }
784 } else {
785
786 define_query_macros (args, disp, response.numDocs, response.isApprox);
787 define_single_query_macros(args, disp, response);
788 // save the query if appropriate
789 save_search_history(args, response.numDocs, response.isApprox);
790 }
791
792 // If Lucene threw a TooManyClauses exception, tell the user about it
793 if (args["ct"] == 2 && response.error_message == "TOO_MANY_CLAUSES") {
794 disp.setmacro ("freqmsg", "query", "_textlucenetoomanyclauses_");
795 }
796 }
797
798 //Restore the "r" and "o" arg in case they have been changed and we still get here
799 args["r"] = start_results_from_old;
800 args["o"] = hits_per_page_old;
801
802 define_history_macros (disp, args, protos, logout);
803
804 textout << outconvert << disp << "_query:header_\n"
805 << "_query:content_";
806
807 if (err == noError) {
808 // output the results
809 text_t numdocs_t = response.numDocs;
810 args["nmd"] = numdocs_t;
811 bool use_table = is_table_content (formatlistptr);
812 bptr->output_section_group (response, args, collection, 0, formatlistptr,
813 use_table, request.fields, request.getParents,
814 collectproto, disp, outconvert, textout, logout);
815 }
816
817 textout << outconvert << disp << "_query:footer_";
818
819 delete (formatlistptr);
820
821 return true;
822}
823
Note: See TracBrowser for help on using the repository browser.