bincimap

Log | Files | Refs | LICENSE

operator-copy.cc (5906B)


      1 /* -*- Mode: c++; -*- */
      2 /*  --------------------------------------------------------------------
      3  *  Filename:
      4  *    operator-copy.cc
      5  *  
      6  *  Description:
      7  *    Implementation of the COPY command.
      8  *
      9  *  Authors:
     10  *    Andreas Aardal Hanssen <andreas-binc curly bincimap spot org>
     11  *
     12  *  Bugs:
     13  *
     14  *  ChangeLog:
     15  *
     16  *  --------------------------------------------------------------------
     17  *  Copyright 2002-2005 Andreas Aardal Hanssen
     18  *
     19  *  This program is free software; you can redistribute it and/or modify
     20  *  it under the terms of the GNU General Public License as published by
     21  *  the Free Software Foundation; either version 2 of the License, or
     22  *  (at your option) any later version.
     23  *
     24  *  This program is distributed in the hope that it will be useful,
     25  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     26  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     27  *  GNU General Public License for more details.
     28  *
     29  *  You should have received a copy of the GNU General Public License
     30  *  along with this program; if not, write to the Free Software
     31  *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
     32  *  --------------------------------------------------------------------
     33  */
     34 #ifdef HAVE_CONFIG_H
     35 #include <config.h>
     36 #endif
     37 
     38 #include <string>
     39 
     40 #include "depot.h"
     41 #include "io.h"
     42 #include "maildir.h"
     43 #include "operators.h"
     44 #include "recursivedescent.h"
     45 #include "session.h"
     46 #include "convert.h"
     47 
     48 using namespace ::std;
     49 using namespace Binc;
     50 
     51 //----------------------------------------------------------------------
     52 CopyOperator::CopyOperator(void)
     53 {
     54 }
     55 
     56 //----------------------------------------------------------------------
     57 CopyOperator::~CopyOperator(void)
     58 {
     59 }
     60 
     61 //----------------------------------------------------------------------
     62 const string CopyOperator::getName(void) const
     63 {
     64   return "COPY";
     65 }
     66 
     67 //----------------------------------------------------------------------
     68 int CopyOperator::getState(void) const
     69 {
     70   return Session::SELECTED;
     71 }
     72 
     73 //------------------------------------------------------------------------
     74 Operator::ProcessResult CopyOperator::process(Depot &depot,
     75 					      Request &command)
     76 {
     77   Session &session = Session::getInstance();
     78   IO &logger = IOFactory::getInstance().get(2);
     79 
     80   // Get the current mailbox
     81   Mailbox *srcMailbox = depot.getSelected();
     82 
     83   // Get the destination mailbox
     84   string dmailbox = command.getMailbox();
     85   Mailbox *destMailbox = depot.get(toCanonMailbox(dmailbox));
     86   if (destMailbox == 0) {
     87     session.setResponseCode("TRYCREATE");
     88     session.setLastError("invalid mailbox " + toImapString(dmailbox));
     89     return NO;
     90   }
     91 
     92   unsigned int mode = Mailbox::SKIP_EXPUNGED;
     93   mode |= command.getUidMode() ? Mailbox::UID_MODE : Mailbox::SQNR_MODE;
     94 
     95   // Copy each message in the sequence set to the destination mailbox.
     96   bool success = true;
     97   Mailbox::iterator i = srcMailbox->begin(command.bset, mode);
     98   for (; success && i != srcMailbox->end(); ++i) {
     99     Message &source = *i;
    100 
    101     if (srcMailbox->fastCopy(source, *destMailbox,
    102 			     depot.mailboxToFilename(toCanonMailbox(dmailbox))))
    103       continue;
    104 
    105     // Have the destination mailbox create a message for us.
    106     Message *dest 
    107       = destMailbox->createMessage(depot.mailboxToFilename(toCanonMailbox(dmailbox)),
    108 				   source.getInternalDate());
    109     if (!dest) {
    110       session.setLastError(destMailbox->getLastError());
    111       success = false;
    112       break;
    113     }
    114 
    115     // Set the flags and internal date.
    116     dest->setStdFlag(source.getStdFlags());
    117     dest->setInternalDate(source.getInternalDate());
    118 
    119     // Reset the read position to the beginning of the source message
    120     source.rewind();
    121 
    122     // Copy chunks from the source message over to the destination
    123     // message.
    124     string chunk;
    125     do {
    126       int readSize = source.readChunk(chunk);
    127 
    128       if (readSize == 0)
    129 	break;
    130       else if (readSize == -1) {
    131 	logger << "when reading from message "
    132 	       << i.getSqnr() << "/" << source.getUID()
    133 	       << " in \"" << srcMailbox->getName() << "\": "
    134 	       << source.getLastError() << endl;
    135 	success = false;
    136       } else if (!dest->appendChunk(chunk)) {
    137 	logger << "when writing to \""
    138 	       << dmailbox << "\": "
    139 	       << dest->getLastError() << endl;
    140 	success = false;
    141       }
    142     } while (success);
    143 
    144     dest->close();
    145   }
    146 
    147   if (!success && !destMailbox->rollBackNewMessages()) {
    148     session.setLastError("Failed to rollback after unsuccessful copy: "
    149 			 + destMailbox->getLastError());
    150     return NO;
    151   }
    152 
    153   if (success)
    154     if (!destMailbox->commitNewMessages(depot.mailboxToFilename(toCanonMailbox(dmailbox)))) {
    155       session.setLastError("Failed to commit after successful copy: "
    156 			   + destMailbox->getLastError());
    157       return NO;
    158     }
    159 
    160   if (!success)
    161     session.setLastError("The transaction was unrolled. Please "
    162 			 "contant your system administrator for "
    163 			 "more information.");
    164 
    165   return success ? OK : NO;
    166 }
    167 
    168 //------------------------------------------------------------------------
    169 Operator::ParseResult CopyOperator::parse(Request &c_in) const
    170 {
    171   Session &session = Session::getInstance();
    172 
    173   Operator::ParseResult res;
    174   if ((res = expectSPACE()) != ACCEPT) {
    175     session.setLastError("Expected SPACE after COPY");
    176     return res;
    177   }
    178 
    179   if ((res = expectSet(c_in.getSet())) != ACCEPT) {
    180     session.setLastError("Expected sequence set after COPY SPACE");
    181     return res;
    182   }
    183 
    184   if ((res = expectSPACE()) != ACCEPT) {
    185     session.setLastError("Expected SPACE after COPY SPACE set");
    186     return res;
    187   }
    188 
    189   string mailbox;
    190   if ((res = expectMailbox(mailbox)) != ACCEPT) {
    191     session.setLastError("Expected mailbox after COPY SPACE set SPACE");
    192     return res;
    193   }
    194 
    195   if ((res = expectCRLF()) != ACCEPT) {
    196     session.setLastError("Expected CRLF after COPY SPACE set SPACE mailbox");
    197     return res;
    198   }
    199 
    200   c_in.setMailbox(mailbox);
    201   c_in.setName("COPY");
    202 
    203   return ACCEPT;
    204 }