summaryrefslogtreecommitdiff
path: root/src/operator-search.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/operator-search.cc')
-rw-r--r--src/operator-search.cc898
1 files changed, 898 insertions, 0 deletions
diff --git a/src/operator-search.cc b/src/operator-search.cc
new file mode 100644
index 0000000..0470eb5
--- /dev/null
+++ b/src/operator-search.cc
@@ -0,0 +1,898 @@
+/** --------------------------------------------------------------------
+ * @file operator-search.cc
+ * @brief Implementation of the SEARCH command.
+ * @author Andreas Aardal Hanssen
+ * @date 2002-2005
+ * ----------------------------------------------------------------- **/
+#include <string>
+#include <iostream>
+#include <algorithm>
+
+#include <ctype.h>
+
+#include "convert.h"
+#include "depot.h"
+#include "imapparser.h"
+#include "iodevice.h"
+#include "iofactory.h"
+#include "mailbox.h"
+#include "mime.h"
+#include "operators.h"
+#include "recursivedescent.h"
+#include "session.h"
+
+using namespace ::std;
+using namespace Binc;
+
+//----------------------------------------------------------------------
+bool SearchOperator::SearchNode::convertDate(const string &date,
+ time_t &t, const string &delim)
+{
+ vector<string> parts;
+ split(date, delim, parts);
+ if (parts.size() < 3) return false;
+
+ struct tm mold;
+ memset((char *) &mold, 0, sizeof(struct tm));
+ mold.tm_mday = atoi(parts[0].c_str());
+ mold.tm_year = atoi(parts[2].c_str()) - 1900;
+
+ // accept mixed case months. this is more than the standard
+ // accepts.
+ string month = parts[1];
+ lowercase(month);
+
+ if (month == "jan") mold.tm_mon = 0;
+ else if (month == "feb") mold.tm_mon = 1;
+ else if (month == "mar") mold.tm_mon = 2;
+ else if (month == "apr") mold.tm_mon = 3;
+ else if (month == "may") mold.tm_mon = 4;
+ else if (month == "jun") mold.tm_mon = 5;
+ else if (month == "jul") mold.tm_mon = 6;
+ else if (month == "aug") mold.tm_mon = 7;
+ else if (month == "sep") mold.tm_mon = 8;
+ else if (month == "oct") mold.tm_mon = 9;
+ else if (month == "nov") mold.tm_mon = 10;
+ else if (month == "dec") mold.tm_mon = 11;
+
+ t = mktime(&mold);
+ return true;
+}
+
+//----------------------------------------------------------------------
+bool SearchOperator::SearchNode::convertDateHeader(const string &d_in,
+ time_t &t)
+{
+ string date = d_in;
+ string::size_type n = date.find(',');
+ if (n != string::npos)
+ date = date.substr(n + 1);
+ trim(date);
+
+ bool result = convertDate(date, t, " ");
+ return result;
+}
+
+//----------------------------------------------------------------------
+SearchOperator::SearchNode::SearchNode(void)
+{
+}
+
+//----------------------------------------------------------------------
+SearchOperator::SearchNode::SearchNode(const BincImapParserSearchKey &a)
+{
+ init(a);
+}
+
+//----------------------------------------------------------------------
+int SearchOperator::SearchNode::getType(void) const
+{
+ return type;
+}
+
+//----------------------------------------------------------------------
+bool SearchOperator::SearchNode::match(Mailbox *mailbox,
+ Message *m, unsigned int seqnr,
+ unsigned int lastmessage,
+ unsigned int lastuid) const
+{
+ HeaderItem hitem;
+ string tmp;
+
+ switch (type) {
+ //--------------------------------------------------------------------
+ case S_ALL:
+ return true;
+ //--------------------------------------------------------------------
+ case S_ANSWERED:
+ return (m->getStdFlags() & Message::F_ANSWERED);
+ //--------------------------------------------------------------------
+ case S_BCC:
+ return m->headerContains("bcc", astring);
+ //--------------------------------------------------------------------
+ case S_BEFORE: {
+ time_t mtime = m->getInternalDate();
+ struct tm *mtime_ = localtime(&mtime);
+ mtime_->tm_sec = 0;
+ mtime_->tm_min = 0;
+ mtime_->tm_hour = 0;
+ mtime_->tm_wday = 0;
+ mtime_->tm_yday = 0;
+ mtime_->tm_isdst = 0;
+ mtime = mktime(mtime_);
+
+ time_t atime;
+ if (!convertDate(date, atime)) {
+ bincWarning << "warning, unable to convert " << date <<
+ " to a time_t" << endl;
+ return false;
+ }
+
+ return mtime < atime;
+ } //--------------------------------------------------------------------
+ case S_BODY:
+ return m->bodyContains(astring);
+ //--------------------------------------------------------------------
+ case S_CC:
+ return m->headerContains("cc", astring);
+ //--------------------------------------------------------------------
+ case S_DELETED:
+ return (m->getStdFlags() & Message::F_DELETED);
+ //--------------------------------------------------------------------
+ case S_FLAGGED:
+ return (m->getStdFlags() & Message::F_FLAGGED);
+ //--------------------------------------------------------------------
+ case S_FROM:
+ return m->headerContains("from", astring);
+ //--------------------------------------------------------------------
+ case S_KEYWORD:
+ // the server does not support keywords
+ return false;
+ //--------------------------------------------------------------------
+ case S_NEW:
+ return (m->getStdFlags() & Message::F_RECENT)
+ && !(m->getStdFlags() & Message::F_SEEN);
+ //--------------------------------------------------------------------
+ case S_OLD:
+ return !(m->getStdFlags() & Message::F_RECENT);
+ //--------------------------------------------------------------------
+ case S_ON: {
+ time_t mtime = m->getInternalDate();
+ struct tm *mtime_ = localtime(&mtime);
+ mtime_->tm_sec = 0;
+ mtime_->tm_min = 0;
+ mtime_->tm_hour = 0;
+ mtime_->tm_wday = 0;
+ mtime_->tm_yday = 0;
+ mtime_->tm_isdst = 0;
+ mtime = mktime(mtime_);
+
+ time_t atime;
+ if (!convertDate(date, atime)) {
+ bincWarning << "warning, unable to convert " << date <<
+ " to a time_t" << endl;
+ return false;
+ }
+
+ return mtime == atime;
+ } //--------------------------------------------------------------------
+ case S_RECENT:
+ return (m->getStdFlags() & Message::F_RECENT);
+ //--------------------------------------------------------------------
+ case S_SEEN:
+ return (m->getStdFlags() & Message::F_SEEN);
+ //--------------------------------------------------------------------
+ case S_SINCE: {
+ time_t mtime = m->getInternalDate();
+ struct tm *mtime_ = localtime(&mtime);
+ mtime_->tm_sec = 0;
+ mtime_->tm_min = 0;
+ mtime_->tm_hour = 0;
+ mtime_->tm_wday = 0;
+ mtime_->tm_yday = 0;
+ mtime_->tm_isdst = 0;
+ mtime = mktime(mtime_);
+
+ time_t atime;
+ if (!convertDate(date, atime)) {
+ bincWarning << "warning, unable to convert " << date <<
+ " to a time_t" << endl;
+ return false;
+ }
+
+ return mtime >= atime;
+ } //--------------------------------------------------------------------
+ case S_SUBJECT:
+ return m->headerContains("subject", astring);
+ //--------------------------------------------------------------------
+ case S_TEXT:
+ return m->textContains(astring);
+ //--------------------------------------------------------------------
+ case S_TO:
+ return m->headerContains("to", astring);
+ //--------------------------------------------------------------------
+ case S_UNANSWERED:
+ return !(m->getStdFlags() & Message::F_ANSWERED);
+ //--------------------------------------------------------------------
+ case S_UNDELETED:
+ return !(m->getStdFlags() & Message::F_DELETED);
+ //--------------------------------------------------------------------
+ case S_UNFLAGGED:
+ return !(m->getStdFlags() & Message::F_FLAGGED);
+ //--------------------------------------------------------------------
+ case S_UNKEYWORD:
+ // the server does not support keywords
+ return true;
+ //--------------------------------------------------------------------
+ case S_UNSEEN:
+ return !(m->getStdFlags() & Message::F_SEEN);
+ //--------------------------------------------------------------------
+ case S_DRAFT:
+ return (m->getStdFlags() & Message::F_DRAFT);
+ //--------------------------------------------------------------------
+ case S_HEADER:
+ return m->headerContains(astring, bstring);
+ //--------------------------------------------------------------------
+ case S_LARGER: {
+ return (m->getSize(true) > number);
+ }
+ //--------------------------------------------------------------------
+ case S_NOT:
+ for (vector<SearchNode>::const_iterator i = children.begin();
+ i != children.end(); ++i)
+ if ((*i).match(mailbox, m, seqnr, lastmessage, lastuid)) return false;
+ return true;
+ //--------------------------------------------------------------------
+ case S_OR:
+ for (vector<SearchNode>::const_iterator i = children.begin();
+ i != children.end(); ++i)
+ if ((*i).match(mailbox, m, seqnr, lastmessage, lastuid)) return true;
+ return false;
+ //--------------------------------------------------------------------
+ case S_SENTBEFORE: {
+ string tmp = m->getHeader("date");
+ if (tmp == "")
+ return false;
+
+ lowercase(tmp);
+
+ time_t mtime;
+ if (!convertDateHeader(tmp, mtime)) return false;
+
+ if (mtime == (time_t) -1) return false;
+
+ time_t atime;
+ if (!convertDate(date, atime)) {
+ bincWarning << "warning, unable to convert " << date <<
+ " to a time_t" << endl;
+ return false;
+ }
+
+ return mtime < atime;
+ } //--------------------------------------------------------------------
+ case S_SENTON: {
+ string tmp = m->getHeader("date");
+ if (tmp == "") return false;
+
+ lowercase(tmp);
+
+ time_t mtime;
+ if (!convertDateHeader(tmp, mtime)) return false;
+
+ if (mtime == (time_t) -1) return false;
+
+ time_t atime;
+ if (!convertDate(date, atime)) {
+ bincWarning << "warning, unable to convert " << date <<
+ " to a time_t" << endl;
+ return false;
+ }
+
+ return mtime == atime;
+ } //--------------------------------------------------------------------
+ case S_SENTSINCE: {
+ string tmp = m->getHeader("date");
+ if (tmp == "") return false;
+
+ lowercase(tmp);
+
+ time_t mtime;
+ if (!convertDateHeader(tmp, mtime)) return false;
+
+ if (mtime == (time_t) -1) return false;
+
+ time_t atime;
+ if (!convertDate(date, atime)) {
+ bincWarning << "warning, unable to convert " << date
+ << " to a time_t" << endl;
+ return false;
+ }
+
+ return mtime >= atime;
+ } //--------------------------------------------------------------------
+ case S_SMALLER:
+ return (m->getSize(true) < number);
+ //--------------------------------------------------------------------
+ case S_UID:
+ if (!bset->isInSet(m->getUID()))
+ if (!(m->getUID() == lastuid && !bset->isLimited())) return false;
+ return true;
+ //--------------------------------------------------------------------
+ case S_UNDRAFT:
+ return !(m->getStdFlags() & Message::F_DRAFT);
+ //--------------------------------------------------------------------
+ case S_SET:
+ if (!bset->isInSet(seqnr))
+ if (!(seqnr == lastmessage && !bset->isLimited())) return false;
+ return true;
+ //--------------------------------------------------------------------
+ case S_AND:
+ for (vector<SearchNode>::const_iterator i = children.begin();
+ i != children.end(); ++i)
+ if (!(*i).match(mailbox, m, seqnr, lastmessage, lastuid)) return false;
+ return true;
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------
+void SearchOperator::SearchNode::init(const BincImapParserSearchKey &a)
+{
+ astring = a.astring;
+ bstring = a.bstring;
+ date = a.date;
+ number = a.number;
+ uppercase(astring);
+ uppercase(bstring);
+ uppercase(date);
+
+ if (a.name == "ALL") { type = S_ALL; weight = 1; }
+ else if (a.name == "ANSWERED") { type = S_ANSWERED; weight = 1; }
+ else if (a.name == "BCC") { type = S_BCC; weight = 2; }
+ else if (a.name == "BEFORE") { type = S_BEFORE; weight = 2; }
+ else if (a.name == "BODY") { type = S_BODY; weight = 1; }
+ else if (a.name == "CC") { type = S_CC; weight = 2; }
+ else if (a.name == "DELETED") { type = S_DELETED; weight = 1; }
+ else if (a.name == "FLAGGED") { type = S_FLAGGED; weight = 1; }
+ else if (a.name == "FROM") { type = S_FROM; weight = 2; }
+ else if (a.name == "KEYWORD") { type = S_KEYWORD; weight = 3; }
+ else if (a.name == "NEW") { type = S_NEW; weight = 1; }
+ else if (a.name == "OLD") { type = S_OLD; weight = 1; }
+ else if (a.name == "ON") { type = S_ON; weight = 1; }
+ else if (a.name == "RECENT") { type = S_RECENT; weight = 1; }
+ else if (a.name == "SEEN") { type = S_SEEN; weight = 1; }
+ else if (a.name == "SINCE") { type = S_SINCE; weight = 1; }
+ else if (a.name == "SUBJECT") { type = S_SUBJECT; weight = 2; }
+ else if (a.name == "TEXT") { type = S_TEXT; weight = 4; }
+ else if (a.name == "TO") { type = S_TO; weight = 2; }
+ else if (a.name == "UNANSWERED") { type = S_UNANSWERED; weight = 1; }
+ else if (a.name == "UNDELETED") { type = S_UNDELETED; weight = 1; }
+ else if (a.name == "UNFLAGGED") { type = S_UNFLAGGED; weight = 1; }
+ else if (a.name == "UNKEYWORD") { type = S_UNKEYWORD; weight = 1; }
+ else if (a.name == "UNSEEN") { type = S_UNSEEN; weight = 1; }
+ else if (a.name == "DRAFT") { type = S_DRAFT; weight = 1; }
+ else if (a.name == "HEADER") { type = S_HEADER; weight = 3; }
+ else if (a.name == "LARGER") { type = S_LARGER; weight = 4; }
+ else if (a.name == "NOT") {
+ // ******* NOT
+ type = S_NOT;
+ weight = 1;
+
+ vector<BincImapParserSearchKey>::const_iterator i = a.children.begin();
+ while (i != a.children.end()) {
+ SearchNode b(*i);
+ weight += b.getWeight();
+ children.push_back(b);
+ ++i;
+ }
+
+ } else if (a.name == "OR") {
+ // ******* OR
+ type = S_OR;
+ weight = 0;
+
+ vector<BincImapParserSearchKey>::const_iterator i = a.children.begin();
+ while (i != a.children.end()) {
+ SearchNode b(*i);
+ weight += b.getWeight();
+
+ children.push_back(b);
+ ++i;
+ }
+
+ } else if (a.name == "SENTBEFORE") { type = S_SENTBEFORE; weight = 1; }
+ else if (a.name == "SENTON") { type = S_SENTON; weight = 1; }
+ else if (a.name == "SENTSINCE") { type = S_SENTSINCE; weight = 1; }
+ else if (a.name == "SMALLER") { type = S_SMALLER; weight = 4; }
+ else if (a.name == "UID") {
+ bset = &a.getSet();
+ type = S_UID;
+ weight = 1;
+ } else if (a.name == "UNDRAFT") { type = S_UNDRAFT; weight = 1; }
+ else if (a.type == BincImapParserSearchKey::KEY_SET) {
+ bset = &a.getSet();
+ type = S_SET;
+ weight = 1;
+ } else if (a.type == BincImapParserSearchKey::KEY_AND) {
+ // ******* AND
+ type = S_AND;
+ weight = 0;
+
+ vector<BincImapParserSearchKey>::const_iterator i = a.children.begin();
+ while (i != a.children.end()) {
+ SearchNode b(*i);
+ weight += b.getWeight();
+ children.push_back(b);
+ ++i;
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+int SearchOperator::SearchNode::getWeight(void) const
+{
+ return weight;
+}
+
+//----------------------------------------------------------------------
+void SearchOperator::SearchNode::setWeight(int i)
+{
+ weight = i;
+}
+
+//----------------------------------------------------------------------
+void SearchOperator::SearchNode::order(void)
+{
+ for (vector<SearchNode>::iterator i = children.begin();
+ i != children.end(); ++i)
+ (*i).order();
+ ::stable_sort(children.begin(), children.end(), compareNodes);
+}
+
+//----------------------------------------------------------------------
+SearchOperator::SearchOperator(void)
+{
+}
+
+//----------------------------------------------------------------------
+SearchOperator::~SearchOperator(void)
+{
+}
+
+//----------------------------------------------------------------------
+const string SearchOperator::getName(void) const
+{
+ return "SEARCH";
+}
+
+//----------------------------------------------------------------------
+int SearchOperator::getState(void) const
+{
+ return Session::SELECTED;
+}
+
+//------------------------------------------------------------------------
+Operator::ProcessResult SearchOperator::process(Depot &depot,
+ Request &command)
+{
+ Session &session = Session::getInstance();
+
+ Mailbox *mailbox = depot.getSelected();
+
+ if (command.getCharSet() != "" && command.getCharSet() != "US-ASCII") {
+ session.setLastError("The " + command.getCharSet()
+ + " charset is not supported");
+ session.setResponseCode("[BADCHARSET (\"US-ASCII\")]");
+ return NO;
+ }
+
+ bincClient << "* SEARCH";
+ bincClient.flush();
+
+ SearchNode s(command.searchkey);
+ s.order();
+
+ const unsigned int maxsqnr = mailbox->getMaxSqnr();
+ const unsigned int maxuid = mailbox->getMaxUid();
+
+ Mailbox::iterator i
+ = mailbox->begin(SequenceSet::all(), Mailbox::SKIP_EXPUNGED);
+ for (; i != mailbox->end(); ++i) {
+ Message &message = *i;
+
+ if (s.match(mailbox, &message, i.getSqnr(), maxsqnr, maxuid)) {
+ bincClient << " "
+ << (command.getUidMode() ? message.getUID() : i.getSqnr());
+ bincClient.flush();
+ }
+
+ message.close();
+ }
+
+ bincClient << endl;
+ return OK;
+}
+
+//------------------------------------------------------------------------
+Operator::ParseResult SearchOperator::parse(Request & c_in) const
+{
+ Session &session = Session::getInstance();
+
+ Operator::ParseResult res;
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectThisString("CHARSET")) == ACCEPT) {
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE after CHARSET");
+ return res;
+ }
+
+ string charset;
+ if ((res = expectAstring(charset)) != ACCEPT) {
+ session.setLastError("Expected astring after CHARSET SPACE");
+ return res;
+ }
+
+ c_in.setCharSet(charset);
+
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE after CHARSET SPACE astring");
+ return res;
+ }
+ }
+
+ BincImapParserSearchKey b;
+ if ((res = expectSearchKey(b)) != ACCEPT) {
+ session.setLastError("Expected search_key");
+ return res;
+ }
+
+ c_in.searchkey.type = BincImapParserSearchKey::KEY_AND;
+ c_in.searchkey.children.push_back(b);
+
+ while (1) {
+ if ((res = expectSPACE()) != ACCEPT)
+ break;
+
+ BincImapParserSearchKey c;
+ if ((res = expectSearchKey(c)) != ACCEPT) {
+ session.setLastError("Expected search_key after search_key SPACE");
+ return res;
+ }
+
+ c_in.searchkey.children.push_back(c);
+ }
+
+ if ((res = expectCRLF()) != ACCEPT) {
+ session.setLastError("Expected CRLF after search_key");
+ return res;
+ }
+
+ c_in.setName("SEARCH");
+ return ACCEPT;
+}
+
+//----------------------------------------------------------------------
+Operator::ParseResult
+SearchOperator::expectSearchKey(BincImapParserSearchKey &s_in) const
+{
+ Session &session = Session::getInstance();
+ Operator::ParseResult res;
+
+ s_in.type = BincImapParserSearchKey::KEY_OTHER;
+ if ((res = expectThisString("ALL")) == ACCEPT) s_in.name = "ALL";
+ else if ((res = expectThisString("ANSWERED")) == ACCEPT) s_in.name = "ANSWERED";
+ else if ((res = expectThisString("BCC")) == ACCEPT) {
+ s_in.name = "BCC";
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectAstring(s_in.astring)) != ACCEPT) {
+ session.setLastError("Expected astring");
+ return res;
+ }
+ } else if ((res = expectThisString("BEFORE")) == ACCEPT) {
+ s_in.name = "BEFORE";
+
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectDate(s_in.date)) != ACCEPT) {
+ session.setLastError("Expected date");
+ return res;
+ }
+ } else if ((res = expectThisString("BODY")) == ACCEPT) {
+ s_in.name = "BODY";
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectAstring(s_in.astring)) != ACCEPT) {
+ session.setLastError("Expected astring");
+ return res;
+ }
+ } else if ((res = expectThisString("CC")) == ACCEPT) {
+ s_in.name = "CC";
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectAstring(s_in.astring)) != ACCEPT) {
+ session.setLastError("Expected astring");
+ return res;
+ }
+ } else if ((res = expectThisString("DELETED")) == ACCEPT) s_in.name = "DELETED";
+ else if ((res = expectThisString("FLAGGED")) == ACCEPT) s_in.name = "FLAGGED";
+ else if ((res = expectThisString("FROM")) == ACCEPT) {
+ s_in.name = "FROM";
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectAstring(s_in.astring)) != ACCEPT) {
+ session.setLastError("Expected astring");
+ return res;
+ }
+ } else if ((res = expectThisString("KEYWORD")) == ACCEPT) {
+ s_in.name = "KEYWORD";
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectAtom(s_in.astring)) != ACCEPT) {
+ session.setLastError("Expected flag_keyword");
+ return res;
+ }
+ } else if ((res = expectThisString("NEW")) == ACCEPT) s_in.name = "NEW";
+ else if ((res = expectThisString("OLD")) == ACCEPT) s_in.name = "OLD";
+ else if ((res = expectThisString("ON")) == ACCEPT) {
+ s_in.name = "ON";
+
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectDate(s_in.date)) != ACCEPT) {
+ session.setLastError("Expected date");
+ return res;
+ }
+ } else if ((res = expectThisString("RECENT")) == ACCEPT) s_in.name = "RECENT";
+ else if ((res = expectThisString("SEEN")) == ACCEPT) s_in.name = "SEEN";
+ else if ((res = expectThisString("SINCE")) == ACCEPT) {
+ s_in.name = "SINCE";
+
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectDate(s_in.date)) != ACCEPT) {
+ session.setLastError("Expected date");
+ return res;
+ }
+ } else if ((res = expectThisString("SUBJECT")) == ACCEPT) {
+ s_in.name = "SUBJECT";
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectAstring(s_in.astring)) != ACCEPT) {
+ session.setLastError("Expected astring");
+ return res;
+ }
+ } else if ((res = expectThisString("TEXT")) == ACCEPT) {
+ s_in.name = "TEXT";
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectAstring(s_in.astring)) != ACCEPT) {
+ session.setLastError("Expected astring");
+ return res;
+ }
+ } else if ((res = expectThisString("TO")) == ACCEPT) {
+ s_in.name = "TO";
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectAstring(s_in.astring)) != ACCEPT) {
+ session.setLastError("Expected astring");
+ return res;
+ }
+ } else if ((res = expectThisString("UNANSWERED")) == ACCEPT)
+ s_in.name = "UNANSWERED";
+ else if ((res = expectThisString("UNDELETED")) == ACCEPT) s_in.name = "UNDELETED";
+ else if ((res = expectThisString("UNFLAGGED")) == ACCEPT) s_in.name = "UNFLAGGED";
+ else if ((res = expectThisString("UNKEYWORD")) == ACCEPT) {
+ s_in.name = "UNKEYWORD";
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectAtom(s_in.astring)) != ACCEPT) {
+ session.setLastError("Expected flag_keyword");
+ return res;
+ }
+ } else if ((res = expectThisString("UNSEEN")) == ACCEPT) s_in.name = "UNSEEN";
+ else if ((res = expectThisString("DRAFT")) == ACCEPT) s_in.name = "DRAFT";
+ else if ((res = expectThisString("HEADER")) == ACCEPT) {
+ s_in.name = "HEADER";
+
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectAstring(s_in.astring)) != ACCEPT) {
+ session.setLastError("Expected astring");
+ return res;
+ }
+
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectAstring(s_in.bstring)) != ACCEPT) {
+ session.setLastError("Expected astring");
+ return res;
+ }
+ } else if ((res = expectThisString("LARGER")) == ACCEPT) {
+ s_in.name = "LARGER";
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectNumber(s_in.number)) != ACCEPT) {
+ session.setLastError("Expected number");
+ return res;
+ }
+ } else if ((res = expectThisString("NOT")) == ACCEPT) {
+ s_in.name = "NOT";
+ s_in.type = BincImapParserSearchKey::KEY_NOT;
+
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ BincImapParserSearchKey s;
+ if ((res = expectSearchKey(s)) != ACCEPT) {
+ session.setLastError("Expected search_key");
+ return res;
+ }
+ s_in.children.push_back(s);
+ } else if ((res = expectThisString("OR")) == ACCEPT) {
+ s_in.name = "OR";
+ s_in.type = BincImapParserSearchKey::KEY_OR;
+
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ BincImapParserSearchKey s;
+ if ((res = expectSearchKey(s)) != ACCEPT) {
+ session.setLastError("Expected search_key");
+ return res;
+ }
+ s_in.children.push_back(s);
+
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ BincImapParserSearchKey t;
+ if ((res = expectSearchKey(t)) != ACCEPT) {
+ session.setLastError("Expected search_key");
+ return res;
+ }
+ s_in.children.push_back(t);
+ } else if ((res = expectThisString("SENTBEFORE")) == ACCEPT) {
+ s_in.name = "SENTBEFORE";
+
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectDate(s_in.date)) != ACCEPT) {
+ session.setLastError("Expected date");
+ return res;
+ }
+ } else if ((res = expectThisString("SENTON")) == ACCEPT) {
+ s_in.name = "SENTON";
+
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectDate(s_in.date)) != ACCEPT) {
+ session.setLastError("Expected date");
+ return res;
+ }
+
+ } else if ((res = expectThisString("SENTSINCE")) == ACCEPT) {
+ s_in.name = "SENTSINCE";
+
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectDate(s_in.date)) != ACCEPT) {
+ session.setLastError("Expected date");
+ return res;
+ }
+ } else if ((res = expectThisString("SMALLER")) == ACCEPT) {
+ s_in.name = "SMALLER";
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectNumber(s_in.number)) != ACCEPT) {
+ session.setLastError("Expected number");
+ return res;
+ }
+ } else if ((res = expectThisString("UID")) == ACCEPT) {
+ s_in.name = "UID";
+ if ((res = expectSPACE()) != ACCEPT) {
+ session.setLastError("Expected SPACE");
+ return res;
+ }
+
+ if ((res = expectSet(s_in.bset)) != ACCEPT) {
+ session.setLastError("Expected number");
+ return res;
+ }
+ } else if ((res = expectThisString("UNDRAFT")) == ACCEPT)
+ s_in.name = "UNDRAFT";
+ else if ((res = expectSet(s_in.bset)) == ACCEPT) {
+ s_in.name = "";
+ s_in.type = BincImapParserSearchKey::KEY_SET;
+ } else if ((res = expectThisString("(")) == ACCEPT) {
+ s_in.type = BincImapParserSearchKey::KEY_AND;
+
+ while (1) {
+ BincImapParserSearchKey c;
+ if ((res = expectSearchKey(c)) != ACCEPT) {
+ session.setLastError("Expected search_key");
+ return res;
+ }
+
+ s_in.children.push_back(c);
+
+ if ((res = expectSPACE()) != ACCEPT) break;
+ }
+
+ if ((res = expectThisString(")")) != ACCEPT) {
+ session.setLastError("Expected )");
+ return res;
+ }
+ } else
+ return REJECT;
+
+ return ACCEPT;
+}