/** * @file operator-store.cc * @brief Implementation of the STORE command * @author Andreas Aardal Hanssen * @date 2002-2005 */ #include "depot.h" #include "imapparser.h" #include "mailbox.h" #include "operators.h" #include "pendingupdates.h" #include "recursivedescent.h" #include "session.h" #include #include using namespace Binc; using std::string; using std::vector; StoreOperator::StoreOperator() {} StoreOperator::~StoreOperator() {} const string StoreOperator::getName() const { return "STORE"; } Session::State StoreOperator::getState() const { return Session::SELECTED; } Operator::ProcessResult StoreOperator::process(Depot &depot, Request &command) { Mailbox *mailbox = depot.getSelected(); // mask all passed flags together unsigned int newflags = (unsigned int)Message::F_NONE; vector newCustomFlags; for (const auto &f_i : command.flags) { if (f_i == "\\Deleted") newflags |= Message::F_DELETED; else if (f_i == "\\Answered") newflags |= Message::F_ANSWERED; else if (f_i == "\\Seen") newflags |= Message::F_SEEN; else if (f_i == "\\Draft") newflags |= Message::F_DRAFT; else if (f_i == "\\Flagged") newflags |= Message::F_FLAGGED; else newCustomFlags.push_back(f_i); } // pass through all messages unsigned int mode = command.getUidMode() ? Mailbox::UID_MODE : Mailbox::SQNR_MODE; Mailbox::iterator i = mailbox->begin(command.bset, Mailbox::SKIP_EXPUNGED | mode); for (; i != mailbox->end(); ++i) { Message &message = *i; // get and reset the old flags unsigned int flags = (unsigned int)message.getStdFlags(); bool recent = (flags & Message::F_RECENT) != 0; flags &= (~Message::F_RECENT); // add, remove or set flags switch (command.getMode()[0]) { case '+': flags |= newflags; for (const auto &it : newCustomFlags) message.setCustomFlag(it); break; case '-': flags &= ~newflags; for (const auto &it : newCustomFlags) message.removeCustomFlag(it); break; default: flags = newflags; message.resetCustomFlags(); for (const auto &it : newCustomFlags) message.setCustomFlag(it); break; }; // set new flags, even if they weren't changed. if (recent) flags |= Message::F_RECENT; message.resetStdFlags(); message.setStdFlag(flags); } // commit flag changes to mailbox (might change mailbox) mailbox->updateFlags(); // check mailbox for updates, and report them if (command.getMode().find(".SILENT") != string::npos) { pendingUpdates(mailbox, PendingUpdates::EXISTS | PendingUpdates::RECENT, false, false, false, command.getUidMode()); } else { pendingUpdates(mailbox, PendingUpdates::EXISTS | PendingUpdates::RECENT | PendingUpdates::EXPUNGE | PendingUpdates::FLAGS, false, false, false, command.getUidMode()); } return ProcessResult::OK; } Parser::ParseResult StoreOperator::parse(Request &c_in, Parser &p) { constexpr auto ACCEPT = Parser::ParseResult::ACCEPT; Session &session = Session::getInstance(); Parser::ParseResult res; if ((res = p.expectSPACE()) != ACCEPT) { session.setLastError("Expected SPACE"); return res; } if ((res = p.expectSet(c_in.getSet())) != ACCEPT) { session.setLastError("Expected Set"); return res; } if ((res = p.expectSPACE()) != ACCEPT) { session.setLastError("Expected SPACE"); return res; } string mode; if ((res = p.expectThisString("+")) == ACCEPT) mode = "+"; else if ((res = p.expectThisString("-")) == ACCEPT) mode = "-"; if ((res = p.expectThisString("FLAGS")) != ACCEPT) { session.setLastError("Expected FLAGS"); return res; } else { mode += "FLAGS"; } if ((res = p.expectThisString(".SILENT")) == ACCEPT) mode += ".SILENT"; c_in.setMode(mode); if ((res = p.expectSPACE()) != ACCEPT) { session.setLastError("Expected SPACE"); return res; } bool paren = false; if ((res = p.expectThisString("(")) == ACCEPT) paren = true; if ((res = p.expectFlag(c_in.getFlags())) == ACCEPT) { while (1) { if ((res = p.expectSPACE()) != ACCEPT) break; if ((res = p.expectFlag(c_in.getFlags())) != ACCEPT) { session.setLastError("Expected flag after SPACE"); return res; } } } if (paren) { if ((res = p.expectThisString(")")) != ACCEPT) { session.setLastError("Expected )"); return res; } } if ((res = p.expectCRLF()) != ACCEPT) { session.setLastError("Expected CRLF"); return res; } return ACCEPT; }