diff options
Diffstat (limited to 'src/operator-lsub.cc')
-rw-r--r-- | src/operator-lsub.cc | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/src/operator-lsub.cc b/src/operator-lsub.cc new file mode 100644 index 0000000..f776503 --- /dev/null +++ b/src/operator-lsub.cc @@ -0,0 +1,238 @@ +/** -------------------------------------------------------------------- + * @file operator-lsub.cc + * @brief Implementation of the LSUB command. + * @author Andreas Aardal Hanssen + * @date 2002-2005 + * ----------------------------------------------------------------- **/ +#include <algorithm> +#include <string> +#include <vector> +#include <iostream> + +#include "convert.h" +#include "depot.h" +#include "iodevice.h" +#include "iofactory.h" +#include "mailbox.h" +#include "operators.h" +#include "recursivedescent.h" +#include "regmatch.h" +#include "session.h" + +namespace { + const int DIR_SELECT = 0x01; + const int DIR_MARKED = 0x02; + const int DIR_NOINFERIORS = 0x04; + const int DIR_LEAF = 0x08; +} + +using namespace ::std; +using namespace Binc; + +//---------------------------------------------------------------------- +LsubOperator::LsubOperator(void) +{ +} + +//---------------------------------------------------------------------- +LsubOperator::~LsubOperator(void) +{ +} + +//---------------------------------------------------------------------- +const string LsubOperator::getName(void) const +{ + return "LSUB"; +} + +//---------------------------------------------------------------------- +int LsubOperator::getState(void) const +{ + return Session::AUTHENTICATED | Session::SELECTED; +} + +//------------------------------------------------------------------------ +Operator::ProcessResult LsubOperator::process(Depot &depot, + Request &command) +{ + const char delim = depot.getDelimiter(); + + // remove leading or trailing delimiter in wildcard + string wildcard = command.getListMailbox(); + trim(wildcard, string(&delim, 1)); + + // convert wildcard to regular expression + string regex = toRegex(wildcard, depot.getDelimiter()); + string wildcardLower = regex; + lowercase(wildcardLower); + if (wildcardLower.substr(0, 6) == "^inbox") + regex = "^[iI][nN][bB][oO][xX]" + regex.substr(6); + + // remove leading or trailing delimiter in reference + string ref = command.getMailbox(); + trim(ref, string(&delim, 1)); + wildcardLower = ref; + lowercase(wildcardLower); + if (wildcardLower.substr(0, 5) == "inbox" + && (wildcardLower.length() == 5 || wildcardLower[5] == delim)) + ref = "INBOX" + ref.substr(5); + + // a multimap from mailbox name to flags + multimap<string, int> mailboxes; + + // read through all entries in depository. + for (Depot::iterator i = depot.begin("."); i != depot.end(); ++i) { + const string path = *i; + const string mpath = depot.filenameToMailbox(path); + Mailbox *m = 0; + + // skip entries that are not identified as mailboxes + if ((m = depot.get(mpath)) == 0) + continue; + + // convert file name to mailbox name. skip it if there is no + // corresponding mailbox name. + string tmp = toCanonMailbox(depot.filenameToMailbox(path)); + trim(tmp, string(&delim, 1)); + if (tmp == "") + continue; + else { + int flags = DIR_SELECT; + multimap<string, int>::iterator mi = mailboxes.find(tmp); + if (mi != mailboxes.end()) { + flags |= mi->second; + mailboxes.erase(mi); + } + mailboxes.insert(make_pair(tmp, flags)); + } + + // now add all superior mailboxes with no flags set if not + // added already. + string::size_type pos = tmp.rfind(delim); + while (pos != string::npos) { + tmp = tmp.substr(0, pos); + trim(tmp, string(&delim, 1)); + + multimap<string, int>::iterator mi = mailboxes.find(tmp); + if (mi == mailboxes.end()) mailboxes.insert(make_pair(tmp, 0)); + + pos = tmp.rfind(delim); + } + } + + // find leaf nodes O(N^2) + multimap<string, int>::iterator i; + for (i = mailboxes.begin(); i != mailboxes.end(); ++i) { + string mailbox = i->first; + mailbox += delim; + + bool leaf = true; + multimap<string, int>::const_iterator j; + for (j = mailboxes.begin(); j != mailboxes.end(); ++j) { + string::size_type pos = j->first.rfind(delim); + if (pos == string::npos) continue; + string base = j->first.substr(0, pos + 1); + if (mailbox == base) { + leaf = false; + break; + } + } + if (leaf) { + unsigned int flags = i->second; + flags |= DIR_LEAF; + i->second = flags; + } + } + + depot.loadSubscribes(); + + vector<string> subscribed = depot.getSubscriptions(); + sort(subscribed.begin(), subscribed.end()); + + // finally, print all mailbox entries with flags. + for (vector<string>::const_iterator j = subscribed.begin(); + j != subscribed.end(); ++j) { + if (ref == "" || (ref.length() <= (*j).length() && ref == (*j).substr(0, ref.length()))) + if (regexMatch((*j).substr(ref.length()), regex) == 0) { + int flags = 0; + for (i = mailboxes.begin(); i != mailboxes.end(); ++i) { + if (i->first == *j) { + flags = i->second; + break; + } + } + bincClient << "* LSUB ("; + string sep = ""; + bool noselect = false; + if (!(flags & DIR_SELECT)) { + bincClient << sep << "\\Noselect"; + sep = " "; + noselect = true; + } + if (!noselect) { + if (flags & DIR_MARKED) + bincClient << sep << "\\Marked"; + else + bincClient << sep << "\\Unmarked"; + sep = " "; + } + if (flags & DIR_LEAF) + bincClient << sep << "\\HasNoChildren"; + else + bincClient << sep << "\\HasChildren"; + sep = " "; + if (flags & DIR_NOINFERIORS) + bincClient << sep << "\\Noinferiors"; + bincClient << ") \"" << depot.getDelimiter() << "\" " + << toImapString(*j) << endl; + } + } + + return OK; +} + +//---------------------------------------------------------------------- +Operator::ParseResult LsubOperator::parse(Request &c_in) const +{ + Session &session = Session::getInstance(); + + if (c_in.getUidMode()) + return REJECT; + + Operator::ParseResult res; + if ((res = expectSPACE()) != ACCEPT) { + session.setLastError("Expected SPACE after LSUB"); + return ERROR; + } + + string mailbox; + if ((res = expectMailbox(mailbox)) != ACCEPT) { + session.setLastError("Expected mailbox after LSUB SPACE"); + return ERROR; + } + + c_in.setMailbox(mailbox); + + if ((res = expectSPACE()) != ACCEPT) { + session.setLastError("Expected SPACE after LSUB SPACE mailbox"); + return ERROR; + } + + string listmailbox; + if ((res = expectListMailbox(listmailbox)) != ACCEPT) { + session.setLastError("Expected list_mailbox after LSUB SPACE" + " mailbox SPACE"); + return ERROR; + } + + if ((res = expectCRLF()) != ACCEPT) { + session.setLastError("Expected CRLF after LSUB SPACE" + " mailbox SPACE list_mailbox"); + return ERROR; + } + + c_in.setListMailbox(listmailbox); + c_in.setName("LSUB"); + + return ACCEPT; +} |