/********************************************************************** * * historydb.cpp -- * Copyright (C) 1999 The New Zealand Digital Library Project * * A component of the Greenstone digital library software * from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *********************************************************************/ #include "historydb.h" #include "fileutil.h" #include "cgiutils.h" #include "recptproto.h" #include "OIDtools.h" // returns true on success (in which case historyinfo will contain // the information for this history) bool get_history_info (const text_t &userid, text_tarray &historyinfo, const text_t &gsdlhome, ostream &logout) { text_t historyfile = filename_cat(gsdlhome, "etc", "history.db"); bool result = false; // open the history database gdbmclass historydb; if (historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) { // get history list text_t historyresult; historydb.getkeydata(userid, historyresult); if (historyresult != "") { // there are entries, process them splitchar(historyresult.begin(), historyresult.end(), '\n', historyinfo); result = true; } historydb.closedatabase(); } else { outconvertclass text_t2ascii; logout << text_t2ascii << "couldn't open history database " << historyfile << "\n"; } return result; } // returns true on success bool set_history_info (const text_t &userid, const text_t &history, const text_t &gsdlhome) { text_t historyfile = filename_cat(gsdlhome, "etc", "history.db"); bool result = false; // open the history database gdbmclass historydb; text_t querynum; text_t historyresult; if ( !historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) { // not created yet historyresult=""; querynum="1"; } else { // get history list if (! historydb.getkeydata(userid, historyresult)) { historyresult=""; querynum="1"; } historydb.closedatabase(); } // get next query num if (historyresult!="") { text_tarray entries; splitchar(historyresult.begin(), historyresult.end(), '\n', entries); get_query_num(entries.back(), querynum); querynum.setint(querynum.getint()+1); } // open for writing if (!historydb.opendatabase(historyfile, GDBM_WRCREAT, 1000, true)) return false; // add on new line historyresult += querynum; historyresult += ":"; historyresult += history; historyresult += "\n"; if (historydb.setinfo(userid, historyresult)) result=true; historydb.closedatabase(); return result; } // deletes all a users history bool delete_all_history_info (const text_t &userid, const text_t &gsdlhome) { text_t historyfile = filename_cat(gsdlhome, "etc", "history.db"); // open the history database gdbmclass historydb; if ( !historydb.opendatabase(historyfile, GDBM_WRITER, 1000, true)) return false; historydb.deletekey(userid); historydb.closedatabase(); return true; } //deletes only the selected records bool delete_history_info (const text_t &userid, const text_t &deletemode, const text_t &selection, const text_t &gsdlhome) { text_t historyfile = filename_cat(gsdlhome, "etc", "history.db"); bool result = false; // open the history database gdbmclass historydb; if ( !historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) return false; // get history list text_t historyresult; if (! historydb.getkeydata(userid, historyresult)) return false; historydb.closedatabase(); text_t newhistory; // for the new list of search history // get list of queries text_tarray queries; splitchar(historyresult.begin(), historyresult.end(), '\n', queries); text_tarray::iterator begin=queries.begin(); text_tarray::iterator end=queries.end(); // get list of numbers to delete text_tarray numbers; splitchar(selection.begin(), selection.end(), ',', numbers); text_tarray::iterator numbegin=numbers.begin(); text_tarray::iterator numend=numbers.end(); bool tdefault, tset; if (deletemode=="delete") { tdefault=true; tset=false; } else {// deletemode == save tdefault=false; tset=true; } // create a HistRecord map of all the entries HistRecordmap records; while (begin != end) { HistRecord rec; rec.entry=*begin; rec.save=tdefault; text_t num; get_query_num(*begin, num); records[num] = rec; begin++; } // now set the save field for all records that are selected while(numbegin != numend) { if (is_number(*numbegin)) { if (records.count(*numbegin)==1) { records[*numbegin].save=tset; } // else invalid number } else{ int start, stop; if (get_selection_params(*numbegin, start, stop)) { for (int i=start; i<=stop; i++) { text_t num = i; if (records.count(num)==1) { records[num].save=tset; } }} else { // dodgy format // error message } } numbegin++; } // while HistRecordmap::iterator recbegin = records.begin(); HistRecordmap::iterator recend = records.end(); //create new history record - go through all Records // and add to new history those with save set to true while (recbegin != recend) { if ((*recbegin).second.save) { expand_query((*recbegin).second, records); newhistory += (*recbegin).second.entry + "\n"; } recbegin++; } // open for writing if (!historydb.opendatabase(historyfile, GDBM_WRITER, 1000, true)) return false; if (historydb.setinfo(userid, newhistory)) result = true; historydb.closedatabase(); return result; } bool get_selection_params (text_t &data, int &start, int &stop) { text_tarray results; splitchar(data.begin(), data.end(), '-', results); if (results.size()==2 && is_number(results[0]) && is_number(results[1])) { start=results[0].getint(); stop=results[1].getint(); return true; } // error message return false; } // expand query takes a HistRecord, and expands out any hashes in // the query string for queries that aren't to be saved bool expand_query(HistRecord &record, HistRecordmap &records) { text_tarray args; splitchar(record.entry.begin(), record.entry.end(), '&', args); text_tarray::iterator begin=args.begin(); text_tarray::iterator end=args.end(); text_t query; // find the q argument while(begin != end) { if ((*begin)[0] == 'q'&& (*begin)[1] == '=') { query=*begin; args.erase(begin); break; } else begin++; } if (query !="") { //remove the q= text_t::iterator front = query.begin(); query.erase(front); front=query.begin(); query.erase(front); decode_cgi_arg(query); // now have just the query string // check any refs in it to see if they are still valid combine_query(query, records); text_t formattedquery = cgi_safe(query); text_t newquery = "q="; newquery += formattedquery; args.push_back(newquery); joinchar(args, '&', record.entry); return true; } return false; } // replaces a reference to a previous query with the search // string from that query bool combine_query(text_t &userid, text_t &query, const text_t &gsdlhome) { text_t::iterator begin = query.begin(); text_t::iterator end = query.end(); text_t::iterator it = findchar(begin, end, '#'); if (it==end) return true; // no need to swap anything text_t queryresult = ""; text_t historyfile = filename_cat(gsdlhome, "etc", "history.db"); text_t historyresult; // open the history database gdbmclass historydb; bool exists = false; if (historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) { // get history list if (historydb.getkeydata(userid, historyresult)) { exists=true; historydb.closedatabase(); } } if (!exists) {// cant open history file, or user entry doesn't exist. replace #x with blanks while(it !=end) { queryresult += substr(begin, it); it++; while(*it>='0'&&*it<='9') it++; begin=it; it=findchar(begin, end, '#'); } queryresult += substr(begin, end); query = queryresult; return false; } bool result=true; // if have got to here, have a previous history in historyresult text_tarray historyinfo; splitchar(historyresult.begin(), historyresult.end(), '\n', historyinfo); text_tarray::iterator histbegin = historyinfo.begin(); text_tarray::iterator histend = historyinfo.end(); text_tmap historymap; // put all entries into a map, so can pull out the appropriate one easily while (histbegin != histend) { text_t num; get_query_num(*histbegin, num); historymap[num]=*histbegin; histbegin++; } while(it!=end) { // while there still is a hash present text_t querynum; text_t newquery; while (begin!=end) { if (*begin==text_t('#')) { begin++; while(begin !=end && *begin>='0'&&*begin<='9') { querynum.push_back(*begin); begin++; } text_t oldquery = historymap[querynum]; if (oldquery !="") { // valid entry parse_saved_args(oldquery, "q", newquery); decode_cgi_arg(newquery); queryresult += newquery; } else { result=false; } querynum.clear(); // else do nothing (replace #x with nothing) } // if else { queryresult.push_back(*begin); begin++; } } // while begin!=end // have got to end of query string, // now go back and check for internal # query = queryresult; begin = query.begin(); end = query.end(); it = findchar(begin, end, '#'); queryresult.clear(); } // while it !=end return result; } // combine query // replaces a reference to a previous query with the search // string from that query, uses the Histrecordmap rather than the GDBM file bool combine_query( text_t &query, HistRecordmap &records) { text_t::iterator begin = query.begin(); text_t::iterator end = query.end(); text_t::iterator it = findchar(begin, end, '#'); if (it==end) return true; // no need to swap anything text_t queryresult = ""; bool changed=true; while(it!=end && changed) { // while there still is a hash present // and query has changed since last time round // we are leaving some #X in text_t querynum; text_t newquery; changed=false; while (begin!=end) { // go through the query looking for hash if (*begin==text_t('#')) { begin++; while(begin !=end && *begin>='0'&&*begin<='9') { querynum.push_back(*begin); begin++; } if(records.count(querynum)>0) { // valid entry if (!records[querynum].save){ // referenced record to be deleted // get the q arg out of referenced query parse_saved_args(records[querynum].entry, "q", newquery); decode_cgi_arg(newquery); queryresult += newquery; changed=true; } else { // leave the #x in queryresult.push_back('#'); queryresult += querynum; } } querynum.clear(); newquery.clear(); // else do nothing (replace #x with nothing) } // if its a hash else { queryresult.push_back(*begin); begin++; } } // while begin!=end // have got to end of query string, // now go back and check for internal # query = queryresult; begin = query.begin(); end = query.end(); it = findchar(begin, end, '#'); queryresult.clear(); } // while it !=end return true; } // combine query // retrieves the value of one of the arguments void parse_saved_args(text_t &args, text_t key, text_t &value) { text_t::iterator here = args.begin(); text_t::iterator end = args.end(); text_t::iterator it; while (here != end) { if(*here==key[0]) { it=findchar(here, end, '='); if (it==end) { value=""; return; } text_t entry = substr(here, it); if (entry==key) { here=it+1; it=findchar(here, end, '&'); value = substr(here, it); return; } } here++; }// while } // retrieves the value of all of the arguments void parse_saved_args(text_t &args, infodbclass &info) { text_t::iterator here = args.begin(); text_t::iterator end = args.end(); text_t::iterator it; text_tarray values; splitchar(here, end, '&', values); text_tarray::iterator start = values.begin(); text_tarray::iterator stop = values.end(); text_t key; text_t value; while(start!=stop) { here=(*start).begin(); end=(*start).end(); it=findchar(here, end, '='); if (it!=end) { key = substr(here, it); value = substr(it+1, end); info[key]=value; } start++; } } void get_query_num(text_t &query, text_t &querynum) { text_t::iterator begin = query.begin(); while (*begin >='0'&& *begin <='9') { // get the digits querynum.push_back(*begin); begin++; } if (*begin != ':') { // something has gone wrong } } void split_saved_query(text_t &query, text_t &querynum, text_t &numdocs, text_t &cgiargs) { text_t::iterator begin = query.begin(); text_t::iterator end = query.end(); while (*begin >='0'&& *begin <='9') { // get the digits querynum.push_back(*begin); begin++; } if (*begin != ':') { // something has gone wrong } else begin++; while (*begin >='0'&& *begin <='9') { // get the digits numdocs.push_back(*begin); begin++; } if (*begin == '+') { // get the + if there numdocs.push_back(*begin); begin++; } cgiargs += (substr(begin, end)); // put rest of query into cgiargs } void format_user_info (text_t &cgiargs, text_t &userinfo, recptprotolistclass *protos, ostream &logout) { logout << "in format user info"; text_tset metadata; infodbclass argsinfo; parse_saved_args(cgiargs, argsinfo); text_t collect = argsinfo["c"]; if (collect=="") { userinfo=""; return; } recptproto *collectproto = protos->getrecptproto(collect,logout); if (collectproto == NULL) { userinfo=""; return; } metadata.insert(argsinfo["h"]); FilterResponse_t response; get_info("collection", collect, metadata, false, collectproto, response, logout); text_t index = response.docInfo[0].metadata[argsinfo["h"]].values[0]; text_t mode; if (argsinfo["b"]=="0") { // simple mode if (argsinfo["t"]=="0") { mode = "all words"; } else { // t=1 mode = "some words"; } } else { // advanced mode if (argsinfo["t"]=="0") { mode = "boolean"; } else { mode = "ranked"; } } text_t options; if (argsinfo["k"]=="0") { options = "case must match"; } else { options = "ignore case"; } if (argsinfo["s"]=="0") { options += ", whole word must match"; } else { options += ", ignore word endings"; } userinfo.clear(); userinfo = "collection ("+argsinfo["c"] + ") "; userinfo += "search (" + index + ") "; userinfo += "mode (" + mode +") "; userinfo += "options (" + options + ")"; logout << "in format user info - end"; }