diff -r 000000000000 -r 72b543305e3a email/imap4mtm/imapprotocolcontroller/src/cimapcompoundcopyfromlocal.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/email/imap4mtm/imapprotocolcontroller/src/cimapcompoundcopyfromlocal.cpp Thu Dec 17 08:44:11 2009 +0200 @@ -0,0 +1,416 @@ +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "cimapcompoundcopyfromlocal.h" + +#include +#include + +#include "cimapfolder.h" +#include "cimapsession.h" +#include "cimapsessionconsts.h" +#include "cimaplogger.h" +#include "imappaniccodes.h" + +#include "mobilitytestmtmapi.h" + +CImapCompoundCopyFromLocal::CImapCompoundCopyFromLocal( CImapSyncManager& aSyncManager, + CMsvServerEntry& aServerEntry, + CImapSettings& aImapSettings, + TBool aIsMove, + const TMsvId aDestination) : + CImapCompoundBase(aSyncManager, aServerEntry, aImapSettings), + iIsMove(aIsMove), iDestinationFolderId(aDestination) + { + + } + +CImapCompoundCopyFromLocal::~CImapCompoundCopyFromLocal() + { + delete iSourceSel; + delete iSendMessage; + } + +CImapCompoundCopyFromLocal* CImapCompoundCopyFromLocal::NewL( CImapSyncManager& aSyncManager, + CMsvServerEntry& aServerEntry, + CImapSettings& aImapSettings, + TBool aIsMove, + const CMsvEntrySelection& aSourceSel, + const TMsvId aDestination) + { + CImapCompoundCopyFromLocal* self = new (ELeave) CImapCompoundCopyFromLocal(aSyncManager, + aServerEntry, + aImapSettings, + aIsMove, + aDestination); + CleanupStack::PushL(self); + self->ConstructL(aSourceSel); + CleanupStack::Pop(self); + return self; + + } + +void CImapCompoundCopyFromLocal::ConstructL(const CMsvEntrySelection& aSourceSel) + { + // Save parameters + iSourceSel = aSourceSel.CopyL(); + iSendMessage = CImSendMessage::NewL(iServerEntry); + + iMessageSelection = iSelectionStillToCopy = iSelectionStillToDelete = aSourceSel.Count(); + iTotalSize = CalculateDownloadSizeL(*iSourceSel); + + // Add to the active scheduler + CActiveScheduler::Add(this); + } + +void CImapCompoundCopyFromLocal::StartOperation(TRequestStatus& aStatus, CImapSession& aSession) + { + iSession = &aSession; + __LOG_TEXT(iSession->LogId(), "CImapCompoundCopyFromLocal::StartOperation()"); + iNextStep = ECheckDestinationMailbox; + Queue(aStatus); + CompleteSelf(); + } + +/** +Handles the compound operation state machine + +Sequence of steps: + For all messages + ESetSource + EAppendMessage + EDeleteLocalMessage + ESelectDestinationMailboxRO + ENewSyncFolder + EFinished + +@return ETrue if compound operation is completed, + EFalse otherwise. +*/ +TBool CImapCompoundCopyFromLocal::DoRunLoopL() + { + SetCurrentStep(); + switch (iCurrentStep) + { + case ECheckDestinationMailbox: // synchonous + { + iNextStep = ESetSource; // default next step to ESetSource + iDestinationFolder = iSyncManager.GetFolderL(iDestinationFolderId); + if (iDestinationFolder==NULL) + { + // note the error code for the progress report and complete + iProgressErrorCode = KErrNotFound; + iNextStep = EFinished; + } + // go to the next step + return EFalse; + } + + case ESetSource: // synchonous + { + if (iSelectionStillToCopy > 0) + { + // suspend operation if stop for migrate has been requested + if (iStopForMigrate) + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundCopyFromLocal::Stopped for migrate"); + iCurrentStep = ESuspendedForMigrate; + iNextStep = ESetSource; + Complete(KErrNone); + return ETrue; + } + + // decrement iSelectionStillToCopy - it becomes the index in the list + // of the current message to operate on. + --iSelectionStillToCopy; + + iCurrentMsgId = iSourceSel->At(iSelectionStillToCopy); + iNextStep = EAppendMessage; + } + else + { + // All messages copied... + iNextStep = ESelectDestinationMailboxRO; + } + // immediately proceed to the next step + return EFalse; + } + + case EAppendMessage: // asynchonous + { + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyFromLocal1); + SetEntryL(iCurrentMsgId); + TTime messageDate = iServerEntry.Entry().iDate; + + iSendMessage->InitialiseL(iCurrentMsgId, + ESendAsMimeEmail, + messageDate, + iImapSettings.ServerAddress(), + KCharacterSetIdentifierUtf8, + ESendNoCopy); + + iSession->AppendL(iStatus, *iSendMessage, iDestinationFolder->FullFolderPathL()); + iNextStep = (iIsMove) ? EDeleteLocalMessage : ESetSource; + SetActive(); + break; + } + + case EDeleteLocalMessage: // synchonous + { + SetEntryL(iServerEntry.Entry().Parent()); + User::LeaveIfError(iServerEntry.DeleteEntry(iCurrentMsgId)); + + --iSelectionStillToDelete; + + iNextStep = ESetSource; + // immediately proceed to the next step + return EFalse; + } + + case ESelectDestinationMailboxRO: // asynchonous + { + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyFromLocal2); // SELECT destination folder + iDestinationFolder->ExamineL(iStatus, *iSession); + iNextStep = ENewSyncFolder; + SetActive(); + break; + } + + case ENewSyncFolder: // asynchonous + { + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyFromLocal3); // synchronising destination folder + // if the current folder hasn't actually changed then don't + // bother with the Sync + if (!iDestinationFolder->Changed(*iSession)) + { + iNextStep = EFinished; + return EFalse; + } + + iSyncProgressState=TImap4SyncProgress::ESyncOther; + iDestinationFolder->SynchroniseL(iStatus, *iSession, ETrue, 0); + iNextStep = EFinished; + SetActive(); + break; + } + + case EFinished: // finished + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundCopyFromLocal::Completing OK"); + iProgressState = TImap4GenericProgress::EIdle; + iSyncProgressState = TImap4SyncProgress::EIdle; + Complete(KErrNone); + return ETrue; + } + + default: + { + __ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyFromLocalCompoundUnexpectedState)); + // unexpected state - complete the request + iProgressState = TImap4GenericProgress::EIdle; + return ETrue; + } + } + return EFalse; + } + +/** +May be called in case of a genuine cancel or a cancel for migrate. +Following a genuine cancel, the compound operation will be deleted. +Following a cancel for migrate, the compound operation will be resumed, +so the iNextState is updated here to ensure the operation is +correctly restarted. + +In either case, CMsgActive::DoCancel() is called to complete the +user request with KErrCancel. + +Note that if the default CMsgActive::DoComplete() is overridden, +then that must also be modified to handle either case described above. +*/ +void CImapCompoundCopyFromLocal::DoCancel() + { + switch (iCurrentStep) + { + case ESelectDestinationMailboxRO: + { + // outstanding request is on the imap session. + // Note that although select operations are performed on a folder they + // actually pass our iStatus to the session, so that is why we cancel + // the session for them. + iSession->Cancel(); + iNextStep = ESelectDestinationMailboxRO; + break; + } + case EAppendMessage: + { + iSession->Cancel(); + iNextStep = EAppendMessage; + break; + } + case ENewSyncFolder: + { + iDestinationFolder->Cancel(); + // on resume, will need to reselect the folder first + iNextStep = ENewSyncFolder; + break; + } + case ECheckDestinationMailbox: + case ESetSource: + case EDeleteLocalMessage : + case EFinished: + { + // self-completed or no outstanding request. + iNextStep = ESelectDestinationMailboxRO; + break; + } + case ESuspendedForMigrate: + default: + { + __ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyFromLocalCompoundCancelUnexpectedState)); + iNextStep = ESelectDestinationMailboxRO; + break; + } + } // end of switch (iCurrentStep) + + if (!iCancelForMigrate) + { + // genuine cancel - update progress + iProgressErrorCode = KErrCancel; + } + CMsgActive::DoCancel(); + } + +void CImapCompoundCopyFromLocal::Progress(TImap4CompoundProgress& aCompoundProgress) + { + if (iIsMove) + { + aCompoundProgress.iGenericProgress.iOperation = TImap4GenericProgress::EMoveFromLocal; + } + else + { + aCompoundProgress.iGenericProgress.iOperation = TImap4GenericProgress::ECopyFromLocal; + } + + // Progress through the received selection + aCompoundProgress.iGenericProgress.iTotalSize = iTotalSize; + aCompoundProgress.iGenericProgress.iMsgsToDo = iMessageSelection; + aCompoundProgress.iGenericProgress.iMsgsDone = iMessageSelection - iSelectionStillToCopy; + + aCompoundProgress.iSyncProgress.iState=iSyncProgressState; + + //if currently syncing then get the latest progress + if(iSyncProgressState!=TImap4SyncProgress::EIdle) + { + iDestinationFolder->Progress(aCompoundProgress.iSyncProgress); + } + + // Put error into progress buffer + if( aCompoundProgress.iGenericProgress.iErrorCode == KErrNone ) + { + aCompoundProgress.iGenericProgress.iErrorCode = iProgressErrorCode; + } + } + +/** +Handles NO/BAD responses according to current step. +Negative server responses are not fatal - the error is saved in +the message currently being operated on and the state machine pushed +on to process the next message in the requested selection. + +@return KErrNone if the error has been handled + Completion error code otherwise. +*/ +TInt CImapCompoundCopyFromLocal::ProcessNegativeServerResponse() + { + TInt err = iStatus.Int(); + switch (iCurrentStep) + { + case ESelectDestinationMailboxRO: + case EAppendMessage: + { + if (err == KErrImapNo) + { + err = KErrNotFound; + } + } // fall through + case ESetSource: + case EDeleteLocalMessage: + case ENewSyncFolder: + { + // save the error with the associated message + TRAP_IGNORE(MessageErrorL(iCurrentMsgId, err)); + // Skip to the next message or finish + iNextStep = (iSelectionStillToCopy>0)?ESetSource:EFinished; + break; + } + case ESuspendedForMigrate: + case EFinished: + default: + { + // positive error code not expected, + // self-completed states or no outstanding request. + TImapServerPanic::ImapPanic(TImapServerPanic::ECopyFromLocalCompoundUnexpectedState); + break; + } + } // end of switch (iCurrentStep) + iProgressErrorCode = err; + return KErrNone; + } + +/** +Called to resume the compound operation following a bearer migration. +*/ +void CImapCompoundCopyFromLocal::ResumeOperationL(TRequestStatus& aStatus, CImapSession& aSession) + { + iSession = &aSession; + __LOG_TEXT(iSession->LogId(), "CImapCompoundCopyFromLocal::Resuming"); + __ASSERT_DEBUG(iCurrentStep==ESuspendedForMigrate, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyFromLocalCompoundUnexpectedState)); + iStopForMigrate = EFalse; + + // Switch on next step - some "next steps" require a SELECT first... + switch (iNextStep) + { + case ESelectDestinationMailboxRO: + case EAppendMessage: + case ESetSource: // if stopped for migrate. + { + // just return to the main state machine + CompleteSelf(); + break; + } + case ENewSyncFolder: + { + // re-issue the EXAMINE before kicking off the folder sync + iDestinationFolder->ExamineL(iStatus, *iSession); + iCurrentStep=ESelectDestinationMailboxRO; + SetActive(); + break; + } + case ECheckDestinationMailbox: + case EDeleteLocalMessage: + case EFinished: + // not expected + default: + { + __ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyFromLocalCompoundCancelUnexpectedState)); + // abandon the compound operation + iNextStep=EFinished; + CompleteSelf(); + break; + } + } // end switch (iNextStep) + + Queue(aStatus); + }