diff -r 6a20128ce557 -r ebfee66fde93 email/imap4mtm/imapprotocolcontroller/src/cimapcompoundbase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/email/imap4mtm/imapprotocolcontroller/src/cimapcompoundbase.cpp Fri Jun 04 10:25:39 2010 +0100 @@ -0,0 +1,381 @@ +// 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: +// cimapcompoundbase.cpp +// + +#include "cimapcompoundbase.h" +#include "cimapsession.h" +#include "cimapsettings.h" +#include "cimapsessionconsts.h" +#include "cimaplogger.h" +#include "imappaniccodes.h" + +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include "timrfc822datefield.h" +#endif + +CImapCompoundBase::CImapCompoundBase( CImapSyncManager& aSyncManager, + CMsvServerEntry& aServerEntry, + CImapSettings& aImapSettings) : + CMsgActive(EPriorityStandard ), + iSyncManager(aSyncManager), + iServerEntry(aServerEntry), + iImapSettings(aImapSettings), + iStopForMigrate(EFalse), + iCancelForMigrate(EFalse), + iProgressState(TImap4GenericProgress::EIdle), + iSyncProgressState(TImap4SyncProgress::EIdle) + { + + } + +CImapCompoundBase::~CImapCompoundBase( ) + { + } + +#ifdef __IMAP_LOGGING +void CImapCompoundBase::DoComplete(TInt& aErr) +#else +void CImapCompoundBase::DoComplete(TInt& /*aErr*/) +#endif //_IMAP_LOGGING + { + __LOG_FORMAT((iSession->LogId(), "CImapCompoundBase::DoComplete(aErr = %d) CurrentStep = %d", aErr, iCurrentStep)); + } + +/** +Called when asynchronous service requests complete. +Handles errors returned by aSynchronous services. + +The state machine for derived compound commands is managed by +the pure-virtual DoRunLoopL() which is called by DoRunL(). + +This form of DoRunL also allows synchronous steps to be performed +sequentially. +*/ +void CImapCompoundBase::DoRunL() + { + // Handle any server errors + if (iStatus.Int()!=KErrNone) + { + if (TInt err=ProcessSessionError() != KErrNone) + { + Complete(err); + return; + } + } + + // Operation state machine handled by DoRunLoopL() + while (!IsActive() && !DoRunLoopL()) + { + // do nothing in the body of this + } + } + + +/** +Base class method for handling errors returned by the session. +Called on completion of an asynchronous request on the IMAP session, +ie at the start of the DoRunL() method. If this method returns +a value other than KErrNone, the compound operation should complete +with the return value as the error code. + +This will catch any positive error codes returned by the imap +session These indicate either NO/BAD server responses or a more +serious error has occurred, for example a disconnect, or corrupt +data received from the remote server. + +NO/BAD server responses are handled by the derived compound +operation classes (these are non-fatal errors, an attempt is +made to continue the requested operation) + +Other errors are more serious - these are passed up to the +Protocol Controller to deal with. + +@return KErrNone if the error has been handled, + otherwise the positive error code as returned by + the IMAP session. +*/ +TInt CImapCompoundBase::ProcessSessionError() + { + TInt errCode = iStatus.Int(); + if (errCode==KErrImapNo || errCode==KErrImapBad) + { + return ProcessNegativeServerResponse(); + } + else + { + return errCode; + } + } + +/** +Checks the input selection for entries of specified types. +In this context, "Messages" means complete messages, not RFC888 +parts of another message. "parts" means attachment or text bodies. + +@param aSelection - original list of message entry ids +@param aLocalCopy - filtered copy of message entry ids. +@param aMessages - accept entries of type KUidMsvMessageEntry +@param aParts - accept entries of type KUidMsvEmailTextEntry, + KUidMsvAttachmentEntry, + KUidMsvMessageEntry + KUidMsvEmailHtmlEntry + KUidMsvEmailExternalBodyEntry + KUidMsvEmailRtfEntry +@param aFolders - accept entries of type KUidMsvFolderEntry +@param aIsInService - only accept entries under the IMAP service entry + +@return KErrNotSupported if no valid entries, + KErrNone otherwise +*/ +TInt CImapCompoundBase::CheckSelectionL(const CMsvEntrySelection& aSelection, + CMsvEntrySelection* aLocalCopy, + const TBool aMessages, + const TBool aParts, + const TBool aFolders, + const TBool aIsInService) + { + // reset the local copy + aLocalCopy->Reset(); + + // get the service ID + TMsvId serviceId = iImapSettings.ServiceId(); + + // Check all entries are messages + for(TInt a=0;aAppendL(aSelection[a]); + } +#ifdef _DEBUG + // UI shouldn't really be giving us bogus items so panic + else + { + TImapServerPanic::ImapPanic(TImapServerPanic::EInvalidMsvTypeToCommand); + } +#endif + } + + // Anything to do? + if (!aLocalCopy->Count()) + { + // Nothing valid to work with + return(KErrNotSupported); + } + else + { + // All OK, the selection isn't empty + return(KErrNone); + } + } + +/** +Sums the total size of messages to be copied or moved + +@param aSelection - selection of messages to be processed +@return TInt - the total size of the messages in the selection +*/ +TInt CImapCompoundBase::CalculateDownloadSizeL(const CMsvEntrySelection& aSelection) + { + TInt totalSize = 0; + + // Do a quick tally on the size of messages which are to be copied / moved. + TInt count=aSelection.Count(); + while (count--) + { + SetEntryL(aSelection.At(count)); + // Only add the size up if the message is not complete. + if(!iServerEntry.Entry().Complete()) + { + totalSize += iServerEntry.Entry().iSize; + } + } + return totalSize; + } + +/** +Find the folder that contains specified message + +@param aMessage - selection of messages to be processed +@return TMsvId - the parent folder of aMessage, or the service ID. +*/ +TMsvId CImapCompoundBase::FindFolderL(const TMsvId aMessage) + { + __LOG_FORMAT((iSession->LogId(), "CImapCompoundBase::FindFolderL(%d)", aMessage)); + + // Find folder that encloses this message (has Mailbox flag set), or service, + // whichever we find first + SetEntryL(aMessage); + TMsvEmailEntry entry; + do + { + // Change context to parent of current entry + SetEntryL(iServerEntry.Entry().Parent()); + entry=iServerEntry.Entry(); + + __LOG_FORMAT((iSession->LogId(), " At %x, type=%x, mailbox=%d", entry.Id(),entry.iType,entry.Mailbox())); + + // A folder & a mailbox, or a service? + if (entry.iType==KUidMsvFolderEntry && entry.Mailbox()) + { + // This'll do! + return(entry.Id()); + } + } + while(iServerEntry.Entry().iType!=KUidMsvServiceEntry && entry.Id()!=KMsvRootIndexEntryId); + + __LOG_TEXT(iSession->LogId(), " FindFolderL() Failed"); + + return(NULL); + } + +// Do setentry, leave if there is an error +void CImapCompoundBase::SetEntryL(const TMsvId aId) + { + User::LeaveIfError(iServerEntry.SetEntry(aId)); + } + +/** +Self completes to allow RunL to be called. +*/ +void CImapCompoundBase::CompleteSelf() + { + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + } + + +void CImapCompoundBase::SetCurrentStep() + { + iCurrentStep = iNextStep; + } + +/** +Save error code in a message + +@param aMessgeId +@param aError +*/ +void CImapCompoundBase::MessageErrorL(const TMsvId aMessageId, const TInt aError) + { + // Save error code: if we can't access this entry, then it's probably something to do + // with the error we're trying to report: ignore it silently + if (iServerEntry.SetEntry(aMessageId)==KErrNone) + { + TMsvEntry entry=iServerEntry.Entry(); + + // Save unnecessary writes... + if (entry.iError!=aError) + { + entry.iError=aError; + User::LeaveIfError(iServerEntry.ChangeEntry(entry)); + } + } + } + +/** +Cancels outstanding service request, and recovers the compound operation +object to a state in which the operation may be restarted following migration +to a new carrier. +The operation will be restarted by a call to ResumeOperationL(). + +Derived classes must implement a DoCancel that sets iNextStep to the step +that should be performed following the migration, when ReumeOperationL is called; +*/ +void CImapCompoundBase::CancelForMigrate() + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundBase::CancelForMigrate()"); + iCancelForMigrate = ETrue; + Cancel(); + iCancelForMigrate = EFalse; + // Mark Operation as suspended. + iCurrentStep = ESuspendedForMigrate; + } + +/** +Indicates that the compound operation should complete as soon as it is possible +for the operation to be re-started without requiring a significant amount of +repeated communication. +The operation will be restarted by a call to ResumeOperationL() +*/ +void CImapCompoundBase::StopForMigrate() + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundBase::StopForMigrate()"); + iStopForMigrate = ETrue; + } + +/** +Returns ETrue if the compound operation has been suspended (stopped/cancelled). +This would occur in the case of a bearer migration. +*/ +TBool CImapCompoundBase::Suspended() + { + if (iCurrentStep == ESuspendedForMigrate) + { + return ETrue; + } + return EFalse; + } +