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

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

fixed some compiler warnings

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