summaryrefslogtreecommitdiffstats
path: root/libmail/search.C
diff options
context:
space:
mode:
Diffstat (limited to 'libmail/search.C')
-rw-r--r--libmail/search.C1198
1 files changed, 1198 insertions, 0 deletions
diff --git a/libmail/search.C b/libmail/search.C
new file mode 100644
index 0000000..0895f2e
--- /dev/null
+++ b/libmail/search.C
@@ -0,0 +1,1198 @@
+/*
+** Copyright 2002-2011, Double Precision Inc.
+**
+** See COPYING for distribution information.
+*/
+#include "libmail_config.h"
+
+#include "search.H"
+#include "envelope.H"
+#include "structure.H"
+#include "rfcaddr.H"
+#include "rfc2047decode.H"
+#include "unicode/unicode.h"
+
+#include "rfc822/rfc822.h"
+#include "rfc822/rfc822hdr.h"
+#include "rfc822/rfc2047.h"
+
+#include <sstream>
+#include <iomanip>
+#include <errno.h>
+#include <string.h>
+
+using namespace std;
+
+mail::searchParams::searchParams() : searchNot(false), criteria(replied),
+ scope(search_all)
+{
+}
+
+mail::searchParams::~searchParams()
+{
+}
+
+static const struct {
+ mail::searchParams::Criteria code;
+ const char *name;
+} searchCriteriaTable[] = {
+ {mail::searchParams::replied, "replied"},
+ {mail::searchParams::deleted, "deleted"},
+ {mail::searchParams::draft, "draft"},
+ {mail::searchParams::unread, "unread"},
+ {mail::searchParams::from, "from"},
+ {mail::searchParams::to, "to"},
+ {mail::searchParams::cc, "cc"},
+ {mail::searchParams::bcc, "bcc"},
+ {mail::searchParams::subject, "subject"},
+ {mail::searchParams::header, "header"},
+ {mail::searchParams::body, "body"},
+ {mail::searchParams::text, "text"},
+ {mail::searchParams::before, "before"},
+ {mail::searchParams::on, "on" },
+ {mail::searchParams::since, "since"},
+ {mail::searchParams::sentbefore, "sentbefore"},
+ {mail::searchParams::senton, "senton"},
+ {mail::searchParams::sentsince, "sentsince"},
+ {mail::searchParams::larger, "larger"},
+ {mail::searchParams::smaller, "smaller"},
+ {mail::searchParams::replied, NULL},
+};
+
+mail::searchParams::searchParams(string s)
+ : searchNot(false), criteria(replied),
+ scope(search_all), rangeLo(0), rangeHi(0)
+{
+ string::iterator b=s.begin(), c;
+
+ if (b != s.end())
+ switch (*b) {
+ case 'A':
+ scope=search_all;
+ break;
+ case 'M':
+ scope=search_marked;
+ break;
+ case 'U':
+ scope=search_unmarked;
+ default:
+ {
+ istringstream i(s);
+ char dummy;
+
+ i >> rangeLo >> dummy >> rangeHi;
+
+ if (!i.fail() && dummy == '-')
+ scope=search_range;
+ }
+ break;
+ }
+
+ while (b != s.end() && *b != ' ')
+ b++;
+
+ while (b != s.end() && *b == ' ')
+ b++;
+
+ if (b != s.end() && *b == '!')
+ {
+ searchNot=true;
+ ++b;
+ }
+
+ c=b;
+ while (c != s.end() && *c != ' ')
+ ++c;
+
+ string n(b, c);
+
+ size_t i;
+
+ for (i=0; searchCriteriaTable[i].name; i++)
+ if (n == searchCriteriaTable[i].name)
+ {
+ criteria=searchCriteriaTable[i].code;
+ break;
+ }
+
+ if (c != s.end())
+ ++c;
+
+ s=string(c, s.end());
+
+ s=decode(s, param1);
+ s=decode(s, param2);
+ decode(s, charset);
+}
+
+string mail::searchParams::searchParams::decode(string s, string &v)
+{
+ ostringstream o;
+
+ string::iterator b=s.begin(), e=s.end();
+
+ while (b != e)
+ {
+ if (*b == ' ')
+ {
+ ++b;
+ break;
+ }
+
+ if (*b != '%')
+ {
+ o << (char)*b;
+ ++b;
+ continue;
+ }
+
+ ++b;
+
+ char hx[3];
+
+ if (b != e)
+ {
+ hx[0]=*b++;
+ if (b != e)
+ {
+ hx[1]=*b++;
+ hx[2]=0;
+
+ istringstream i(hx);
+
+ unsigned n;
+
+ i >> hex >> n;
+
+ if (!i.fail())
+ o << (char)n;
+ }
+ }
+ }
+
+ v=o.str();
+ return string(b, e);
+}
+
+mail::searchParams::operator std::string() const
+{
+ string s;
+
+ size_t i;
+
+ for (i=0; searchCriteriaTable[i].name; i++)
+ if (criteria == searchCriteriaTable[i].code)
+ {
+ s=searchCriteriaTable[i].name;
+ break;
+ }
+
+ if (searchNot)
+ s = "!" +s;
+
+ switch (scope) {
+ case search_all:
+ s= "A " + s;
+ break;
+ case search_marked:
+ s= "M " + s;
+ break;
+ case search_unmarked:
+ s = "U " + s;
+ break;
+ case search_range:
+ {
+ ostringstream o;
+
+ o << rangeLo << '-' << rangeHi << ' ';
+
+ s=o.str() + s;
+ }
+ }
+
+ return s + " " + encode(param1) + " " + encode(param2) + " "
+ + encode(charset);
+}
+
+
+string mail::searchParams::encode(std::string s)
+{
+ ostringstream o;
+
+ string::iterator b, e;
+
+ b=s.begin();
+ e=s.end();
+
+ while (b != e)
+ {
+ if (*b <= ' ' || *b >= 127 || *b == '%')
+ {
+ o << '%' << hex << setw(2) << setfill('0') <<
+ (int)(unsigned char)*b;
+ }
+ else
+ o << (char)*b;
+ ++b;
+ }
+
+ return o.str();
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+int mail::searchOneMessage::Searcher::converted(const char *str,
+ size_t n)
+{
+ const unicode_char *uc=reinterpret_cast<const unicode_char *>(str);
+ n /= sizeof(unicode_char);
+
+ while (n)
+ {
+ mail::Search::operator<<(*uc);
+ ++uc;
+ --n;
+ }
+ return 0;
+}
+
+mail::searchCallback::searchCallback()
+{
+}
+
+mail::searchCallback::~searchCallback()
+{
+}
+
+mail::searchOneMessage::Callback::Callback()
+{
+}
+
+mail::searchOneMessage::Callback::~Callback()
+{
+}
+
+void mail::searchOneMessage::Callback::success(string message)
+{
+ (me->*nextFunc)();
+}
+
+void mail::searchOneMessage::Callback::fail(string message)
+{
+ me->callback.fail(message);
+ delete me;
+}
+
+void mail::searchOneMessage
+::Callback::reportProgress(size_t bytesCompleted,
+ size_t bytesEstimatedTotal,
+
+ size_t messagesCompleted,
+ size_t messagesEstimatedTotal)
+{
+ me->callback.reportProgress(bytesCompleted, bytesEstimatedTotal,
+ me->alreadyCompleted,
+ me->alreadyCompleted+1);
+}
+
+void mail::searchOneMessage::Callback
+::messageEnvelopeCallback(size_t messageNumber,
+ const mail::envelope &envelope)
+{
+ me->search(envelope);
+}
+
+void mail::searchOneMessage::Callback
+::messageArrivalDateCallback(size_t messageNumber,
+ time_t datetime)
+{
+ me->search(datetime);
+}
+
+void mail::searchOneMessage::Callback
+::messageSizeCallback(size_t messageNumber,
+ unsigned long size)
+{
+ me->search(size);
+}
+
+void mail::searchOneMessage::Callback
+::messageStructureCallback(size_t messageNumber,
+ const mail::mimestruct &messageStructure)
+{
+ me->search(messageStructure);
+}
+
+void mail::searchOneMessage::Callback
+::messageTextCallback(size_t n, string text)
+{
+ me->search(text);
+}
+
+mail::searchOneMessage::searchOneMessage(mail::searchCallback
+ &callbackArg,
+ mail::searchParams &searchInfoArg,
+ mail::account *ptrArg,
+ size_t messageNumArg,
+ size_t alreadyCompletedArg)
+ : callback(callbackArg),
+ searchInfo(searchInfoArg),
+ ptr(ptrArg),
+ messageNum(messageNumArg),
+ alreadyCompleted(alreadyCompletedArg)
+{
+ my_callback.me=this;
+ uid=ptr->getFolderIndexInfo(messageNum).uid;
+}
+
+mail::searchOneMessage::~searchOneMessage()
+{
+}
+
+void mail::searchOneMessage::go()
+{
+ char *c=libmail_u_convert_tocase(searchInfo.param2.c_str(),
+ searchInfo.charset.c_str(),
+ unicode_uc,
+ NULL);
+
+ if (c == NULL)
+ {
+ my_callback.fail("Unknown search charset.");
+ return;
+ }
+
+ try
+ {
+ searchInfo.param2=c;
+ free(c);
+ } catch (...) {
+ free(c);
+ LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
+ }
+
+ c=libmail_u_convert_tocase(searchInfo.param1.c_str(),
+ "iso-8859-1",
+ unicode_uc,
+ NULL);
+ if (!c)
+ {
+ my_callback.fail(strerror(errno));
+ return;
+ }
+
+ try {
+ searchInfo.param1=c;
+ free(c);
+ } catch (...) {
+ free(c);
+ LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
+ }
+
+ searchCharset=searchInfo.charset;
+ searchFlag=false;
+
+ try {
+ vector<size_t> messageNumVector;
+
+ messageNumVector.push_back(messageNum);
+
+ size_t n;
+
+ switch (searchInfo.criteria) {
+ case searchParams::larger:
+ case searchParams::smaller:
+
+ my_callback.nextFunc=
+ &mail::searchOneMessage::checkNextHeader;
+ ptr->readMessageAttributes(messageNumVector,
+ mail::account::MESSAGESIZE,
+ my_callback);
+ return;
+
+ case searchParams::before:
+ case searchParams::on:
+ case searchParams::since:
+ case searchParams::sentbefore:
+ case searchParams::senton:
+ case searchParams::sentsince:
+
+ while (searchInfo.param2.size() > 0 &&
+ unicode_isspace((unsigned char)searchInfo
+ .param2[0]))
+ searchInfo.param2=searchInfo.param2.substr(1);
+
+ n=searchInfo.param2.find(' ');
+
+ if (n != std::string::npos)
+ searchInfo.param2=
+ searchInfo.param2.substr(0,n);
+
+ for (n=0; n<searchInfo.param2.size(); n++)
+ if (searchInfo.param2[n] == '-')
+ searchInfo.param2[n]=' ';
+
+ searchInfo.param2 += " 00:00:00 -0000";
+
+ cmpDate=rfc822_parsedt(searchInfo.param2.c_str());
+
+ if (cmpDate == 0)
+ {
+ my_callback.fail("Invalid date specified");
+ return;
+ }
+
+ my_callback.nextFunc=
+ &mail::searchOneMessage::checkFwdEnvelope;
+ ptr->readMessageAttributes(messageNumVector,
+
+ (searchInfo.criteria ==
+ searchInfo.before ||
+ searchInfo.criteria ==
+ searchInfo.on ||
+ searchInfo.criteria ==
+ searchInfo.since ?
+
+ mail::account::ARRIVALDATE:
+ mail::account::ENVELOPE),
+ my_callback);
+ return;
+
+ case searchParams::from:
+ case searchParams::to:
+ case searchParams::cc:
+ case searchParams::bcc:
+ case searchParams::subject:
+ my_callback.nextFunc=
+ &mail::searchOneMessage::checkFwdEnvelope;
+ ptr->readMessageAttributes(messageNumVector,
+ mail::account::ENVELOPE,
+ my_callback);
+ return;
+
+ case searchParams::header:
+ case searchParams::body:
+ case searchParams::text:
+
+ while (!mimeSearch.empty())
+ mimeSearch.pop();
+
+ headerSearchBuffer="";
+ my_callback.nextFunc=
+ &mail::searchOneMessage::checkNextHeader;
+ ptr->readMessageAttributes(messageNumVector,
+ mail::account::MIMESTRUCTURE,
+ my_callback);
+ return;
+
+ case searchParams::replied:
+ case searchParams::deleted:
+ case searchParams::draft:
+ case searchParams::unread:
+ break;
+ }
+ } catch (...) {
+ my_callback.fail("An exception occured in mail::searchOneMessage.");
+ return;
+ }
+
+ checkSearch();
+}
+
+bool mail::searchOneMessage::sanityCheck()
+{
+ if (!ptr.isDestroyed() && messageNum < ptr->getFolderIndexSize() &&
+ uid == ptr->getFolderIndexInfo(messageNum).uid)
+ return true;
+ checkSearch();
+ return false;
+}
+
+void mail::searchOneMessage::checkFwdEnvelope()
+{
+ if (!sanityCheck())
+ return;
+
+ if (searchFlag)
+ {
+ checkSearch(); // No need
+ return;
+ }
+
+ try {
+ vector<size_t> messageNumVector;
+
+ messageNumVector.push_back(messageNum);
+
+ my_callback.nextFunc=
+ &mail::searchOneMessage::checkSearch;
+ ptr->readMessageAttributes(messageNumVector,
+ mail::account::MIMESTRUCTURE,
+ my_callback);
+ } catch (...) {
+ my_callback.fail("An exception occured in mail::searchOneMessage.");
+ return;
+ }
+}
+
+void mail::searchOneMessage::checkNextHeader()
+{
+ if (searchInfo.criteria == searchParams::header &&
+ headerSearchBuffer.size() > 0)
+ search("\n");
+
+ searchEngine.end();
+
+ if (searchEngine)
+ searchFlag=true;
+
+ if (!sanityCheck())
+ return;
+
+ mail::mimestruct *hdrs;
+ std::string bodyCharset("iso-8859-1");
+
+ for (;;) {
+
+ if (searchFlag || mimeSearch.empty())
+ {
+ checkSearch();
+ return;
+ }
+
+ hdrs=mimeSearch.front();
+
+ mimeSearch.pop();
+
+ my_callback.nextFunc=&mail::searchOneMessage::checkNextHeader;
+ headerSearchBuffer="";
+
+ switch (searchInfo.criteria) {
+ case searchParams::header:
+
+ if (!searchEngine.setString(searchInfo.param2,
+ searchCharset))
+ {
+ my_callback.fail(strerror(errno));
+ return;
+ }
+ bodyCharset="utf-8";
+ break;
+
+ case searchParams::body:
+ case searchParams::text:
+
+ if (!searchEngine.setString(searchInfo.param2,
+ searchCharset))
+ {
+ my_callback.fail(strerror(errno));
+ return;
+ }
+
+ if (hdrs->type == "TEXT" &&
+ hdrs->type_parameters.exists("CHARSET"))
+ {
+ bodyCharset=hdrs->type_parameters
+ .get("CHARSET");
+ }
+ break;
+ default:
+ checkSearch(); // Shouldn't happen.
+ return;
+ }
+
+ if (searchEngine.getSearchLen() == 0) // Empty srch string
+ {
+ checkSearch();
+ return;
+ }
+ break;
+ }
+
+ searchEngine.begin(bodyCharset.c_str(),
+ libmail_u_ucs4_native);
+
+ switch (searchInfo.criteria) {
+ case searchParams::header:
+ ptr->readMessageContent(messageNum, true, *hdrs,
+ mail::readHeadersFolded,
+ my_callback);
+ break;
+ case searchParams::body:
+ case searchParams::text:
+ ptr->readMessageContentDecoded(messageNum, true, *hdrs,
+ my_callback);
+ break;
+ default:
+ break;
+ }
+}
+
+void mail::searchOneMessage::checkSearch()
+{
+ if (searchInfo.criteria == searchInfo.text && !searchFlag)
+ {
+ // Not found, look in the headers.
+
+ searchInfo.criteria=searchInfo.header;
+ searchInfo.param1="";
+ headerSearchBuffer="";
+ searchFwdEnvelope(structureBuffer);
+ checkNextHeader();
+ return;
+ }
+
+ if (searchInfo.searchNot)
+ searchFlag= !searchFlag;
+
+ success(callback, messageNum, searchFlag);
+}
+
+void mail::searchOneMessage::success(mail::searchCallback &callback,
+ size_t n, bool result)
+{
+ delete this;
+
+ try {
+ vector<size_t> msgSet;
+
+ if (result)
+ msgSet.push_back(n);
+
+ callback.success(msgSet);
+ } catch (...) {
+ my_callback.fail("An exception has occured processing search results.");
+ return;
+ }
+}
+
+void mail::searchOneMessage::search(const mail::envelope &envelope)
+{
+ switch (searchInfo.criteria) {
+ case searchParams::from:
+ case searchParams::to:
+ case searchParams::cc:
+ case searchParams::bcc:
+ case searchParams::subject:
+ case searchParams::sentbefore:
+ case searchParams::senton:
+ case searchParams::sentsince:
+
+ searchEnvelope(envelope);
+ break;
+ default:
+ break;
+ }
+}
+
+void mail::searchOneMessage::searchEnvelope(const mail::envelope &envelope)
+{
+ string searchStr;
+ const char *header="Subject";
+
+ switch (searchInfo.criteria) {
+ case searchParams::from:
+ searchStr= mail::address::toString("", envelope.from);
+ header="From";
+ break;
+ case searchParams::to:
+ searchStr= mail::address::toString("", envelope.to);
+ header="To";
+ break;
+ case searchParams::cc:
+ searchStr= mail::address::toString("", envelope.cc);
+ header="Cc";
+ break;
+ case searchParams::bcc:
+ searchStr= mail::address::toString("", envelope.bcc);
+ header="Bcc";
+ break;
+ case searchParams::subject:
+ searchStr=envelope.subject;
+ break;
+
+ case searchParams::sentbefore:
+ case searchParams::senton:
+ case searchParams::sentsince:
+
+ doDateCmp(envelope.date);
+ return;
+ default:
+ return;
+ }
+
+ char *q=rfc822_display_hdrvalue_tobuf(header,
+ searchStr.c_str(),
+ "utf-8",
+ NULL, NULL);
+
+ if (!q)
+ return;
+
+ if (!searchEngine.setString(searchInfo.param2, searchCharset))
+ {
+ free(q);
+ return;
+ }
+
+ if (searchEngine.getSearchLen() == 0)
+ {
+ free(q);
+ return;
+ }
+
+ std::vector<unicode_char> uc;
+
+ if (!mail::iconvert::convert(q, "utf-8", uc))
+ {
+ free(q);
+ return;
+ }
+ free(q);
+
+ for (std::vector<unicode_char>::iterator
+ b(uc.begin()), e(uc.end()); b != e; ++b)
+ searchEngine << *b;
+
+ if (searchEngine)
+ searchFlag=true;
+}
+
+static const char spaces[]=" \t\r\n";
+
+void mail::searchOneMessage::search(time_t internaldate)
+{
+ switch (searchInfo.criteria) {
+ case searchParams::before:
+ case searchParams::on:
+ case searchParams::since:
+ doDateCmp(internaldate);
+ break;
+ default:
+ break;
+ }
+}
+
+void mail::searchOneMessage::search(unsigned long messageSize)
+{
+ unsigned long b=0;
+
+ istringstream i(searchInfo.param2.c_str());
+
+ i >> b;
+
+ if (!i.fail())
+ switch (searchInfo.criteria) {
+ case searchParams::larger:
+ if (messageSize > b)
+ searchFlag=true;
+ break;
+ case searchParams::smaller:
+ if (messageSize < b)
+ searchFlag=true;
+ break;
+ default:
+ break;
+ }
+}
+
+void mail::searchOneMessage::search(const mail::mimestruct &structureInfo)
+{
+ switch (searchInfo.criteria) {
+ case searchParams::from:
+ case searchParams::to:
+ case searchParams::cc:
+ case searchParams::bcc:
+ case searchParams::subject:
+ case searchParams::header:
+ case searchParams::body:
+ case searchParams::text:
+
+ structureBuffer=structureInfo;
+
+ searchFwdEnvelope(structureBuffer);
+ break;
+ default:
+ break;
+ }
+}
+
+// Search envelopes of attached messages.
+
+void mail::searchOneMessage::searchFwdEnvelope(mail::mimestruct &structureInfo)
+{
+ if (searchFlag)
+ return;
+
+ if (searchInfo.criteria == searchInfo.header)
+ mimeSearch.push(&structureInfo); // Queue up header searches
+ else if (searchInfo.criteria == searchInfo.body ||
+ searchInfo.criteria == searchInfo.text)
+ {
+ if (structureInfo.getNumChildren() == 0)
+ // Only leafs receive the content search.
+ mimeSearch.push(&structureInfo);
+ }
+ else if (structureInfo.messagerfc822())
+ searchEnvelope( structureInfo.getEnvelope());
+
+ size_t n=structureInfo.getNumChildren();
+ size_t i;
+
+ for (i=0; i<n; i++)
+ searchFwdEnvelope(*structureInfo.getChild(i));
+}
+
+void mail::searchOneMessage::search(string text)
+{
+ if (searchFlag)
+ return;
+
+ if (searchInfo.criteria == searchInfo.header)
+ {
+ text=headerSearchBuffer + text;
+
+ size_t n;
+
+ while (!searchFlag && (n=text.find('\n')) != std::string::npos)
+ {
+ searchEngine.reset();
+
+ string s=text.substr(0, n);
+
+ text=text.substr(n+1);
+
+ std::string headername;
+
+ size_t colon=s.find(':');
+
+ if (colon != std::string::npos)
+ {
+ headername=s.substr(0, colon);
+ s=s.substr(colon+1);
+ }
+
+ if (searchInfo.param1.size() > 0 &&
+ rfc822hdr_namecmp(headername.c_str(),
+ searchInfo.param1.c_str()))
+ continue;
+
+ char *value=
+ rfc822_display_hdrvalue_tobuf(headername
+ .c_str(),
+ s.c_str(),
+ "utf-8",
+ NULL,
+ NULL);
+
+ if (!value)
+ continue;
+
+
+ unicode_char *uc;
+ size_t ucsize;
+
+ if (libmail_u_convert_tou_tobuf(value,
+ strlen(value),
+ "utf-8",
+ &uc,
+ &ucsize,
+ NULL))
+ {
+ free(value);
+ continue;
+ }
+ free(value);
+
+ size_t n;
+
+ for (n=0; n<ucsize; ++n)
+ {
+ searchEngine << uc[n];
+ }
+ free(uc);
+
+ if (searchEngine)
+ searchFlag=true;
+ }
+ if (!searchFlag)
+ headerSearchBuffer=text;
+ }
+ else if (searchInfo.criteria == searchInfo.body ||
+ searchInfo.criteria == searchInfo.text)
+ {
+ searchEngine(text.c_str(), text.size());
+
+ if (searchEngine)
+ searchFlag=true;
+ }
+}
+
+void mail::searchOneMessage::doDateCmp(time_t t)
+{
+ struct tm *tmptr=gmtime(&cmpDate);
+
+ if (!tmptr)
+ return;
+
+ int y=tmptr->tm_year;
+ int m=tmptr->tm_mon;
+ int d=tmptr->tm_mday;
+
+ tmptr=localtime(&t);
+
+ int diff=0;
+
+ if (tmptr->tm_year > y)
+ diff=1;
+ else if (tmptr->tm_year < y)
+ diff= -1;
+ else if (tmptr->tm_mon > m)
+ diff=1;
+ else if (tmptr->tm_mon < m)
+ diff= -1;
+ else if (tmptr->tm_mday > d)
+ diff=1;
+ else if (tmptr->tm_mday < d)
+ diff= -1;
+
+ switch (searchInfo.criteria) {
+ case searchParams::on:
+ case searchParams::senton:
+ if (diff == 0)
+ searchFlag=true;
+ break;
+
+ case searchParams::before:
+ case searchParams::sentbefore:
+
+ if (diff < 0)
+ searchFlag=true;
+ break;
+
+ case searchParams::since:
+ case searchParams::sentsince:
+
+ if (diff >= 0)
+ searchFlag=true;
+ break;
+ default:
+ break;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////
+
+mail::searchMessages::searchMessages(mail::searchCallback
+ &callbackArg,
+ const mail::searchParams
+ &searchInfoArg,
+ mail::account *ptrArg)
+ : callback(callbackArg), server(ptrArg), searchInfo(searchInfoArg)
+{
+ search_callback.me=this;
+
+ nextMsgNum=0;
+}
+
+void mail::searchMessages::nextSearch()
+{
+ try {
+ RunLater();
+ } catch (...) {
+ callback.fail("An exception occured in mail::searchMessages.");
+ }
+}
+
+void mail::searchMessages::RunningLater()
+{
+ if (server.isDestroyed())
+ {
+ callback.fail("Folder closed while a search was in progress.");
+ delete this;
+ return;
+ }
+
+ size_t cnt=server->getFolderIndexSize();
+
+ while (nextMsgNum < cnt)
+ {
+ mail::messageInfo i=server->getFolderIndexInfo(nextMsgNum);
+
+ switch (searchInfo.scope) {
+ case searchParams::search_all:
+ break;
+
+ case searchParams::search_unmarked:
+ if (i.marked)
+ {
+ ++nextMsgNum;
+ continue;
+ }
+ break;
+
+ case searchParams::search_marked:
+ if (!i.marked)
+ {
+ ++nextMsgNum;
+ continue;
+ }
+ break;
+
+ case searchParams::search_range:
+ if (nextMsgNum < searchInfo.rangeLo
+ || nextMsgNum >= searchInfo.rangeHi)
+ {
+ ++nextMsgNum;
+ continue;
+ }
+ break;
+ }
+
+ uid=i.uid;
+
+ switch (searchInfo.criteria) {
+ case searchParams::replied:
+ if (searchInfo.searchNot ? !i.replied:i.replied)
+ successArray.push_back(uid);
+ ++nextMsgNum;
+ continue;
+ case searchParams::deleted:
+ if (searchInfo.searchNot ? !i.deleted:i.deleted)
+ successArray.push_back(uid);
+ ++nextMsgNum;
+ continue;
+ case searchParams::draft:
+ if (searchInfo.searchNot ? !i.draft:i.draft)
+ successArray.push_back(uid);
+ ++nextMsgNum;
+ continue;
+ case searchParams::unread:
+ if (searchInfo.searchNot ? !i.unread:i.unread)
+ successArray.push_back(uid);
+ ++nextMsgNum;
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (nextMsgNum >= cnt)
+ {
+ vector<size_t> msgNumArray;
+
+ size_t n=server->getFolderIndexSize();
+
+ size_t i=0;
+ size_t j;
+
+ for (j=0; j<n && i < successArray.size(); j++)
+ if (server->getFolderIndexInfo(j).uid
+ == successArray[i])
+ {
+ msgNumArray.push_back(j);
+ i++;
+ }
+
+ callback.success(msgNumArray);
+ delete this;
+ return;
+ }
+
+ searchInfoCpy=searchInfo;
+
+ mail::searchOneMessage *m=NULL;
+
+ try {
+ m=new mail::searchOneMessage(search_callback,
+ searchInfoCpy,
+ server,
+ nextMsgNum,
+ nextMsgNum);
+ nextMsgNum++;
+
+ if (!m)
+ {
+ callback.fail("Out of memory.");
+ delete m;
+ return;
+ }
+
+ m->go();
+ } catch (...) {
+ delete m;
+ LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
+ }
+}
+
+mail::searchMessages::~searchMessages()
+{
+}
+
+mail::searchMessages::Callback::Callback()
+{
+}
+
+mail::searchMessages::Callback::~Callback()
+{
+}
+
+void mail::searchMessages::Callback::fail(string message)
+{
+ me->callback.fail(message);
+ delete me;
+}
+
+void mail::searchMessages::Callback::success(const vector<size_t> &found)
+{
+ try {
+ if (found.size() > 0)
+ me->successArray.push_back(me->uid);
+ me->nextSearch();
+ } catch (...) {
+ fail("Exception occured during a search.");
+ }
+}
+
+void mail::searchMessages
+::Callback::reportProgress(size_t bytesCompleted,
+ size_t bytesEstimatedTotal,
+
+ size_t messagesCompleted,
+ size_t messagesEstimatedTotal)
+{
+ me->callback.reportProgress(bytesCompleted, bytesEstimatedTotal,
+ messagesCompleted,
+ me->server.isDestroyed() ?
+ messagesCompleted+1:
+ me->server->getFolderIndexSize());
+}
+
+void mail::searchMessages::search(mail::searchCallback
+ &callbackArg,
+ const mail::searchParams &searchInfoArg,
+ mail::account *ptrArg)
+{
+ mail::searchMessages *m=NULL;
+
+ try {
+ m=new mail::searchMessages(callbackArg, searchInfoArg,
+ ptrArg);
+
+ if (!m)
+ {
+ callbackArg.fail("Out of memory.");
+ return;
+ }
+
+ m->nextSearch();
+ } catch (...) {
+ if (m)
+ delete m;
+ callbackArg.fail("Exception occured trying to start a search.");
+ }
+}
+
+