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