/** * @file operator-copy.cc * @brief Implementation of the COPY command. * @author Andreas Aardal Hanssen * @date 2002-2005 */ #include "convert.h" #include "depot.h" #include "iodevice.h" #include "iofactory.h" #include "maildir.h" #include "operators.h" #include "recursivedescent.h" #include "session.h" #include using namespace Binc; using std::string; CopyOperator::CopyOperator() {} CopyOperator::~CopyOperator() {} const string CopyOperator::getName() const { return "COPY"; } Session::State CopyOperator::getState() const { return Session::SELECTED; } Operator::ProcessResult CopyOperator::process(Depot &depot, Request &command) { Session &session = Session::getInstance(); // Get the current mailbox Mailbox *srcMailbox = depot.getSelected(); // Get the destination mailbox string dmailbox = command.getMailbox(); Mailbox *destMailbox = depot.get(toCanonMailbox(dmailbox)); if (destMailbox == nullptr) { session.setResponseCode("TRYCREATE"); session.setLastError("invalid mailbox " + toImapString(dmailbox)); return Operator::ProcessResult::NO; } unsigned int mode = Mailbox::SKIP_EXPUNGED; mode |= command.getUidMode() ? Mailbox::UID_MODE : Mailbox::SQNR_MODE; // Copy each message in the sequence set to the destination mailbox. bool success = true; Mailbox::iterator i = srcMailbox->begin(command.bset, mode); for (; success && i != srcMailbox->end(); ++i) { Message &source = *i; if (srcMailbox->fastCopy(source, *destMailbox, depot.mailboxToFilename(toCanonMailbox(dmailbox)))) continue; // Have the destination mailbox create a message for us. Message *dest = destMailbox->createMessage( depot.mailboxToFilename(toCanonMailbox(dmailbox)), source.getInternalDate()); if (!dest) { session.setLastError(destMailbox->getLastError()); success = false; break; } // Set the flags and internal date. dest->setStdFlag(source.getStdFlags()); dest->setInternalDate(source.getInternalDate()); // Copy chunks from the source message over to the destination // message. string chunk; do { int readSize = source.readChunk(chunk); if (readSize == 0) { break; } else if (readSize == -1) { bincWarning << "when reading from message " << i.getSqnr() << "/" << source.getUID() << " in \"" << srcMailbox->getName() << "\": " << source.getLastError() << std::endl; success = false; } else if (!dest->appendChunk(chunk)) { bincWarning << "when writing to \"" << dmailbox << "\": " << dest->getLastError() << std::endl; success = false; } } while (success); dest->close(); } if (!success && !destMailbox->rollBackNewMessages()) { session.setLastError("Failed to rollback after unsuccessful copy: " + destMailbox->getLastError()); return Operator::ProcessResult::NO; } if (success) { if (!destMailbox->commitNewMessages(depot.mailboxToFilename(toCanonMailbox(dmailbox)))) { session.setLastError("Failed to commit after successful copy: " + destMailbox->getLastError()); return Operator::ProcessResult::NO; } } if (!success) { session.setLastError("The transaction was unrolled. Please " "contant your system administrator for " "more information."); } return success ? Operator::ProcessResult::OK : Operator::ProcessResult::NO; } Parser::ParseResult CopyOperator::parse(Request &c_in) { constexpr auto ACCEPT = Parser::ParseResult::ACCEPT; Session &session = Session::getInstance(); Parser::ParseResult res; if ((res = expectSPACE()) != ACCEPT) { session.setLastError("Expected SPACE after COPY"); return res; } if ((res = expectSet(c_in.getSet())) != ACCEPT) { session.setLastError("Expected sequence set after COPY SPACE"); return res; } if ((res = expectSPACE()) != ACCEPT) { session.setLastError("Expected SPACE after COPY SPACE set"); return res; } string mailbox; if ((res = expectMailbox(mailbox)) != ACCEPT) { session.setLastError("Expected mailbox after COPY SPACE set SPACE"); return res; } if ((res = expectCRLF()) != ACCEPT) { session.setLastError("Expected CRLF after COPY SPACE set SPACE mailbox"); return res; } c_in.setMailbox(mailbox); c_in.setName("COPY"); return ACCEPT; }