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

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

gsdlhome now comes from gsdlsite.cfg

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