source: trunk/gsdl/src/recpt/historydb.cpp@ 1861

Last change on this file since 1861 was 1786, checked in by kjm18, 23 years ago

fixed the handling of #x in the query string - only #n where n is a number
are treated as references to history items. So #icus (stem, case) will be left
in the query string.

  • Property svn:keywords set to Author Date Id Revision
File size: 16.0 KB
Line 
1/**********************************************************************
2 *
3 * historydb.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 "historydb.h"
27#include "fileutil.h"
28#include "cgiutils.h"
29#include "recptproto.h"
30#include "OIDtools.h"
31
32
33// returns true on success (in which case historyinfo will contain
34// the information for this history)
35bool get_history_info (const text_t &userid, text_tarray &historyinfo,
36 const text_t &gsdlhome, ostream &logout) {
37
38 text_t historyfile = filename_cat(gsdlhome, "etc", "history.db");
39
40 bool result = false;
41 // open the history database
42 gdbmclass historydb;
43
44 if (historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) {
45 // get history list
46 text_t historyresult;
47
48 historydb.getkeydata(userid, historyresult);
49
50 if (historyresult != "") { // there are entries, process them
51
52 splitchar(historyresult.begin(), historyresult.end(), '\n', historyinfo);
53 result = true;
54 }
55 historydb.closedatabase();
56
57 } else {
58 outconvertclass text_t2ascii;
59 logout << text_t2ascii << "couldn't open history database " << historyfile << "\n";
60 }
61 return result;
62}
63
64
65// returns true on success
66bool set_history_info (const text_t &userid, const text_t &history, const text_t &gsdlhome) {
67
68 text_t historyfile = filename_cat(gsdlhome, "etc", "history.db");
69
70 bool result = false;
71 // open the history database
72 gdbmclass historydb;
73
74 text_t querynum;
75 text_t historyresult;
76
77
78 if ( !historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) {
79 // not created yet
80 historyresult="";
81 querynum="1";
82 }
83 else {
84
85 // get history list
86 if (! historydb.getkeydata(userid, historyresult)) {
87 historyresult="";
88 querynum="1";
89 }
90 historydb.closedatabase();
91 }
92
93 // get next query num
94 if (historyresult!="") {
95 text_tarray entries;
96 splitchar(historyresult.begin(), historyresult.end(), '\n', entries);
97 get_query_num(entries.back(), querynum);
98 querynum.setint(querynum.getint()+1);
99 }
100
101 // open for writing
102 if (!historydb.opendatabase(historyfile, GDBM_WRCREAT, 1000, true)) return false;
103
104 // add on new line
105 historyresult += querynum;
106 historyresult += ":";
107 historyresult += history;
108 historyresult += "\n";
109
110 if (historydb.setinfo(userid, historyresult))
111 result=true;
112
113 historydb.closedatabase();
114 return result;
115}
116
117// deletes all a users history
118bool delete_all_history_info (const text_t &userid, const text_t &gsdlhome) {
119
120 text_t historyfile = filename_cat(gsdlhome, "etc", "history.db");
121
122 // open the history database
123 gdbmclass historydb;
124
125 if ( !historydb.opendatabase(historyfile, GDBM_WRITER, 1000, true)) return false;
126
127 historydb.deletekey(userid);
128 historydb.closedatabase();
129 return true;
130
131}
132
133//deletes only the selected records
134bool delete_history_info (const text_t &userid, const text_t &deletemode,
135 const text_t &selection, const text_t &gsdlhome) {
136
137 text_t historyfile = filename_cat(gsdlhome, "etc", "history.db");
138 bool result = false;
139 // open the history database
140 gdbmclass historydb;
141
142 if ( !historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) return false;
143
144 // get history list
145 text_t historyresult;
146
147 if (! historydb.getkeydata(userid, historyresult)) return false;
148
149 historydb.closedatabase();
150
151 text_t newhistory; // for the new list of search history
152 // get list of queries
153 text_tarray queries;
154 splitchar(historyresult.begin(), historyresult.end(), '\n', queries);
155 text_tarray::iterator begin=queries.begin();
156 text_tarray::iterator end=queries.end();
157
158 // get list of numbers to delete
159 text_tarray numbers;
160 splitchar(selection.begin(), selection.end(), ',', numbers);
161 text_tarray::iterator numbegin=numbers.begin();
162 text_tarray::iterator numend=numbers.end();
163
164 bool tdefault, tset;
165 if (deletemode=="delete") {
166 tdefault=true;
167 tset=false;
168 }
169 else {// deletemode == save
170 tdefault=false;
171 tset=true;
172 }
173
174 // create a HistRecord map of all the entries
175 HistRecordmap records;
176 while (begin != end) {
177 HistRecord rec;
178 rec.entry=*begin;
179 rec.save=tdefault;
180 text_t num;
181 get_query_num(*begin, num);
182 records[num] = rec;
183 begin++;
184 }
185
186
187 // now set the save field for all records that are selected
188 while(numbegin != numend) {
189
190 if (is_number(*numbegin)) {
191 if (records.count(*numbegin)==1) {
192 records[*numbegin].save=tset;
193 } // else invalid number
194 }
195 else{
196 int start, stop;
197 if (get_selection_params(*numbegin, start, stop)) {
198 for (int i=start; i<=stop; i++) {
199 text_t num = i;
200 if (records.count(num)==1) {
201 records[num].save=tset;
202 }
203 }
204 }
205 else { // dodgy format
206 // error message
207 }
208
209 }
210 numbegin++;
211 } // while
212
213 HistRecordmap::iterator recbegin = records.begin();
214 HistRecordmap::iterator recend = records.end();
215
216 //create new history record - go through all Records
217 // and add to new history those with save set to true
218 while (recbegin != recend) {
219 if ((*recbegin).second.save) {
220 expand_query((*recbegin).second, records);
221 newhistory += (*recbegin).second.entry + "\n";
222 }
223 recbegin++;
224 }
225
226 // open for writing
227 if (!historydb.opendatabase(historyfile, GDBM_WRITER, 1000, true)) return false;
228
229 if (historydb.setinfo(userid, newhistory)) result = true;
230
231 historydb.closedatabase();
232 return result;
233}
234
235bool get_selection_params (text_t &data, int &start, int &stop) {
236
237 text_tarray results;
238
239 splitchar(data.begin(), data.end(), '-', results);
240 if (results.size()==2 && is_number(results[0]) && is_number(results[1])) {
241 start=results[0].getint();
242 stop=results[1].getint();
243 return true;
244 }
245
246 // error message
247 return false;
248}
249
250// expand query takes a HistRecord, and expands out any hashes in
251// the query string for queries that aren't to be saved
252bool expand_query(HistRecord &record, HistRecordmap &records) {
253
254 text_tarray args;
255 splitchar(record.entry.begin(), record.entry.end(), '&', args);
256
257 text_tarray::iterator begin=args.begin();
258 text_tarray::iterator end=args.end();
259
260 text_t query;
261 // find the q argument
262 while(begin != end) {
263 if ((*begin)[0] == 'q'&& (*begin)[1] == '=') {
264 query=*begin;
265 args.erase(begin);
266 break;
267 } else begin++;
268 }
269 if (query !="") {
270
271 //remove the q=
272 text_t::iterator front = query.begin();
273 query.erase(front);
274 front=query.begin();
275
276 query.erase(front);
277 decode_cgi_arg(query);
278 // now have just the query string
279 // check any refs in it to see if they are still valid
280 combine_query(query, records);
281 text_t formattedquery = cgi_safe(query);
282 text_t newquery = "q=";
283 newquery += formattedquery;
284
285 args.push_back(newquery);
286 joinchar(args, '&', record.entry);
287
288 return true;
289 }
290 return false;
291}
292
293// replaces a reference to a previous query with the search
294// string from that query
295bool combine_query(text_t &userid, text_t &query, const text_t &gsdlhome)
296{
297 text_t::iterator begin = query.begin();
298 text_t::iterator end = query.end();
299 text_t::iterator it = findchar(begin, end, '#');
300 if (it==end) return true; // no need to swap anything
301
302 bool result=true;
303 text_t queryresult = "";
304 text_t historyfile = filename_cat(gsdlhome, "etc", "history.db");
305 text_t historyresult;
306 // open the history database
307 gdbmclass historydb;
308 bool exists = false;
309 if (historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) {
310 // get history list
311 if (historydb.getkeydata(userid, historyresult)) {
312 exists=true;
313
314 historydb.closedatabase();
315 }
316 }
317 if (!exists) {// cant open history file, or user entry doesn't exist. replace #x with blanks
318 while(it !=end) {
319 queryresult += substr(begin, it);
320 it++;
321 if (*it<'0' || *it>'9') {
322 queryresult.push_back('#'); // put the hash back if its not next to a number
323 }
324 else {
325 while(*it>='0'&&*it<='9') it++;
326 result = false;
327 }
328 begin=it;
329 it=findchar(begin, end, '#');
330 }
331 queryresult += substr(begin, end);
332 query = queryresult;
333 return result;
334 }
335
336 // if have got to here, have a previous history in historyresult
337 text_tarray historyinfo;
338 splitchar(historyresult.begin(), historyresult.end(), '\n', historyinfo);
339 text_tarray::iterator histbegin = historyinfo.begin();
340 text_tarray::iterator histend = historyinfo.end();
341
342 text_tmap historymap;
343 // put all entries into a map, so can pull out the appropriate one easily
344 while (histbegin != histend) {
345 text_t num;
346 get_query_num(*histbegin, num);
347 historymap[num]=*histbegin;
348 histbegin++;
349 }
350 while(it!=end) { // while there still is a hash present
351 text_t querynum;
352 text_t newquery;
353
354 while (begin!=end) {
355 if (*begin==text_t('#')) {
356 begin++;
357 if(*begin<'0'||*begin>'9') { // not a history ref, leave in
358 queryresult.push_back('#');
359 }
360 else { // history ref
361 while(begin !=end && *begin>='0'&&*begin<='9') {
362 querynum.push_back(*begin);
363 begin++;
364 }
365 text_t oldquery = historymap[querynum];
366 if (oldquery !="") { // valid entry
367 parse_saved_args(oldquery, "q", newquery);
368 decode_cgi_arg(newquery);
369 queryresult += newquery;
370 }
371 else {
372 result=false; // have replaced #n with nothing
373 }
374 querynum.clear();
375 }
376 } // if #
377 else {
378 queryresult.push_back(*begin);
379 begin++;
380 }
381 } // while begin!=end
382
383 // have got to end of query string,
384 // now go back and check for internal #
385 query = queryresult;
386 begin = query.begin();
387 end = query.end();
388 it = findchar(begin, end, '#');
389 queryresult.clear();
390
391 } // while it !=end
392
393
394 return result;
395
396} // combine query
397
398
399// replaces a reference to a previous query with the search
400// string from that query, uses the Histrecordmap rather than the GDBM file
401bool combine_query( text_t &query, HistRecordmap &records)
402{
403 text_t::iterator begin = query.begin();
404 text_t::iterator end = query.end();
405 text_t::iterator it = findchar(begin, end, '#');
406 if (it==end) return true; // no need to swap anything
407
408 text_t queryresult = "";
409 bool changed=true;
410 while(it!=end && changed) { // while there still is a hash present
411 // and query has changed since last time round
412 // we are leaving some #X in
413 text_t querynum;
414 text_t newquery;
415 changed=false;
416 while (begin!=end) { // go through the query looking for hash
417 if (*begin==text_t('#')) {
418 begin++;
419 if ( *begin<'0' || *begin>'9') { // not a ref
420 queryresult.push_back('#');
421 }
422 else {
423 while(begin !=end && *begin>='0'&&*begin<='9') {
424 querynum.push_back(*begin);
425 begin++;
426 }
427 if(records.count(querynum)>0) { // valid entry
428 if (!records[querynum].save){ // referenced record to be deleted
429 // get the q arg out of referenced query
430 parse_saved_args(records[querynum].entry, "q", newquery);
431 decode_cgi_arg(newquery);
432 queryresult += newquery;
433 changed=true;
434 }
435 else { // leave the #x in
436 queryresult.push_back('#');
437 queryresult += querynum;
438 }
439 }// else do nothing (replace #x with nothing)
440 querynum.clear();
441 newquery.clear();
442 }
443 } // if its a hash
444 else {
445 queryresult.push_back(*begin);
446 begin++;
447 }
448 } // while begin!=end
449
450 // have got to end of query string,
451 // now go back and check for internal #
452 query = queryresult;
453 begin = query.begin();
454 end = query.end();
455 it = findchar(begin, end, '#');
456 queryresult.clear();
457
458 } // while it !=end
459
460 return true;
461} // combine query
462
463// retrieves the value of one of the arguments
464void parse_saved_args(text_t &args, text_t key, text_t &value)
465{
466 text_t::iterator here = args.begin();
467 text_t::iterator end = args.end();
468 text_t::iterator it;
469 while (here != end) {
470 if(*here==key[0]) {
471 it=findchar(here, end, '=');
472 if (it==end) {
473 value=""; return;
474 }
475 text_t entry = substr(here, it);
476 if (entry==key) {
477 here=it+1;
478 it=findchar(here, end, '&');
479 value = substr(here, it);
480 return;
481 }
482 }
483 here++;
484 }// while
485}
486
487// retrieves the value of all of the arguments
488void parse_saved_args(text_t &args, infodbclass &info)
489{
490 text_t::iterator here = args.begin();
491 text_t::iterator end = args.end();
492 text_t::iterator it;
493 text_tarray values;
494
495 splitchar(here, end, '&', values);
496
497 text_tarray::iterator start = values.begin();
498 text_tarray::iterator stop = values.end();
499
500 text_t key;
501 text_t value;
502 while(start!=stop) {
503
504 here=(*start).begin();
505 end=(*start).end();
506 it=findchar(here, end, '=');
507 if (it!=end) {
508 key = substr(here, it);
509 value = substr(it+1, end);
510
511 info[key]=value;
512 }
513 start++;
514 }
515}
516
517void get_query_num(text_t &query, text_t &querynum)
518{
519 text_t::iterator begin = query.begin();
520
521 while (*begin >='0'&& *begin <='9') { // get the digits
522 querynum.push_back(*begin);
523 begin++;
524 }
525 if (*begin != ':') {
526 // something has gone wrong
527 }
528}
529
530void split_saved_query(text_t &query, text_t &querynum, text_t &numdocs, text_t &cgiargs)
531{
532 text_t::iterator begin = query.begin();
533 text_t::iterator end = query.end();
534
535 while (*begin >='0'&& *begin <='9') { // get the digits
536 querynum.push_back(*begin);
537 begin++;
538 }
539 if (*begin != ':') {
540 // something has gone wrong
541 }
542 else begin++;
543 while (*begin >='0'&& *begin <='9') { // get the digits
544 numdocs.push_back(*begin);
545 begin++;
546 }
547 if (*begin == '+') { // get the + if there
548 numdocs.push_back(*begin);
549 begin++;
550 }
551
552 cgiargs += (substr(begin, end)); // put rest of query into cgiargs
553
554}
555
556void format_user_info (text_t &cgiargs, text_t &userinfo, recptprotolistclass *protos, ostream &logout)
557{
558 logout << "in format user info";
559 text_tset metadata;
560
561 infodbclass argsinfo;
562 parse_saved_args(cgiargs, argsinfo);
563
564 text_t collect = argsinfo["c"];
565 if (collect=="") {
566 userinfo="";
567 return;
568 }
569 recptproto *collectproto = protos->getrecptproto(collect,logout);
570 if (collectproto == NULL) {
571 userinfo="";
572 return;
573 }
574 metadata.insert(argsinfo["h"]);
575 FilterResponse_t response;
576
577 get_info("collection", collect, metadata, false, collectproto, response, logout);
578
579 text_t index = response.docInfo[0].metadata[argsinfo["h"]].values[0];
580
581 text_t mode;
582 if (argsinfo["b"]=="0") { // simple mode
583 if (argsinfo["t"]=="0") {
584 mode = "all words";
585 }
586 else { // t=1
587 mode = "some words";
588 }
589
590 }
591 else { // advanced mode
592 if (argsinfo["t"]=="0") {
593 mode = "boolean";
594 }
595 else {
596 mode = "ranked";
597 }
598 }
599
600 text_t options;
601 if (argsinfo["k"]=="0") {
602 options = "case must match";
603 }
604 else {
605 options = "ignore case";
606 }
607 if (argsinfo["s"]=="0") {
608 options += ", whole word must match";
609 }
610 else {
611 options += ", ignore word endings";
612 }
613
614 userinfo.clear();
615 userinfo = "collection ("+argsinfo["c"] + ") ";
616 userinfo += "search (" + index + ") ";
617 userinfo += "mode (" + mode +") ";
618 userinfo += "options (" + options + ")";
619
620 logout << "in format user info - end";
621}
Note: See TracBrowser for help on using the repository browser.