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

Last change on this file since 939 was 939, checked in by sjboddie, 24 years ago

tidied up a bit - fixed a bug (gdbm file wasn't always being closed properly)

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