diff options
Diffstat (limited to 'src/operator-copy.cc')
-rw-r--r-- | src/operator-copy.cc | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/src/operator-copy.cc b/src/operator-copy.cc new file mode 100644 index 0000000..cbe8767 --- /dev/null +++ b/src/operator-copy.cc @@ -0,0 +1,169 @@ +/** -------------------------------------------------------------------- + * @file operator-copy.cc + * @brief Implementation of the COPY command. + * @author Andreas Aardal Hanssen + * @date 2002-2005 + * ----------------------------------------------------------------- **/ +#include <string> + +#include "depot.h" +#include "iodevice.h" +#include "iofactory.h" +#include "maildir.h" +#include "operators.h" +#include "recursivedescent.h" +#include "session.h" +#include "convert.h" + +using namespace ::std; +using namespace Binc; + +//---------------------------------------------------------------------- +CopyOperator::CopyOperator(void) +{ +} + +//---------------------------------------------------------------------- +CopyOperator::~CopyOperator(void) +{ +} + +//---------------------------------------------------------------------- +const string CopyOperator::getName(void) const +{ + return "COPY"; +} + +//---------------------------------------------------------------------- +int CopyOperator::getState(void) 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 == 0) { + session.setResponseCode("TRYCREATE"); + session.setLastError("invalid mailbox " + toImapString(dmailbox)); + return 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() << endl; + success = false; + } else if (!dest->appendChunk(chunk)) { + bincWarning << "when writing to \"" + << dmailbox << "\": " + << dest->getLastError() << endl; + success = false; + } + } while (success); + + dest->close(); + } + + if (!success && !destMailbox->rollBackNewMessages()) { + session.setLastError("Failed to rollback after unsuccessful copy: " + + destMailbox->getLastError()); + return NO; + } + + if (success) + if (!destMailbox->commitNewMessages(depot.mailboxToFilename(toCanonMailbox(dmailbox)))) { + session.setLastError("Failed to commit after successful copy: " + + destMailbox->getLastError()); + return NO; + } + + if (!success) + session.setLastError("The transaction was unrolled. Please " + "contant your system administrator for " + "more information."); + + return success ? OK : NO; +} + +//------------------------------------------------------------------------ +Operator::ParseResult CopyOperator::parse(Request &c_in) const +{ + Session &session = Session::getInstance(); + + Operator::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; +} |