diff -r 000000000000 -r 72b543305e3a email/pop3andsmtpmtm/popservermtm/src/POPSOFFL.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/email/pop3andsmtpmtm/popservermtm/src/POPSOFFL.CPP Thu Dec 17 08:44:11 2009 +0200 @@ -0,0 +1,1024 @@ + +// Copyright (c) 2007-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 +#include +#include "POPSOFFL.H" +#include "popstran.h" +#include "POPS.PAN" + +// API +// === +// The CImPop3OfflineOperationFinder class is used to find and order offline +// operations. It can also be used to obtain progress information eg. the +// number of operations queued of a particular type. + +// Offline operations are retrieved by first calling the asynchronous +// FindFirstL function. After completetion call the OperationFound function +// to find out whether or not an offline operation has been found, if it has +// then the OfflineOperation function should be called to retrive it. +// +// The FindNextL function should be called to find other offline operations +// (in conjunction with the OperationFound and OfflineOperations functions.) +// It should be noted that the FindNextL function is synchronous. + +// The DeleteCurrentOperationL() function deletes the current entry from the +// message store. + +// OperationDetails returns TOperationDetails which can be used for providing +// progress information. + + +// Implementaiton +// ============== +// The asynchronous FindFirstL function builds up a list of +// CImOffLineOperationArray objects, each array holds a list of operations +// of a particular type. + +// The operations are stored this way to facilitate easy ordering based on +// operation type as well as being useful for generating progress +// information. + +// The operations are retrieved by first visiting each message under the +// service, this potentially slow operation is handled by the asynchronous +// function. + +CImPop3OfflineOperationFinder* CImPop3OfflineOperationFinder::NewL(CMsvServerEntry& aEntry) + { + CImPop3OfflineOperationFinder* self = NewLC(aEntry); + CleanupStack::Pop(); // self + return self; + } + +CImPop3OfflineOperationFinder* CImPop3OfflineOperationFinder::NewLC(CMsvServerEntry& aEntry) + { + CImPop3OfflineOperationFinder* self = new (ELeave) CImPop3OfflineOperationFinder(aEntry); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +void CImPop3OfflineOperationFinder::FindFirstL(TMsvId aServiceId, TBool aQuitting, TRequestStatus &aStatus) +// Asynchronous function for finding all the offline operations and setting +// the current operation (iOperationArrayIndex and iOperationIndex) to point +// to the first one. + +// Use OperationFound(), OfflineOperation() and OperationDetails() to access +// the results of this search. + { + TInt index = 0; + // Delete each of the CImOffLineOperationArrays + while (index < iOfflineOperations->Count()) + { + delete (*iOfflineOperations)[index]; + index++; + } + iOfflineOperations->Reset(); + + iServiceId = aServiceId; + iState = EPopsOffOpLookingForMessages; + iQuitting = aQuitting; + + if (iChildMessages) + { + delete iChildMessages; + iChildMessages = 0; + } + + iChildMessages = new (ELeave) CMsvEntrySelection(); + + User::LeaveIfError(iEntry.GetChildren(*iChildMessages)); + iMessageIndex = 0; + Queue(aStatus); + if (iChildMessages->Count()) + { + // Check the first message for offline operations. + CheckNextChildMessageL(); + } + else + { + // There are no messages found so complete and stop searching here. + delete iChildMessages; + iChildMessages = 0; + Complete(KErrNone); + } + } + +void CImPop3OfflineOperationFinder::CheckNextChildMessageL() +// Check the current message (iMessageIndex) and append any offline operations +// to the offline operations list. + { + if (iMessageIndex < iChildMessages->Count()) + { + iEntry.SetEntry((*iChildMessages)[iMessageIndex]); + TMsvEmailEntry entry = iEntry.Entry(); + if (entry.DisconnectedOperation() != ENoDisconnectedOperations) + // If the entry has offline operations queued then add it to the list. + { + AppendOfflineOpsL(); + } + } + + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + } + +void CImPop3OfflineOperationFinder::AppendOfflineOpsL() +// This private help function appends the offline operations associated with the +// current message to the appropriate offline operations array. +// The array to which it is added depends on the operation type. If there +// is currently no array for this operation type then one is created. + { + // Get the offline operations for the current message. + CImOffLineOperationArray* localOfflineOpArray = CImOffLineOperationArray::NewL(); + CleanupStack::PushL(localOfflineOpArray); + CImOffLineArrayStore* offlineArrayStore = new (ELeave) CImOffLineArrayStore(*localOfflineOpArray); + CleanupStack::PushL(offlineArrayStore); + CMsvStore* messageStore = iEntry.ReadStoreL(); + CleanupStack::PushL(messageStore); + offlineArrayStore->RestoreL(*messageStore); + + // Append the local offline operations to the correct operations list. + TInt opCounter; + TInt offlineOps = localOfflineOpArray->CountOperations(); + const CImOffLineOperation* newOperation; + for (opCounter = 0; opCounter < offlineOps; opCounter++) + { + newOperation = &localOfflineOpArray->Operation(opCounter); + // Append newOperation to the correct list as each list holds a different operation type. + + // Find the appropriate offline operation list. + CImOffLineOperationArray* operationArray = 0; + if (iOfflineOperations->Count() == 0) + { + // If there are no arrays then create the first one. + operationArray = CImOffLineOperationArray::NewL(); + CleanupStack::PushL(operationArray); + iOfflineOperations->AppendL(operationArray, sizeof(void*)); + CleanupStack::Pop(operationArray); + } + else + { + TBool found = EFalse; + TInt index = 0; + // Search the different arrays for one that contains the correct operation types. + while ((!found) && (index < iOfflineOperations->Count())) + { + if ((*iOfflineOperations)[index]->CountOperations()) + { + if (((*iOfflineOperations)[index]->Operation(0)).OpType() == newOperation->OpType()) + { + found = ETrue; + operationArray = (*iOfflineOperations)[index]; + } + } + index++; + } + + if (!found) + { + // If there are no appropriate arrays then create a new one. + operationArray = CImOffLineOperationArray::NewL(); + CleanupStack::PushL(operationArray); + iOfflineOperations->AppendL(operationArray, sizeof(void*)); + CleanupStack::Pop(operationArray); + } + } + + operationArray->AppendOperationL(*newOperation); + } + + CleanupStack::PopAndDestroy(3); // offlineArrayStore, messageStore, localOfflineOperationArray + } + + +TBool CImPop3OfflineOperationFinder::AppropriateOperation(const CImOffLineOperation& aOperation) const + { +// Returns true if the operation should be run at this point. +// Delete operations should be run at the end of the session, all others at the start. + return (aOperation.OpType()==CImOffLineOperation::EOffLineOpDelete) ? iQuitting : (!iQuitting); + } + + +void CImPop3OfflineOperationFinder::FindNext() +// Finds the next offline operations. +// The results of this function call are valid as soon as the function returns. + { + TBool go = ETrue; + + CImOffLineOperationArray* operationArray = 0; + iOperationIndex++; + while (go) + { + go = ETrue; + + if (iOfflineOperations->Count()) + { + operationArray = (*iOfflineOperations)[iOperationArrayIndex]; + } + else + { + operationArray = 0; + } + + if (operationArray == 0) + { + go = EFalse; + } + else if (iOperationIndex == operationArray->CountOperations()) + // If there are no more operations in this array then move on to the next one. + { + iOperationArrayIndex++; + iOperationIndex = 0; + } + else if (!AppropriateOperation(operationArray->Operation(0))) + // If the operations in this array aren't of an appropriate type then move on to the next one. + { + iOperationArrayIndex++; + iOperationIndex = 0; + } + else + // An appropriate operation has been found. + { + go = EFalse; + } + + if (iOperationArrayIndex == iOfflineOperations->Count()) + // If there are no more operation arrays then don't carry on looking. + { + go = EFalse; + } + } + + // Set the operaitons details for later. + if (OperationFound()) + { + iOperationDetails.iOpType = OfflineOperation().OpType(); + iOperationDetails.iOperationNumber = iOperationIndex; + iOperationDetails.iOperationsOfType = ((*iOfflineOperations)[iOperationArrayIndex])->CountOperations(); + } + else + { + iOperationDetails.iOpType = CImOffLineOperation::EOffLineOpNone; + } + } + +TBool CImPop3OfflineOperationFinder::OperationFound() const +// Returns true if an operation has been found. + { + return (iOperationArrayIndex < (iOfflineOperations->Count())); + } + +const CImOffLineOperation& CImPop3OfflineOperationFinder::OfflineOperation() const +// Returns the current offline operations. + { + return ((*iOfflineOperations)[iOperationArrayIndex])->Operation(iOperationIndex); + } + +const CImPop3OfflineOperationFinder::TOperationDetails& CImPop3OfflineOperationFinder::OperationDetails() const +// Returns the details for the current operation. + { + return iOperationDetails; + } + +CImPop3OfflineOperationFinder::~CImPop3OfflineOperationFinder() + { + delete iChildMessages; + TInt index = 0; + if (iOfflineOperations) + { + // Delete each of the CImOffLineOperationArrays + while (index < iOfflineOperations->Count()) + { + delete (*iOfflineOperations)[index]; + index++; + } + delete iOfflineOperations; + } + } + +void CImPop3OfflineOperationFinder::DoRunL() + { + ++iMessageIndex; + if (iMessageIndex < iChildMessages->Count()) + // If there are more messages then check them for offline operations. + { + CheckNextChildMessageL(); + } + else + // If there are no more messages then go back and find all the offline operations. + { + delete iChildMessages; + iChildMessages = 0; + + // Move the offline copy opertion array to the front of the list. + TInt index = 0; + TBool go = ETrue; + while ((index < iOfflineOperations->Count()) + && go) + { + CImOffLineOperation::TOffLineOpType opType = ((*iOfflineOperations)[index]->Operation(0)).OpType(); + if (opType == CImOffLineOperation::EOffLineOpCopyToLocal) + { + // Move the offline copy operation array to the front of the list. + go = EFalse; + CImOffLineOperationArray* populateOperationList = (*iOfflineOperations)[index]; + iOfflineOperations->Delete(index); + iOfflineOperations->InsertL(index, populateOperationList, sizeof(void*)); + } + else + { + index++; + } + } + + // Move the offline populate opertion array to the front of the list. + index = 0; + go = ETrue; + while ((index < iOfflineOperations->Count()) + && go) + { + CImOffLineOperation::TOffLineOpType opType = ((*iOfflineOperations)[index]->Operation(0)).OpType(); + if (opType == CImOffLineOperation::EOffLineOpCopyWithinService) + { + // Move the offline populate operation array to the front of the list. + go = EFalse; + CImOffLineOperationArray* populateOperationList = (*iOfflineOperations)[index]; + iOfflineOperations->Delete(index); + iOfflineOperations->InsertL(index, populateOperationList, sizeof(void*)); + } + else + { + index++; + } + } + + // Set the iOperationIndex to the first appropriate operation. + iOperationArrayIndex = 0; + iOperationIndex = -1; + FindNext(); + + Complete(KErrNone); + } + } + +void CImPop3OfflineOperationFinder::DoCancel() + { + CMsgActive::DoCancel(); + } + +void CImPop3OfflineOperationFinder::DoComplete() + { + + } + +void CImPop3OfflineOperationFinder::ConstructL() + { + CActiveScheduler::Add(this); + iOfflineOperations = new (ELeave) CArrayVarFlat(3); + } + +CImPop3OfflineOperationFinder::CImPop3OfflineOperationFinder(CMsvServerEntry& aEntry) : CMsgActive(EPriorityStandard), iEntry(aEntry) + { + + } + + + + + + +// API +// === +// The CImPop3SetOfflineOps class provides a means of asynchronously adding +// offline operations to the message stores of the appropriate messages. + +// Use the AddOfflineOperationL to add the offline operations. + + +CImPop3SetOfflineOps* CImPop3SetOfflineOps::NewL(CMsvServerEntry& aEntry) + { + CImPop3SetOfflineOps* self = NewLC(aEntry); + CleanupStack::Pop(); // self + return self; + } + +CImPop3SetOfflineOps* CImPop3SetOfflineOps::NewLC(CMsvServerEntry& aEntry) + { + CImPop3SetOfflineOps* self = new (ELeave) CImPop3SetOfflineOps(aEntry); + CleanupStack::PushL(self); + self->ConstructL(); + CActiveScheduler::Add(self); + // ConstructL(); + return self; + } + +void CImPop3SetOfflineOps::AddOfflineOperationL(const CMsvEntrySelection *aMessageSelection, + CImOffLineOperation::TOffLineOpType aOperationType, + TMsvId aTargetFolderId, + TRequestStatus& aStatus) +// Adds the aOperationType operation to each message in aMessageSelection. +// The aTargetFolderId is not used for some operation types, eg. deleting. + { + iState = EAddingOfflineOperations; + + iMessageCounter = 0; + iOperationType = aOperationType; + iDestinationEntryId = aTargetFolderId; + + delete iSourceMessages; + iSourceMessages = 0; + + delete iMessagesToCopyLocally; + iMessagesToCopyLocally = new (ELeave) CMsvEntrySelection; + + iSourceMessages = aMessageSelection->CopyL(); + + TInt count = iSourceMessages->Count(); + iOfflineOperationArrayFlag.Reset(); + + for(TInt i=0; i< count; ++i ) + { + iOfflineOperationArrayFlag.AppendL(EFalse); + } + + + Queue(aStatus); + + AddOfflineOperationL(); + } + + +void CImPop3SetOfflineOps::CancelOfflineOperationsL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus) +// Cancel all pending operations on each message in aSelection. + { + iState = ECancellingOfflineOperations; + iMessageCounter = 0; + + delete iSourceMessages; + iSourceMessages = 0; + + iSourceMessages = aSelection.CopyL(); + Queue(aStatus); + + CancelOfflineOperationL(); + } + +// Resumes a cancelled "Cancel Offline Operations" operation. +void CImPop3SetOfflineOps::ResumeCancelOfflineOperationsL(TRequestStatus& aStatus) + { + Queue(aStatus); + CancelOfflineOperationL(); + } + +void CImPop3SetOfflineOps::AddOfflineOperationL() + { + // Set the current entry, ready for the operation to be attached to it. + User::LeaveIfError(iEntry.SetEntry((*iSourceMessages)[iMessageCounter])); + + iModifiedOperationType = iOperationType; + + if ((iEntry.Entry()).Complete()) + // Any messages that have already been populated can be copied locally without + // the need to be online. + // This is done after any offline operations have been added but they are + // saved for later here: + { + if (iOperationType == CImOffLineOperation::EOffLineOpCopyToLocal) + { + iMessagesToCopyLocally->AppendL(iEntry.Entry().Id()); + iModifiedOperationType = CImOffLineOperation::EOffLineOpNone; + } + + if (iOperationType == CImOffLineOperation::EOffLineOpMoveToLocal) + { + iMessagesToCopyLocally->AppendL(iEntry.Entry().Id()); + iModifiedOperationType = CImOffLineOperation::EOffLineOpDelete; + } + } + + if (iModifiedOperationType == CImOffLineOperation::EOffLineOpNone) + { + iStatus = KRequestPending; + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + return; + } + + CImOffLineOperationArray* operationArray = CImOffLineOperationArray::NewL(); + CleanupStack::PushL(operationArray); + CImOffLineArrayStore* operationStore = new (ELeave) CImOffLineArrayStore(*operationArray); + CleanupStack::PushL(operationStore); + CMsvStore* messageStore = iEntry.EditStoreL(); + CleanupStack::PushL(messageStore); + + // Get the array of operations currently attached to the message. + operationStore->RestoreL(*messageStore); + + // If the operation is a move or delete then ensure that it doesn't interfere with any existing operations. + if ((iModifiedOperationType == CImOffLineOperation::EOffLineOpMoveToLocal) + || (iModifiedOperationType == CImOffLineOperation::EOffLineOpDelete)) + { + // Find out if there is a move or a delete operation already pending on the message. + TBool moveOrDeleteAlreadyPending = EFalse; + CImOffLineOperation::TOffLineOpType opType; + TInt counter = operationArray->CountOperations(); + + while (counter > 0) + { + counter--; + opType = (operationArray->Operation(counter)).OpType(); + if ((opType == CImOffLineOperation::EOffLineOpMoveToLocal) + || (opType == CImOffLineOperation::EOffLineOpDelete)) + { + moveOrDeleteAlreadyPending = ETrue; + counter = 0; + } + } + + if (moveOrDeleteAlreadyPending) + { + if (iModifiedOperationType == CImOffLineOperation::EOffLineOpMoveToLocal) + { + // Change the move operation to a copy, it will be deleted by the existing move or delete. + iModifiedOperationType = CImOffLineOperation::EOffLineOpCopyToLocal; + } + + if (iModifiedOperationType == CImOffLineOperation::EOffLineOpDelete) + { + // No need to append this delete operation as it will be delete be the existing move or delete. + iModifiedOperationType = CImOffLineOperation::EOffLineOpNone; + } + } + } + + CImOffLineOperation* operation = new (ELeave) CImOffLineOperation(); + CleanupStack::PushL(operation); + + TMsvEmailEntry entry = iEntry.Entry(); + + switch (iModifiedOperationType) + { + case CImOffLineOperation::EOffLineOpCopyFromLocal: + case CImOffLineOperation::EOffLineOpMoveFromLocal: + case CImOffLineOperation::EOffLineOpMoveWithinService: + case CImOffLineOperation::EOffLineOpChange: + case CImOffLineOperation::EOffLineOpCreate: + case CImOffLineOperation::EOffLineOpMtmSpecific: + User::Leave(KErrNotSupported); + + case CImOffLineOperation::EOffLineOpCopyToLocal: + operation->SetCopyToLocal((*iSourceMessages)[iMessageCounter], iDestinationEntryId); + break; + + case CImOffLineOperation::EOffLineOpDelete: + operation->SetDelete((*iSourceMessages)[iMessageCounter]); + break; + + case CImOffLineOperation::EOffLineOpCopyWithinService: + operation->SetCopyWithinService((*iSourceMessages)[iMessageCounter], iDestinationEntryId); + break; + + case CImOffLineOperation::EOffLineOpMoveToLocal: + operation->SetMoveToLocal((*iSourceMessages)[iMessageCounter], iDestinationEntryId); + break; + + case CImOffLineOperation::EOffLineOpNone: + break; + + default: + User::Leave(KErrNotSupported); + } + + + if (iModifiedOperationType != CImOffLineOperation::EOffLineOpNone) + { + operationArray->AppendOperationL(*operation); + entry.SetOperation(ETrue); + iOfflineOperationArrayFlag[iMessageCounter] = ETrue; + } + + CImPop3OfflineUtilities::SetOfflineFlags(*operationArray, entry); + + operationStore->StoreL(*messageStore); + iEntry.ChangeEntry(entry); + messageStore->CommitL(); + CleanupStack::PopAndDestroy(4); // operation, messageStore, operationStore, operationArray + iStatus = KRequestPending; + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + } + +void CImPop3SetOfflineOps::CancelOfflineOperationL() + { + SetActive(); + + // Set the current entry, ready for the operation to be attached to it. + User::LeaveIfError(iEntry.SetEntry((*iSourceMessages)[iMessageCounter])); + TMsvEmailEntry entry = iEntry.Entry(); + CImOffLineOperationArray* operationArray = CImOffLineOperationArray::NewL(); + CleanupStack::PushL(operationArray); + CImOffLineArrayStore* operationStore = new (ELeave) CImOffLineArrayStore(*operationArray); + CleanupStack::PushL(operationStore); + CMsvStore* messageStore = iEntry.EditStoreL(); + CleanupStack::PushL(messageStore); + + // Get the array of operations currently attached to the message. + operationStore->RestoreL(*messageStore); + + TInt counter = operationArray->CountOperations(); + while (counter > 0) + { + counter--; + operationArray->Delete(counter); + } + + operationStore->StoreL(*messageStore); + messageStore->CommitL(); + entry.SetOperation(EFalse); + entry.SetDisconnectedOperation(ENoDisconnectedOperations); + iEntry.ChangeEntry(entry); + CleanupStack::PopAndDestroy(3); // messageStore, operationStore, operationArray + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + } + +void CImPop3SetOfflineOps::CopyLocalMessageL() + // Copy the current local message. + { + User::LeaveIfError(iEntry.SetEntry((*iSourceMessages)[iMessageCounter])); + User::LeaveIfError(iEntry.SetEntry(iEntry.Entry().Parent())); + + iStatus = KRequestPending; + iTransfer->StartL((*iSourceMessages)[iMessageCounter], iDestinationEntryId, CImPop3TransferMessage::EImPop3CopyTransfer, iStatus); + + SetActive(); + } + +CImPop3SetOfflineOps::~CImPop3SetOfflineOps() + { + Cancel(); + delete iSourceMessages; + delete iMessagesToCopyLocally; + delete iTransfer; + iOfflineOperationArrayFlag.Close(); + } + +void CImPop3SetOfflineOps::Progress(TPop3Progress& rPop3Progress) const + { + // It is only necessary to report the progress when it is in the + // ECopyingLocalEntries state. All other states should be near-instantaneous + // and a 0 filled progress will do. + + switch (iState) + { + case ECopyingLocalEntries: + if (iOperationType == CImOffLineOperation::EOffLineOpMoveToLocal) + { + rPop3Progress.iPop3Progress = TPop3Progress::EPopMoving; + rPop3Progress.iPop3SubStateProgress = TPop3Progress::EPopMoving; + } + else + { + rPop3Progress.iPop3Progress = TPop3Progress::EPopCopying; + rPop3Progress.iPop3SubStateProgress = TPop3Progress::EPopCopying; + } + rPop3Progress.iTotalMsgs = iMessagesToCopyLocally->Count(); + rPop3Progress.iMsgsToProcess = rPop3Progress.iTotalMsgs - iMessageCounter; + rPop3Progress.iBytesDone = 0; + rPop3Progress.iTotalBytes = 0; + rPop3Progress.iErrorCode = 0; + break; + + case EAddingOfflineOperations: + if (iOperationType == CImOffLineOperation::EOffLineOpDelete) + { + rPop3Progress.iPop3Progress = TPop3Progress::EPopDeleting; + rPop3Progress.iTotalMsgs = iSourceMessages->Count(); + rPop3Progress.iMsgsToProcess = rPop3Progress.iTotalMsgs - iMessageCounter; + rPop3Progress.iBytesDone = 0; + rPop3Progress.iTotalBytes = 0; + rPop3Progress.iErrorCode = 0; + rPop3Progress.iPop3SubStateProgress = TPop3Progress::EPopDeleting; + } + else if (iOperationType == CImOffLineOperation::EOffLineOpMoveToLocal) + { + rPop3Progress.iPop3Progress = TPop3Progress::EPopMoving; + rPop3Progress.iTotalMsgs = iSourceMessages->Count(); + rPop3Progress.iMsgsToProcess = rPop3Progress.iTotalMsgs - iMessageCounter; + rPop3Progress.iBytesDone = 0; + rPop3Progress.iTotalBytes = 0; + if(rPop3Progress.iErrorCode != KErrDisconnected) + { + rPop3Progress.iErrorCode = 0; + } + rPop3Progress.iPop3SubStateProgress = TPop3Progress::EPopMoving; + } + else if ((iOperationType == CImOffLineOperation::EOffLineOpCopyToLocal) || + (iOperationType == CImOffLineOperation::EOffLineOpCopyWithinService)) + { + rPop3Progress.iPop3Progress = TPop3Progress::EPopCopying; + rPop3Progress.iTotalMsgs = iSourceMessages->Count(); + rPop3Progress.iMsgsToProcess = rPop3Progress.iTotalMsgs - iMessageCounter; + rPop3Progress.iBytesDone = 0; + rPop3Progress.iTotalBytes = 0; + if(rPop3Progress.iErrorCode != KErrDisconnected) + { + rPop3Progress.iErrorCode = 0; + } + rPop3Progress.iPop3SubStateProgress = TPop3Progress::EPopCopying; + } + break; + + case ECancellingOfflineOperations: + rPop3Progress.iPop3Progress = TPop3Progress::EPopCancellingOfflineOps; + rPop3Progress.iTotalMsgs = iSourceMessages->Count(); + rPop3Progress.iMsgsToProcess = rPop3Progress.iTotalMsgs - iMessageCounter; + rPop3Progress.iBytesDone = 0; + rPop3Progress.iTotalBytes = 0; + rPop3Progress.iErrorCode = 0; + rPop3Progress.iPop3SubStateProgress = TPop3Progress::EPopCancellingOfflineOps; + break; + + default: + { + _LIT(KPop3Session,"Pop3 session"); + __ASSERT_DEBUG(EFalse, User::Panic(KPop3Session, EPopInvalidState)); + } + break; + } + } + +//private: +void CImPop3SetOfflineOps::DoRunL() + { + // Create the ghost destination entry if one is required. + switch (iState) + { + case EAddingOfflineOperations: + if ((iModifiedOperationType == CImOffLineOperation::EOffLineOpCopyToLocal) + || (iModifiedOperationType == CImOffLineOperation::EOffLineOpMoveToLocal)) + { + User::LeaveIfError(iEntry.SetEntry((*iSourceMessages)[iMessageCounter])); + TMsvEntry ghostEntry = iEntry.Entry(); + ghostEntry.iRelatedId = iEntry.Entry().Id(); + ghostEntry.SetComplete(EFalse); + User::LeaveIfError(iEntry.SetEntry(iDestinationEntryId)); + iEntry.CreateEntry(ghostEntry); + } + + iMessageCounter++; + if (iMessageCounter < iSourceMessages->Count()) + { + AddOfflineOperationL(); + } + else + { + iMessageCounter = 0; + if (iMessageCounter < iMessagesToCopyLocally->Count()) + { + iState = ECopyingLocalEntries; + CopyLocalMessageL(); + } + } + break; + + case ECancellingOfflineOperations: + iMessageCounter++; + if (iMessageCounter < iSourceMessages->Count()) + { + CancelOfflineOperationL(); + } + break; + + case ECopyingLocalEntries: + iMessageCounter++; + if (iMessageCounter < iMessagesToCopyLocally->Count()) + { + CopyLocalMessageL(); + } + break; + } + } + +void CImPop3SetOfflineOps::DoCancel() + { + iTransfer->Cancel(); + + switch(iState) + { + case ECopyingLocalEntries: + { + TInt messageCounter = iMessageCounter; + + // Loop to delete all the operations attached to the messages in iSourceMessages. + for(TInt i = iSourceMessages->Count() - messageCounter; i > 0; -- i) + { + DeleteOfflineOperationL(messageCounter); + messageCounter++; + } + break; + } + + case EAddingOfflineOperations: + { + // Loop to delete all the operations attached to the messages in iSourceMessages. + for(TInt count = 0; count <= iMessageCounter; ++count) + { + DeleteOfflineOperationL(count); + } + break; + } + + case ECancellingOfflineOperations: + default: + { + // Nothing to be done here. + break; + } + } + iOfflineOperationArrayFlag.Reset(); + CMsgActive::DoCancel(); + } + + +void CImPop3SetOfflineOps::DeleteOfflineOperationL(TInt aMessageCounter) + { + // Set the current entry, ready for the operation to be attached to it. + User::LeaveIfError(iEntry.SetEntry((*iSourceMessages)[aMessageCounter])); + TMsvEmailEntry entry = iEntry.Entry(); + + if(iOfflineOperationArrayFlag[aMessageCounter]) + { + CImOffLineOperationArray* operationArray = CImOffLineOperationArray::NewL(); + CleanupStack::PushL(operationArray); + CImOffLineArrayStore* operationStore = new (ELeave) CImOffLineArrayStore(*operationArray); + CleanupStack::PushL(operationStore); + CMsvStore* messageStore = iEntry.EditStoreL(); + CleanupStack::PushL(messageStore); + + // Get the array of operations currently attached to the message. + operationStore->RestoreL(*messageStore); + + TInt counter = operationArray->CountOperations(); + if (counter > 0) + { + counter--; + operationArray->Delete(counter); + } + + operationStore->StoreL(*messageStore); + messageStore->CommitL(); + + if(counter == 0) + { + entry.SetOperation(EFalse); + entry.SetDisconnectedOperation(ENoDisconnectedOperations); + } + else + { + CImPop3OfflineUtilities::SetOfflineFlags(*operationArray, entry); + } + iEntry.ChangeEntry(entry); + CleanupStack::PopAndDestroy(3); // messageStore, operationStore, operationArray + } + } + + +void CImPop3SetOfflineOps::DoComplete(TInt& /*status*/) + { + + } + +CImPop3SetOfflineOps::CImPop3SetOfflineOps(CMsvServerEntry& aEntry) : CMsgActive(EPriorityStandard), iEntry(aEntry) + { + + } + +void CImPop3SetOfflineOps::ConstructL() + { + iTransfer = CImPop3TransferMessage::NewL(iEntry); + } + + + +void CImPop3OfflineUtilities::DeleteL(const CImOffLineOperation& aOperation, CMsvServerEntry& aEntry) +// Finds the specified operation in the message tree and then deletes it. + { + aEntry.SetEntry(aOperation.MessageId()); + CImOffLineOperationArray* localOperationArray = CImOffLineOperationArray::NewL(); + CleanupStack::PushL(localOperationArray); + CImOffLineArrayStore* operationStore = new (ELeave) CImOffLineArrayStore(*localOperationArray); + CleanupStack::PushL(operationStore); + CMsvStore* messageStore = aEntry.EditStoreL(); + CleanupStack::PushL(messageStore); + + // Get the array of operations currently attached to the message. + operationStore->RestoreL(*messageStore); + + // Look for the offline operation + TBool found = EFalse; + TInt index = 0; + while ((!found) && (index < localOperationArray->CountOperations())) + { + if (aOperation == localOperationArray->Operation(index)) + { + found = ETrue; + } + else + { + index++; + } + } + + if (found) + { + // Remove the entry from the list + localOperationArray->Delete(index); + + // Write out the list to the stream + operationStore->StoreL(*messageStore); + messageStore->CommitL(); + + // Set the TMsvEmailEntry details + TMsvEmailEntry entry = aEntry.Entry(); + SetOfflineFlags(*localOperationArray, entry); + aEntry.ChangeEntry(entry); + } + + CleanupStack::PopAndDestroy(3); // messageStore, operationStore, operationArray + } + +void CImPop3OfflineUtilities::SetOfflineFlags(const CImOffLineOperationArray& aOperationArray, TMsvEmailEntry& aEntry) + { + // Sets the DisconnectedOperation flag on the given TMsvEmailEntry. + // Note that it is NOT commited to the index. + TImDisconnectedOperationType operationType = ENoDisconnectedOperations; + TInt index = 0; + while (index < aOperationArray.CountOperations()) + { + if (operationType != ENoDisconnectedOperations) + { + operationType = EDisconnectedMultipleOperation; + } + else + { + switch (aOperationArray.Operation(index).OpType()) + { + case CImOffLineOperation::EOffLineOpCopyToLocal: + operationType = EDisconnectedCopyToOperation; + break; + case CImOffLineOperation::EOffLineOpCopyFromLocal: + operationType = EDisconnectedCopyFromOperation; + break; + case CImOffLineOperation::EOffLineOpCopyWithinService: + operationType = EDisconnectedCopyWithinServiceOperation; + break; + case CImOffLineOperation::EOffLineOpMoveToLocal: + operationType = EDisconnectedMoveToOperation; + break; + case CImOffLineOperation::EOffLineOpMoveFromLocal: + operationType = EDisconnectedMoveFromOperation; + break; + case CImOffLineOperation::EOffLineOpMoveWithinService: + operationType = EDisconnectedMoveWithinServiceOperation; + break; + case CImOffLineOperation::EOffLineOpDelete: + operationType = EDisconnectedDeleteOperation; + break; + case CImOffLineOperation::EOffLineOpChange: + operationType = EDisconnectedChangeOperation; + break; + case CImOffLineOperation::EOffLineOpCreate: + operationType = EDisconnectedCreateOperation; + break; + case CImOffLineOperation::EOffLineOpMtmSpecific: + operationType = EDisconnectedSpecialOperation; + break; + default: + operationType = EDisconnectedUnknownOperation; + break; + } + } + index++; + } + aEntry.SetDisconnectedOperation(operationType); + } + +