diff -r 238255e8b033 -r 84d9eb65b26f email/pop3andsmtpmtm/imapservermtm/src/IMAPCOMP.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/email/pop3andsmtpmtm/imapservermtm/src/IMAPCOMP.CPP Mon May 03 12:29:07 2010 +0300 @@ -0,0 +1,993 @@ +// Copyright (c) 1998-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: +// IMAP4 compound operations +// This class wraps up operations which require more than one IMAP command +// (the imapsess.cpp class deals with single IMAP commands generally), +// allowing increased neatness in the higher classes. +// +// + +#include +#include +#include +#include "impspan.h" +#include "imapsess.h" +#include +#include "imapcomp.h" + +#ifdef _DEBUG +#define LOG_COMMANDS(a) a +#define DBG(a) a +#define PRINTING +#else +#define LOG_COMMANDS(a) +#define DBG(a) +#undef PRINTING +#endif + +// Priority of MsgActive object +const TInt ECompoundPriority=1; + + +// Operations that can be chained +enum + { + EFinished=0, + ESelectSourceMailboxRW, + ESelectSourceMailboxRO, + ESelectDestinationMailboxRW, + ESelectDestinationMailboxRO, + EFetchMessage, + ECopyMessage, + EAppendMessage, + EDeleteMessage, + EDeleteLocalMessage, + EDeleteAllMessages, + ENewSyncFolder, + ESyncFolder, + EInboxDuplicateMove, + EInboxDuplicateCopy, + ECloseFolderWithoutExpunge, + EDeleteFolder, + EStartIdle, + EStopIdle, + ECreate, + ERename, + ESelectInbox + }; + +//DS - Split EInboxDuplicate into EInboxDuplicateCopy and EInboxDuplicateMove to allow +//use of either CMsvServerEntry::CopyL or MoveL depending on what operation the user +//is attempting. + +CImImap4Compound::CImImap4Compound():CMsgActive(ECompoundPriority) + { + __DECLARE_NAME(_S("CImImap4Compound")); + } + +CImImap4Compound::~CImImap4Compound() + { + // We don't delete iSession as we don't own it, we were just passed it to use. + delete iSourceSel; + } + +CImImap4Compound* CImImap4Compound::NewL(CImImap4Session* aSession) + { + CImImap4Compound* self=new (ELeave) CImImap4Compound(); + CleanupStack::PushL(self); + + // Non-trivial constructor + self->ConstructL(aSession); + CleanupStack::Pop(); + return self; + } + +// The non-trivial constructor +void CImImap4Compound::ConstructL(CImImap4Session* aSession) + { + // Save session & entry + iSession=aSession; + + iPopulateCommand=EFalse; + iIdleBeforeFirstPopulate = EFalse; + // We're an active object... + CActiveScheduler::Add(this); + + // Initialise static sequences. There must be a better way + // than this without causing complaints :-( + SeqCopyToLocal[0]=EStopIdle; + SeqCopyToLocal[1]=ESelectSourceMailboxRO; + SeqCopyToLocal[2]=EFetchMessage; + SeqCopyToLocal[3]=EInboxDuplicateCopy; + SeqCopyToLocal[4]=ESelectInbox; + SeqCopyToLocal[5]=EStartIdle; + SeqCopyToLocal[6]=EFinished; + + SeqMoveToLocal[0]=EStopIdle; + SeqMoveToLocal[1]=ESelectSourceMailboxRW; + SeqMoveToLocal[2]=EFetchMessage; + SeqMoveToLocal[3]=EInboxDuplicateMove; + SeqMoveToLocal[4]=EDeleteMessage; + SeqMoveToLocal[5]=ESelectInbox; + SeqMoveToLocal[6]=EStartIdle; + SeqMoveToLocal[7]=EFinished; + + SeqCopyWithinService[0]=EStopIdle; + SeqCopyWithinService[1]=ESelectSourceMailboxRO; + SeqCopyWithinService[2]=ECopyMessage; + SeqCopyWithinService[3]=ESelectDestinationMailboxRO; + SeqCopyWithinService[4]=ENewSyncFolder; + SeqCopyWithinService[5]=ESelectInbox; + SeqCopyWithinService[6]=EStartIdle; + SeqCopyWithinService[7]=EFinished; + + SeqMoveWithinService[0]=EStopIdle; + SeqMoveWithinService[1]=ESelectSourceMailboxRW; + SeqMoveWithinService[2]=ECopyMessage; + SeqMoveWithinService[3]=EDeleteMessage; + SeqMoveWithinService[4]=ESelectDestinationMailboxRO; + SeqMoveWithinService[5]=ENewSyncFolder; + SeqMoveWithinService[6]=ESelectInbox; + SeqMoveWithinService[7]=EStartIdle; + SeqMoveWithinService[8]=EFinished; + + SeqCopyFromLocal[0]=EAppendMessage; + SeqCopyFromLocal[1]=ESelectDestinationMailboxRO; + SeqCopyFromLocal[2]=ENewSyncFolder; + SeqCopyFromLocal[3]=EFinished; + + SeqMoveFromLocal[0]=EStopIdle; + SeqMoveFromLocal[1]=EAppendMessage; + SeqMoveFromLocal[2]=EDeleteLocalMessage; + SeqMoveFromLocal[3]=ESelectDestinationMailboxRO; + SeqMoveFromLocal[4]=ENewSyncFolder; + SeqMoveFromLocal[5]=ESelectInbox; + SeqMoveFromLocal[6]=EStartIdle; + SeqMoveFromLocal[7]=EFinished; + + SeqDelete[0]=EStopIdle; + SeqDelete[1]=ESelectSourceMailboxRW; + SeqDelete[2]=EDeleteMessage; // Explicit expunge + SeqDelete[3]=ESelectInbox; + SeqDelete[4]=EStartIdle; + SeqDelete[5]=EFinished; + + SeqDeleteFolder[0]=EStopIdle; + SeqDeleteFolder[1]=ESelectSourceMailboxRW; + SeqDeleteFolder[2]=EDeleteAllMessages; + SeqDeleteFolder[3]=ECloseFolderWithoutExpunge; + SeqDeleteFolder[4]=EDeleteFolder; + SeqDeleteFolder[5]=ESelectInbox; + SeqDeleteFolder[6]=EStartIdle; + SeqDeleteFolder[7]=EFinished; + + SeqNewSync[0]=EStopIdle; + SeqNewSync[1]=ESelectSourceMailboxRW; + SeqNewSync[2]=ENewSyncFolder; + SeqNewSync[3]=ESelectInbox; + SeqNewSync[4]=EStartIdle; + SeqNewSync[5]=EFinished; + + SeqFullSync[0]=EStopIdle; + SeqFullSync[1]=ESelectSourceMailboxRW; + SeqFullSync[2]=ESyncFolder; + SeqFullSync[3]=ESelectInbox; + SeqFullSync[4]=EStartIdle; + SeqFullSync[5]=EFinished; + + SeqSelect[0]=EStopIdle; + SeqSelect[1]=ESelectSourceMailboxRW; + SeqSelect[2]=EFinished; + + SeqSynchronise[0]=EStopIdle; + SeqSynchronise[1]=ESyncFolder; + SeqSynchronise[2]=ESelectInbox; + SeqSynchronise[3]=EStartIdle; + SeqSynchronise[4]=EFinished; + + SeqCreate[0]=EStopIdle; + SeqCreate[1]=ECreate; + SeqCreate[2]=ESelectInbox; + SeqCreate[3]=EStartIdle; + SeqCreate[4]=EFinished; + + SeqRename[0]=EStopIdle; + SeqRename[1]=ERename; + SeqRename[2]=ESelectInbox; + SeqRename[3]=EStartIdle; + SeqRename[4]=EFinished; + + // operations when done as part of a synchronisation process + SeqSyncCopyToLocal[0]=EFetchMessage; + SeqSyncCopyToLocal[1]=EInboxDuplicateCopy; + SeqSyncCopyToLocal[2]=EFinished; + } + +// Set a new session +void CImImap4Compound::SetSession(CImImap4Session* aSession) + { + iSession=aSession; + } + +// Set entry for access to server's database +void CImImap4Compound::SetEntry(CMsvServerEntry* aEntry) + { + iEntry=aEntry; + } + +// Do setentry, leave if there is an error +void CImImap4Compound::SetEntryL(const TMsvId aId) + { +#ifdef PRINTING + TInt error=iEntry->SetEntry(aId); + if (error) + iSession->LogText(_L8("SetEntryL(%x) returned %d"),aId,error); + User::LeaveIfError(error); +#else + User::LeaveIfError(iEntry->SetEntry(aId)); +#endif + } + + +// Called when async child completes +void CImImap4Compound::DoRunL() + { + DBG((iSession->LogText(_L8("COMPOUND dorunl, step %d, status=%d"),iStep,iStatus.Int()))); + + // Are we still connected? Worth checking... + if (!iSession->Connected()) + { + Complete(KErrDisconnected); + return; + } + + // Any error from last operation? + if (iStep>0 && iStatus.Int()!=KErrNone) + { + switch(iSequence[iStep-1]) + { + // If we get KErrIMAPNO from a selection state, we need to report this as KErrNotFound + case ESelectSourceMailboxRW: + case ESelectSourceMailboxRO: + case ESelectDestinationMailboxRW: + case ESelectDestinationMailboxRO: + case ESelectInbox: + if (iStatus.Int()==KErrIMAPNO) + { + Complete(KErrNotFound); + break; + } + + // Fall through + + default: + // Complete with this error + Complete(iStatus.Int()); + break; + } + + // Reset step (shouldn't really be necessary, but it looks neat!) + iStep=0; + return; + } + + while (!IsActive() && !DoRunLoopL()) + { + // do nothing in the body of this + } + } + +// Called when async child completes +TBool CImImap4Compound::DoRunLoopL() + { + DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): step to execute: %d"), iSequence[iStep]))); + + switch(iSequence[iStep++]) + { + case EFinished: + // All done + DBG((iSession->LogText(_L8("COMPOUND finished")))); + + Complete(KErrNone); + iStep=0; + return ETrue; + + case ESelectSourceMailboxRW: + iSession->Select(iStatus,iSourceFolder,ETrue); + break; + + case ESelectSourceMailboxRO: + iSession->Select(iStatus,iSourceFolder,EFalse); + break; + + case ESelectDestinationMailboxRW: + iSession->Select(iStatus,iDestinationFolder,ETrue); + break; + + case ESelectDestinationMailboxRO: + iSession->Select(iStatus,iDestinationFolder,EFalse); + break; + + case ESelectInbox: + { + // Selecting inbox before starting IDLE command + if (iSession->ImapIdleSupported()==EFalse || iIdleBeforeCommand==EFalse || iIdleBeforeFirstPopulate == EFalse || iMsgCount > 0) + { + return EFalse; + } + + TMsvId inbox = iSession->GetInbox(); + DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): selecting inbox")))); + iSession->Select(iStatus,inbox,ETrue); + break; + } + + case ECreate: + iSession->Create(iStatus,iSource,iLeafName,iFolder); + break; + + case ERename: + iSession->Rename(iStatus,iSource,iLeafName); + break; + + case EFetchMessage: + { + // Don't fetch the message if it is marked for delete + SetEntryL(iSource); + + TMsvEmailEntry entry = static_cast (iEntry->Entry()); + + if (((TMsvEmailEntry)iEntry->Entry()).DisconnectedOperation() == EDisconnectedDeleteOperation) + return EFalse; + + // Don't attempt to fetch the message if it has either been fully or partially downloaded, unless this is a populate command. + if ( entry.Complete() && entry.PartialDownloaded() && !iPopulateCommand ) + return EFalse; + + // We fetch to the mirror in all cases + DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): fetching message")))); + iSession->FetchBody(iStatus,iSource,iGetPartialMailInfo); + + break; + } + + case ECopyMessage: + if (iSequence==SeqCopyWithinService || iSequence==SeqMoveWithinService) + { + if (iSelectionStillToCopy-->0) + { + // Copy all messages before moving onto next step. + iSession->Copy(iStatus,(*iSourceSel)[iSelectionStillToCopy],iDestinationFolder,ETrue); + if (iSelectionStillToCopy>0) + iStep--; // still copying. + } + } + else + iSession->Copy(iStatus,iSource,iDestinationFolder,ETrue); + break; + + case EAppendMessage: + iSession->Append(iStatus,iSource,iDestinationFolder); + break; + + case EDeleteMessage: + // Deletes a message remotely + if (iSequence==SeqMoveWithinService && iSession->CommandFailure()==KErrIMAPNO) + { + DBG((iSession->LogText(_L8("Copy failed, Cancelling Delete")))); + // Copy failed, so do not continue with delete. + return EFalse; + } + + if (iSelectionStillToDelete>1) + iSession->Delete(iStatus,*iSourceSel); + else + iSession->Delete(iStatus,iSource); + iSelectionStillToDelete=0; + break; + + case EDeleteLocalMessage: + // Deletes a message locally: only for messages not within the service + iSession->DeleteMessageL(iSource); + + // As this is an instant operation, loop + return EFalse; + + case EDeleteAllMessages: + // Deletes all messages/folder (must have no subfolders) + iSession->DeleteAllMessagesL(iStatus); + break; + + case EDeleteFolder: + // Delete the folder + iSession->Delete(iStatus,iSourceFolder); + break; + + case ENewSyncFolder: + // New only sync. + + // if the current folder hasn't actually changed then don't + // bother with the Sync + if (!iSession->FolderChanged()) + return EFalse; + + // This used to do just that, new only messages, but it causes a lot of problems + // with sync limits, as for that to work deletes need to be taken into account also. + // This will fix that. + DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): ESyncNewFolder: synchronising")))); + iSession->Synchronise(iStatus,EFalse); + break; + + case ESyncFolder: + // Full sync + DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): ESyncFolder: synchronising")))); + iSession->Synchronise(iStatus,EFalse); + break; + + case ECloseFolderWithoutExpunge: + // Close current folder + iSession->Close(iStatus,EFalse); + break; + + case EInboxDuplicateCopy: + case EInboxDuplicateMove: + { + // SJM: if we asked to fetch to the mirror then we can skip + // this stage + if (iDestinationFolder == KMsvNullIndexEntryId) + { + return EFalse; + } + + // Move the message to the destination (the local inbox) then duplicate it + // back to the original folder for the mirror. + iEntry->SetEntry(iSource); + TMsvId sourcefolder=iEntry->Entry().Parent(); + + // Do the move & copy back structure: we update iSource here as the message + // in the mirror is actually a recreated one with a new TMsvId. We may want + // to delete this (if we're doing a MoveToLocal, for example) and so we need + // the correct TMsvId + +#if 1 + // always copy so that on a move the delete happens on the original correctly + iSession->CopyMessage(iStatus,sourcefolder,iSource,iDestinationFolder, + &iSource,EFalse); +#else + //DS - Added the iSequence[iStep]==EInboxDuplicateMove to represent whether or not + //to remove the original (i.e. copy or move). + iSession->CopyMessage(iStatus,sourcefolder,iSource,iDestinationFolder, + &iSource,iSequence[iStep-1]==EInboxDuplicateMove); +#endif + break; + } + + case EStartIdle: + // if there are more messages(iMsgCount) to populate don't go to IDLE state. + if (iSession->ImapIdleSupported()==EFalse || iIdleBeforeCommand==EFalse || iIdleBeforeFirstPopulate == EFalse || iMsgCount > 0) + { + return EFalse; + } + DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): EStartIdle: calling StartIdle()")))); + iIdleBeforeFirstPopulate = EFalse; + iSession->StartIdle(iStatus); + break; + + case EStopIdle: + if (iSession->ImapIdleSupported()==EFalse || iSession->IsIdling()==EFalse) + { + DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): EStopIdle: not idling or waitng for idle")))); + iIdleBeforeCommand = EFalse; + + // If last message being fetched , then should start IDLE after that. + if (iMsgCount == 1 ) + { + iIdleBeforeCommand = ETrue; + } + + return EFalse; + } + + iIdleBeforeFirstPopulate = ETrue;//Are we "IDLE" before first populate.. + iIdleBeforeCommand = ETrue; + DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): EStopIdle: Calling StopIdle()")))); + iSession->StopIdle(iStatus); + break; + + default: + gPanic(EUnknownState); + return ETrue; + } + + // Next step in sequence... + DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): Setting active")))); + SetActive(); + return EFalse; + } + +// Called when parent wants to cancel us +void CImImap4Compound::DoCancel() + { + DBG((iSession->LogText(_L8("CImImap4Compound::DoCancel()")))); + + // Cancel any session object we're using + switch( iSequence[iStep-1] ) + { + case EStopIdle: + case ESelectSourceMailboxRO: + case EFetchMessage: + case EInboxDuplicateCopy: + case ESelectInbox: + case EStartIdle: + { + TRAP_IGNORE(iSession->CancelAndIdleL(iIdleBeforeFirstPopulate)); + } break; + + default: + iSession->Cancel(); + } + + iIdleBeforeFirstPopulate = EFalse; + iMsgCount = 0; + // ...and parent + CMsgActive::DoCancel(); + } + +// Store an offline operation in the correct place +TMsvId CImImap4Compound::FindFolderL(const TMsvId aMessage) + { + DBG((iSession->LogText(_L8("FindFolderL(%x)"),aMessage))); + + // Find folder that encloses this message (has Mailbox flag set), or service, + // whichever we find first + SetEntryL(aMessage); + TMsvEmailEntry entry; + do + { + // Visit this entry + SetEntryL(iEntry->Entry().Parent()); + entry=iEntry->Entry(); + + DBG((iSession->LogText(_L8(" 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(iEntry->Entry().iType!=KUidMsvServiceEntry && entry.Id()!=KMsvRootIndexEntryId); + + DBG((iSession->LogText(_L8(" Failed")))); + + return(NULL); + } + +void CImImap4Compound::GenericCopyL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination, TInt* aSequence) + { + DBG((iSession->LogText(_L8("CImImap4Compound::GenericCopyL()")))); + Queue(aStatus); + + // Save parameters + iSource=aSource; + iDestinationFolder=aDestination; + iSourceFolder=FindFolderL(iSource); + iMessageSelection=iSelectionStillToCopy=iSelectionStillToDelete=-1; + + // Find the offending source folder + if (iSourceFolder == NULL && + aSequence != SeqMoveFromLocal && aSequence != SeqCopyFromLocal) + { + Complete(KErrNotFound); + return; + } + + // Select it + iStep=0; + iSequence=aSequence; + DoRunL(); + } + +void CImImap4Compound::GenericCopyL(TRequestStatus& aStatus, const CMsvEntrySelection& aSourceSel, const TMsvId aDestination, TInt* aSequence) + { + DBG((iSession->LogText(_L8("CImImap4Compound::GenericCopyL()")))); + Queue(aStatus); + + // Save parameters + iSource=aSourceSel[0]; + delete iSourceSel; + iSourceSel = NULL; + iSourceSel=aSourceSel.CopyL(); + iDestinationFolder=aDestination; + iMessageSelection=iSelectionStillToCopy=iSelectionStillToDelete=aSourceSel.Count(); + + // Check that selection elements are contiguous. Just call Copy on contiguous selections. + + iSourceFolder=FindFolderL((*iSourceSel)[iSelectionStillToCopy-1]); + + // Find the offending source folder + if (iSourceFolder == NULL && + aSequence != SeqMoveFromLocal && aSequence != SeqCopyFromLocal) + { + Complete(KErrNotFound); + return; + } + + // Select it + iStep=0; + iSequence=aSequence; + DoRunL(); + } + +// CopyToLocal +void CImImap4Compound::CopyToLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND CopyToLocal(%x to %x)"),aSource,aDestination))); + + iPopulateCommand=EFalse; + + UpdatePartialMailInfoToDefaults(aDestination); + + // Kick off the copy + GenericCopyL(aStatus,aSource,aDestination,SeqCopyToLocal); + } + +void CImImap4Compound::PopulateL(TRequestStatus& aStatus, const TMsvId aSource, TImImap4GetPartialMailInfo aGetPartialMailInfo) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Populate(%x,%d)"),aSource,aGetPartialMailInfo.iGetMailBodyParts))); + + iPopulateCommand = ETrue; + // Set options and kick off the copy to ourselves + iGetPartialMailInfo = aGetPartialMailInfo; + GenericCopyL(aStatus,aSource,KMsvNullIndexEntryId,SeqCopyToLocal); + + if(iMsgCount > 0) + { + iMsgCount--; + } + + } + +// MoveToLocal +void CImImap4Compound::MoveToLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND MoveToLocal(%x to %x)"),aSource,aDestination))); + + + //Partial populate option is implemented only for the populate command. moving a partially + //populated message will delete the unpopulated message from the remote server. UI takes care + // of notifying this and ask for confirmation whether user still wants to move the message. + + iPopulateCommand=EFalse; + + UpdatePartialMailInfoToDefaults(aDestination); + + // We can't do a MoveToLocal if the destination is in the service: this possibility + // if filtered out by the things calling us, so we don't have to worry about it here. + // We know the destination is therefore a local folder. + GenericCopyL(aStatus,aSource,aDestination,SeqMoveToLocal); + } + +// CopyWithinService +void CImImap4Compound::CopyWithinServiceL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND CopyWithinService(%x to %x)"),aSource,aDestination))); + + GenericCopyL(aStatus,aSource,aDestination,SeqCopyWithinService); + } + +void CImImap4Compound::CopyWithinServiceL(TRequestStatus& aStatus, const CMsvEntrySelection& aSourceSel, const TMsvId aDestination) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND CopyWithinService(to %x)"),aDestination))); + + GenericCopyL(aStatus,aSourceSel,aDestination,SeqCopyWithinService); + } + +// MoveWithinService +void CImImap4Compound::MoveWithinServiceL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND MoveWithinService(%x to %x)"),aSource,aDestination))); + + GenericCopyL(aStatus,aSource,aDestination,SeqMoveWithinService); + } + +void CImImap4Compound::MoveWithinServiceL(TRequestStatus& aStatus, const CMsvEntrySelection& aSourceSel, const TMsvId aDestination) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND MoveWithinService(to %x)"),aDestination))); + + GenericCopyL(aStatus,aSourceSel,aDestination,SeqMoveWithinService); + } + +// CopyFromLocal +void CImImap4Compound::CopyFromLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND CopyFromLocal(%x to %x)"),aSource,aDestination))); + + GenericCopyL(aStatus,aSource,aDestination,SeqCopyFromLocal); + } + +// MoveFromLocal +void CImImap4Compound::MoveFromLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND MoveFromLocal(%x to %x)"),aSource,aDestination))); + + GenericCopyL(aStatus,aSource,aDestination,SeqMoveFromLocal); + } + +// SyncCopyToLocal +void CImImap4Compound::SyncCopyToLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND SyncCopyToLocal(%x to %x)"),aSource,aDestination))); + + iPopulateCommand=EFalse; + + UpdatePartialMailInfoToDefaults(aDestination); + + // Kick off the copy + GenericCopyL(aStatus,aSource,aDestination,SeqSyncCopyToLocal); + } + +// Delete +void CImImap4Compound::DeleteL(TRequestStatus& aStatus, const TMsvId aSource) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Delete(%x)"),aSource))); + + Queue(aStatus); + + // Save parameters + iSource=aSource; + iMessageSelection=iSelectionStillToDelete=1; + + // Find the offending source folder + if ((iSourceFolder=FindFolderL(iSource))==NULL) + { + Complete(KErrNotFound); + return; + } + + // Select it + iStep=0; + iSequence=SeqDelete; + DoRunL(); + } + +// Delete +void CImImap4Compound::DeleteL(TRequestStatus& aStatus, const CMsvEntrySelection& aSourceSel) + { + LOG_COMMANDS( (iSession->LogText(_L8("COMPOUND Delete selection")))); + + Queue(aStatus); + + // Save parameters + iSource=aSourceSel[0]; + delete iSourceSel; + iSourceSel = NULL; + iSourceSel=aSourceSel.CopyL(); + iMessageSelection=iSelectionStillToDelete=aSourceSel.Count(); + + // Find the offending source folder + if ((iSourceFolder=FindFolderL(iSource))==NULL) + { + Complete(KErrNotFound); + return; + } + + // Select it + iStep=0; + iSequence=SeqDelete; + DoRunL(); + } + +// Delete all in folder, then folder itself +void CImImap4Compound::DeleteFolderL(TRequestStatus& aStatus, const TMsvId aSource) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND DeleteFolder(%x)"),aSource))); + + Queue(aStatus); + + // Save parameters + iSourceFolder=aSource; + iSequence=SeqDeleteFolder; + + // The folder might be a mailbox (in which case it needs selecting, messages + // deleting, closing, then deletion of the folder) or it might be a \Noselect + // folder, which we just delete. + User::LeaveIfError(iEntry->SetEntry(aSource)); + TMsvEmailEntry folder=iEntry->Entry(); + if (!folder.Mailbox()) + { + DBG((iSession->LogText(_L8("Folder is marked \\NoSelect: just delete it")))); + + // Skip the first few steps + iStep=2; + } + else + { + DBG((iSession->LogText(_L8("Folder is a mailbox: deleting messages and folder")))); + + // Start from folder selection + iStep=0; + } + + DoRunL(); + } + +void CImImap4Compound::CreateL(TRequestStatus& aStatus, const TMsvId aParent, const TDesC& aLeafName, const TBool aFolder) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Create(%x)"),aParent))); + + Queue(aStatus); + + iStep=0; + iSequence=SeqCreate; + iSource=aParent; + iLeafName=aLeafName; + iFolder=aFolder; + DoRunL(); + } + +void CImImap4Compound::RenameL(TRequestStatus& aStatus, const TMsvId aTarget, const TDesC& aNewName) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Rename(%x)"),aTarget))); + + Queue(aStatus); + + iStep=0; + iSequence=SeqRename; + iSource=aTarget; + iLeafName=aNewName; + DoRunL(); + } + +void CImImap4Compound::SynchroniseL(TRequestStatus& aStatus) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Synchronise")))); + + Queue(aStatus); + + iStep=0; + iSequence=SeqSynchronise; + DoRunL(); + } + +void CImImap4Compound::SelectL(TRequestStatus& aStatus, const TMsvId aFolder) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Select(%x)"),aFolder))); + + Queue(aStatus); + + iStep=0; + iSequence=SeqSelect; + iSourceFolder=aFolder; + DoRunL(); + } + +void CImImap4Compound::NewOnlySyncL(TRequestStatus& aStatus, const TMsvId aFolder) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND NewOnlySync(%x)"),aFolder))); + + Queue(aStatus); + + if (iSession->ImapIdleSupported()) + { + // Igmore sync as Imap Idle is supported + Complete(KErrNone); + return; + } + + // Check folder is a mailbox + User::LeaveIfError(iEntry->SetEntry(aFolder)); + TMsvEmailEntry mbcheck=iEntry->Entry(); + if (!mbcheck.Mailbox()) + { + // Not a mailbox, so we can't sync it + Complete(KErrNotSupported); + return; + } + + // Select it + iStep=0; + iSequence=SeqNewSync; + iSourceFolder=aFolder; + DoRunL(); + } + +void CImImap4Compound::FullSyncL(TRequestStatus& aStatus, const TMsvId aFolder) + { + LOG_COMMANDS((iSession->LogText(_L8("COMPOUND FullSync(%x)"),aFolder))); + + Queue(aStatus); + + // Check folder is a mailbox + User::LeaveIfError(iEntry->SetEntry(aFolder)); + TMsvEmailEntry mbcheck=iEntry->Entry(); + if (!mbcheck.Mailbox()) + { + do + { + // Ensure visibility + if (!mbcheck.Visible()) + { + mbcheck.SetVisible(ETrue); + User::LeaveIfError(iEntry->ChangeEntryBulk(mbcheck)); + } + + // Move up one + User::LeaveIfError(iEntry->SetEntry(mbcheck.Parent())); + mbcheck=iEntry->Entry(); + } + while(mbcheck.iType!=KUidMsvServiceEntry && mbcheck.Id()!=KMsvRootIndexEntryId); + + // Not a mailbox, so we can't sync it + Complete(KErrNone); + return; + } + + // Select it + iStep=0; + iSequence=SeqFullSync; + iSourceFolder=aFolder; + DoRunL(); + } + +// Report progress +TImap4GenericProgress CImImap4Compound::Progress() + { + // First, ask session (updates byte counts & stuff) + TImap4GenericProgress progress=iSession->Progress(); + if (iSequence==SeqDelete || iSequence==SeqCopyWithinService) + { + progress.iMsgsToDo=iMessageSelection; + progress.iMsgsDone=iMessageSelection-iSelectionStillToCopy; + } + else if (iSequence==SeqMoveWithinService) + { + // DEL done in one go in imapsess, + // just have progress for the COPY part of the MOVE command. + progress.iMsgsToDo=iMessageSelection; + progress.iMsgsDone=iMessageSelection-iSelectionStillToCopy; + } + + // don't believe there's any point in modifying the operation + // since it'll be set correctly in the Mtm handler. +#if 0 + // Now, overlay our current operation (move or copy, at least) + if (iSequence==SeqCopyToLocal || iSequence==SeqCopyWithinService || + iSequence==SeqCopyFromLocal) + progress.iOperation=TImap4Progress::ECopying; + else if (iSequence==SeqMoveToLocal || iSequence==SeqMoveWithinService || + iSequence==SeqMoveFromLocal) + progress.iOperation=TImap4Progress::EMoving; +#endif + + // Return the modified progress + return(progress); + } + +void CImImap4Compound::UpdatePartialMailInfoToDefaults(TMsvId aDestination) + { + iGetPartialMailInfo.iTotalSizeLimit= KMaxTInt; + iGetPartialMailInfo.iBodyTextSizeLimit = KMaxTInt; + iGetPartialMailInfo.iAttachmentSizeLimit = KMaxTInt; + iGetPartialMailInfo.iGetMailBodyParts = EGetImap4EmailBodyTextAndAttachments; + iGetPartialMailInfo.iPartialMailOptions=ENoSizeLimits; + iGetPartialMailInfo.iDestinationFolder=aDestination; + } + +void CImImap4Compound::SetMessageCount(const TInt aCount) + { + iMsgCount = aCount; + }