// imapd/SearchCmd.hh // This file is part of Decimail; see http://decimail.org // (C) 2004-2007 Philip Endecott // 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 // 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef Imapd_SearchCmd_hh #define Imapd_SearchCmd_hh #include "Command.hh" #include "unimplemented_commands.hh" #include "utils.hh" #include "compiler_magic.hh" #include namespace Imapd { class SearchKey { public: virtual ~SearchKey() {} virtual ostream& write_query(ostream& s, Session& session) = 0; virtual bool get_sense(void) = 0; virtual bool is_all(void) { return false; } }; class SearchKeyNotImplemented: public SearchKey { public: SearchKeyNotImplemented(void) {} ostream& write_query(ostream& s, PBE_UNUSED_ARG(Session& session)) { throw NotImplemented(); return s; } virtual bool get_sense(void) { throw NotImplemented(); return true; } }; class SearchKeyRowCondition: public SearchKey { private: const string table_name; const string condition; const bool sense; public: SearchKeyRowCondition(string t, string c, bool s): table_name(t), condition(c), sense(s) {} ostream& write_query(ostream& s, Session& session); bool get_sense(void) { return sense; } }; class SearchKeyFieldEqual: public SearchKeyRowCondition { public: SearchKeyFieldEqual(string t, string n, string v, bool s): SearchKeyRowCondition(t, n+"='"+pbe::escape_for_squoted_string(v)+"'", s) {} }; class SearchKeyFieldSubstring: public SearchKeyRowCondition { public: SearchKeyFieldSubstring(string t, string n, string v, bool s): SearchKeyRowCondition(t, n+" like '%"+pbe::escape_for_squoted_string(v)+"%'", s) {} }; class SearchKeyAll: public SearchKey { public: ostream& write_query(ostream& s, PBE_UNUSED_ARG(Session& session)) { return s; } bool get_sense(void) { return true; } bool is_all(void) { return true; } }; class SearchKeyFlag: public SearchKeyFieldEqual { public: SearchKeyFlag(string f): SearchKeyFieldEqual("u_imap_message_flags","flag",f,true) {} }; class SearchKeyNoFlag: public SearchKeyFieldEqual { public: SearchKeyNoFlag(string f): SearchKeyFieldEqual("u_imap_message_flags","flag",f,false) {} }; class SearchKeyAddr: public SearchKey { private: const string addr_type; const string pattern; public: SearchKeyAddr(string addr_type_, string pattern_): addr_type(addr_type_), pattern(pattern_) {} ostream& write_query(ostream& s, Session& session); bool get_sense(void) { return true; } }; class SearchKeyDateBefore: public SearchKeyRowCondition { public: SearchKeyDateBefore(string date): SearchKeyRowCondition("u_messages","msgdate<'"+date+"'",true) {} }; class SearchKeyBody: public SearchKeyFieldSubstring { public: SearchKeyBody(string pattern): SearchKeyFieldSubstring("u_messages","body",pattern,true) {} }; class SearchKeyFrom: public SearchKeyFieldSubstring { public: SearchKeyFrom(string pattern): SearchKeyFieldSubstring("u_messages","from_addr",pattern,true) {} }; class SearchKeyDateSameDay: public SearchKeyRowCondition { public: SearchKeyDateSameDay(string date): SearchKeyRowCondition("u_messages", "date_trunc('day',msgdate)=date_trunc('day','"+date+"')", true) {} }; class SearchKeyDateOnOrAfter: public SearchKeyRowCondition { public: SearchKeyDateOnOrAfter(string date): SearchKeyRowCondition("u_messages", "date_trunc('day',msgdate)>=date_trunc('day','"+date+"')", true) {} }; class SearchKeySubject: public SearchKeyFieldSubstring { public: SearchKeySubject(string pattern): SearchKeyFieldSubstring("u_messages","subject",pattern,true) {} }; class SearchKeyText: public SearchKeyRowCondition { public: SearchKeyText(string pattern): SearchKeyRowCondition("u_messages", "header like '%"+pattern+"%' or body like '%"+pattern+"%'", true) {} }; class SearchKeyHeader: public SearchKeyRowCondition { public: SearchKeyHeader(ci_string header, string pattern): SearchKeyRowCondition("u_messages", // Hmm, the .* ought to not match into the next headers. // SQL requires that the whole regexp has the same // case-sensitivity, which is not what we want. string("headers::text ~* '")+header.c_str()+":.*"+pattern+"'", true) {} }; class SearchKeySizeLarger: public SearchKeyRowCondition { public: SearchKeySizeLarger(int value): SearchKeyRowCondition("u_messages","size>"+boost::lexical_cast(value),true) {} }; class SearchKeyNot: public SearchKey { private: SearchKey* const search_key; public: SearchKeyNot(SearchKey* sk): search_key(sk) {} ~SearchKeyNot() { delete search_key; } ostream& write_query(ostream& s, Session& session); bool get_sense(void); }; class SearchKeyOr: public SearchKey { private: SearchKey* const left; SearchKey* const right; public: SearchKeyOr(SearchKey* l, SearchKey* r): left(l), right(r) {} ~SearchKeyOr() { delete left; delete right; } ostream& write_query(ostream& s, Session& session); bool get_sense(void); bool is_all(void); }; class SearchKeySentBefore: public SearchKeyDateBefore { public: SearchKeySentBefore(string date): SearchKeyDateBefore(date) {} }; class SearchKeySentSameDay: public SearchKeyDateSameDay { public: SearchKeySentSameDay(string date): SearchKeyDateSameDay(date) {} }; class SearchKeySentOnOrAfter: public SearchKeyDateOnOrAfter { public: SearchKeySentOnOrAfter(string date): SearchKeyDateOnOrAfter(date) {} }; class SearchKeySizeSmaller: public SearchKeyRowCondition { public: SearchKeySizeSmaller(int value): SearchKeyRowCondition("u_messages","size<"+boost::lexical_cast(value),true) {} }; class SearchKeyUid: public SearchKey { private: MessageSet* msgs; public: SearchKeyUid(MessageSet* s): msgs(s) {} ~SearchKeyUid() { delete msgs; } ostream& write_query(ostream& s, Session& session); bool get_sense(void) {return true;} }; class SearchKeyMsgset: public SearchKey { private: MessageSet* msgs; public: SearchKeyMsgset(MessageSet* s): msgs(s) {} ~SearchKeyMsgset() { delete msgs; } ostream& write_query(ostream& s, Session& session); bool get_sense(void) {return true;} }; class SearchKeySubexpression: public SearchKey { private: list subexprs; // who deletes these? public: SearchKeySubexpression(list s): subexprs(s) {} ostream& write_query(ostream& s, Session& session); bool get_sense(void); bool is_all(void); }; class SearchCmd: public UidableCmd { private: string charset; list search_keys; public: SearchCmd(string t, string charset, list s): UidableCmd(t,"SEARCH"), search_keys(s) {} ~SearchCmd(); private: void runbody(Session& session); }; }; #endif