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