diff -r 000000000000 -r 72b543305e3a email/pop3andsmtpmtm/clientmtms/src/OFFOP.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/email/pop3andsmtpmtm/clientmtms/src/OFFOP.CPP Thu Dec 17 08:44:11 2009 +0200 @@ -0,0 +1,669 @@ +// 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: +// + +#if !defined(__MSVAPI_H__) +#include +#endif + +#include "OFFOP.H" +#include "MIUTQUE.H" + +#include "MIUT_ERR.H" +#include "MIUTSET.H" // KUidMsgTypeIMAP4 + + +const TUid KUidImQueuedOperationList = {0x10001794}; // 2648441492 dec. + + +// +// CImOffLineOperation +EXPORT_C CImOffLineOperation::CImOffLineOperation() + : iOpType(EOffLineOpNone), iMessageId(KMsvNullIndexEntryId), iTargetMessageId(KMsvNullIndexEntryId),iMtmFunctionId(0),iMtmParameters(NULL) + { + }; + +EXPORT_C TBool CImOffLineOperation::Equals(const CImOffLineOperation& aOperation) const + { + if (iOpType != aOperation.iOpType || + iMessageId != aOperation.iMessageId || + iTargetMessageId != aOperation.iTargetMessageId || + iMtmFunctionId != aOperation.iMtmFunctionId) + return EFalse; + + if (iMtmParameters) + { + if (!aOperation.iMtmParameters) + return EFalse; + if (iMtmParameters->Des().Compare(aOperation.iMtmParameters->Des())) + return EFalse; + } + + return ETrue; + } + +EXPORT_C void CImOffLineOperation::CopyL(const CImOffLineOperation& aOperation) + { + DeleteBuffer(); + iOpType = aOperation.iOpType; + iMessageId = aOperation.iMessageId; + iTargetMessageId = aOperation.iTargetMessageId; + iMtmFunctionId = aOperation.iMtmFunctionId; + if (aOperation.iMtmParameters) + { + iMtmParameters = aOperation.iMtmParameters->Des().AllocL(); + } + } + +EXPORT_C CImOffLineOperation::~CImOffLineOperation() + { + DeleteBuffer(); + } + +EXPORT_C void CImOffLineOperation::DeleteBuffer() + { + delete iMtmParameters; + iMtmParameters = NULL; + } + +EXPORT_C void CImOffLineOperation::DetachMtmParameters() + { + iMtmParameters = NULL; + } + +EXPORT_C void CImOffLineOperation::SetMtmSpecificCommandL(TMsvId aMessageId, TMsvId aTargetMessageId, TInt aMtmFunctionId, const TDesC8& aParameters) + { + HBufC8* parameters = aParameters.AllocL(); + SetOperation(EOffLineOpMtmSpecific, aMessageId, aTargetMessageId, aMtmFunctionId, parameters); + } + + +EXPORT_C void CImOffLineOperation::SetOperation(TOffLineOpType aOpType, TMsvId aMessageId, TMsvId aTargetMessageId, TInt aMtmFunctionId, HBufC8* aParameters) + { + DeleteBuffer(); + iOpType = aOpType; + iMessageId = aMessageId; + iTargetMessageId = aTargetMessageId; + iMtmFunctionId = aMtmFunctionId; + iMtmFunctionId = aMtmFunctionId; + iMtmParameters = aParameters; + } + +EXPORT_C void CImOffLineOperation::SetOperation(TOffLineOpType aOpType, TMsvId aMessageId, TMsvId aTargetMessageId) + { + DeleteBuffer(); + iOpType = aOpType; + iMessageId = aMessageId; + iTargetMessageId = aTargetMessageId; + iMtmFunctionId = 0; + } + +EXPORT_C void CImOffLineOperation::ExternalizeL( RMsvWriteStream& aWriteStream ) const + { + aWriteStream.WriteInt32L(iOpType); + aWriteStream.WriteInt32L(iMessageId); + aWriteStream.WriteInt32L(iTargetMessageId); + aWriteStream.WriteInt32L(iMtmFunctionId); + + if (iMtmParameters) + { + TInt length = iMtmParameters->Length(); + aWriteStream.WriteInt32L(length); + if (length > 0) + aWriteStream << TPtrC8(*iMtmParameters); + } + else + { + aWriteStream.WriteInt32L(0); + } + return; + } + +EXPORT_C void CImOffLineOperation::InternalizeL( RMsvReadStream& aReadStream ) + { + DeleteBuffer(); + iOpType = TOffLineOpType(aReadStream.ReadInt32L()); + iMessageId = TMsvId(aReadStream.ReadInt32L()); + iTargetMessageId = TMsvId(aReadStream.ReadInt32L()); + iMtmFunctionId = aReadStream.ReadInt32L(); + + TInt length = aReadStream.ReadInt32L(); + + if (length > 0) + { + iMtmParameters = HBufC8::NewL(aReadStream, length); + } + return; + } + +EXPORT_C int CImOffLineOperation::operator ==(const CImOffLineOperation& otherOperation) const + { + TBool result; + + if ((iMessageId == otherOperation.iMessageId) + && (iMtmFunctionId == otherOperation.iMtmFunctionId) + && (iOpType == otherOperation.iOpType) + && (iTargetMessageId == otherOperation.iTargetMessageId)) + { + result = ETrue; + } + else + { + result = EFalse; + } + + if (iMtmParameters != otherOperation.iMtmParameters) + { + if ((iMtmParameters == NULL) || (otherOperation.iMtmParameters == NULL)) + { + result = EFalse; + } + else if (*iMtmParameters != *(otherOperation.iMtmParameters)) + { + result = EFalse; + } + } + + return result; + } + + +// +// CImOffLineOperationArrayStore + +EXPORT_C void CImOffLineArrayStore::StoreL(CMsvStore& aMsvStore) const + { + RMsvWriteStream out; + out.AssignLC( aMsvStore, KUidImQueuedOperationList ); + ExternalizeL(out); + out.CommitL(); + CleanupStack::PopAndDestroy(); + } + + +EXPORT_C void CImOffLineArrayStore::RestoreL(const CMsvStore& aMessageStore ) + { + if (aMessageStore.IsPresentL(KUidImQueuedOperationList)) + { + RMsvReadStream in; + in.OpenLC( aMessageStore, KUidImQueuedOperationList ); // pushes 'in' to the stack + InternalizeL(in); + CleanupStack::PopAndDestroy(); + } + } + +EXPORT_C void CImOffLineArrayStore::ExternalizeL(RMsvWriteStream& aWriteStream) const + { + TInt nr = iArray->CountOperations(); + aWriteStream.WriteUint16L(iVersion); + aWriteStream.WriteInt32L(nr); + + TInt i; + for ( i = 0 ; i < nr ; i++) + { + iArray->Operation( i ).ExternalizeL(aWriteStream); + } + } + +EXPORT_C void CImOffLineArrayStore::InternalizeL(RMsvReadStream& aReadStream) + { + TInt nr; + TUint16 version = aReadStream.ReadUint16L(); + if (version > iVersion) + return; + + nr = aReadStream.ReadInt32L(); + CImOffLineOperation *operation=new(ELeave)CImOffLineOperation; + CleanupStack::PushL(operation); + + TInt i; + for (i = 0 ; i < nr ; i++) + { + operation->InternalizeL(aReadStream); + iArray->AppendOperationL(*operation); + } + CleanupStack::PopAndDestroy();//operation + } + + +// +// COffLineOperationArrayStore +EXPORT_C CImOffLineOperationArray* CImOffLineOperationArray::NewL() + { + CImOffLineOperationArray* self = new(ELeave)CImOffLineOperationArray(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop();//self + return self; + } + +EXPORT_C void CImOffLineOperationArray::ConstructL() + { + iArray = new(ELeave)CArrayFixFlat(10); + } + +CImOffLineOperationArray::CImOffLineOperationArray() + { + } + +EXPORT_C CImOffLineOperationArray::~CImOffLineOperationArray() + { + if (iArray) + { + TInt i; + TInt nr = CountOperations(); + for (i=0;iCount(); + } + +const CImOffLineOperation& CImOffLineOperationArray::Operation(TInt aIndex) const + { + return iArray->At(aIndex); + } + +void CImOffLineOperationArray::AppendOperationL(const CImOffLineOperation& aOperation) + { + CImOffLineOperation *operation=new(ELeave)CImOffLineOperation; + CleanupStack::PushL(operation); + operation->CopyL(aOperation); // Construct by hand + iArray->AppendL(*operation); + operation->DetachMtmParameters(); // Delete by hand + CleanupStack::PopAndDestroy();//operation + } + +EXPORT_C void CImOffLineOperationArray::InsertOperationL(CImOffLineOperation& aOperation, TInt aPosition) + { + CImOffLineOperation *operation=new(ELeave)CImOffLineOperation; + CleanupStack::PushL(operation); + operation->CopyL(aOperation); // Construct by hand + iArray->InsertL(aPosition,*operation); + operation->DetachMtmParameters(); // Delete by hand + CleanupStack::PopAndDestroy();//operation + } + +void CImOffLineOperationArray::Delete(TInt aIndex) + { + (*iArray)[aIndex].DeleteBuffer(); + iArray->Delete(aIndex); + } + +// +// TQueuedOperation + + +EXPORT_C TQueuedOperation* TQueuedOperation::NewL(TMsvId aFolderId,TInt aOperationIndex, const CImOffLineOperation& aStoredOperation) + { + TQueuedOperation* self = new(ELeave)TQueuedOperation(aFolderId,aOperationIndex); + CleanupStack::PushL(self); + self->iStoredOperation.CopyL(aStoredOperation); + CleanupStack::Pop();//self + return self; + } + + +TQueuedOperation::TQueuedOperation(TMsvId aFolderId,TInt aOperationIndex) + : iFolderId(aFolderId),iOperationIndex(aOperationIndex) + { + } + +EXPORT_C TQueuedOperation::TQueuedOperation() + : iFolderId(KMsvNullIndexEntryId), iOperationIndex(0), iStoredOperation() + { + } + +EXPORT_C void TQueuedOperation::CopyL(const TQueuedOperation& aOperation) + { + iFolderId = aOperation.iFolderId; + iOperationIndex = aOperation.iOperationIndex; + iStoredOperation.CopyL(aOperation.iStoredOperation); + } + +EXPORT_C TBool TQueuedOperation::operator!=(const TQueuedOperation& aOp) + { + return (iFolderId != aOp.iFolderId || + iOperationIndex != aOp.iOperationIndex || + !iStoredOperation.Equals(aOp.iStoredOperation)); + } + +// +// CImQueuedList + +EXPORT_C CImQueuedList* CImQueuedList::NewL() + { + CImQueuedList* self = new(ELeave)CImQueuedList(); + CleanupStack::PushL(self); + self->iArray = new(ELeave)CArrayFixFlat(10); + CleanupStack::Pop();//self + return self; + } + +CImQueuedList::CImQueuedList() + : iFolderId(KMsvNullIndexEntryId), iLine(0) + { + } + +EXPORT_C CImQueuedList::~CImQueuedList() + { + if (iArray) + { + TInt i; + TInt nr = CountOperations(); + for (i=0;iCount(); + } + +EXPORT_C const CImOffLineOperation& CImQueuedList::Operation(TInt aIndex) const + { + return iArray->At(aIndex).Operation(); + } + +EXPORT_C void CImQueuedList::AppendOperationL(const CImOffLineOperation& aOperation) + { + TQueuedOperation *operation=TQueuedOperation::NewL(iFolderId, iLine, aOperation); + CleanupStack::PushL(operation); + iArray->AppendL(*operation); + operation->Operation().DetachMtmParameters(); + CleanupStack::Pop();//operation + delete operation; + iLine++; + } + +EXPORT_C void CImQueuedList::Delete(TInt aIndex) + { + (*iArray)[aIndex].Operation().DeleteBuffer(); + iArray->Delete(aIndex); + } + +EXPORT_C void CImQueuedList::Reset() + { + TInt i; + TInt nr = iArray->Count(); + for (i=0;iReset(); + } + +EXPORT_C void CImQueuedList::AppendL(TQueuedOperation& aOperation) + { + iArray->AppendL(aOperation); + aOperation.Operation().DetachMtmParameters(); + } + +// +// CImOperationQueueList +// +// definition of class CImOperationQueueList. This class is responsible for gathering all +// the queued information of a MTM service, traversing folders to gather that +// information. It will then give access to the queued operations in the list, allowing +// queued elements to be deleted. +// + +EXPORT_C CImOperationQueueList* CImOperationQueueList::NewL(CMsvEntry& aServiceEntry, MImUndoOffLineOperation *aImUndoOffLineOperation) +// +// Create new list of queued operations for service entry aServiceEntry is set to. +// + { + CImOperationQueueList* self = new (ELeave) CImOperationQueueList(aServiceEntry, aImUndoOffLineOperation); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop();//self + return self; + } + +EXPORT_C CImOperationQueueList::~CImOperationQueueList() + { + delete iServiceEntry; + delete iQueuedList; + delete iDeletedList; + } + +CImOperationQueueList::CImOperationQueueList(CMsvEntry& aServiceEntry, MImUndoOffLineOperation *aImUndoOffLineOperation) + : iServiceEntry(&aServiceEntry) , iUndoOffline(aImUndoOffLineOperation) + { + iServiceId = iServiceEntry->Entry().Id(); + }; + +void CImOperationQueueList::ProcessFoldersL() +// +// Usage: reset iQueuedList, set iServiceEntry to the service entry, and +// call this function if a complete list of all queued operations stored +// under the folders within the service is needed. +// + { + __ASSERT_DEBUG( iServiceEntry->Entry().iType == KUidMsvFolderEntry || + iServiceEntry->Entry().iType == KUidMsvServiceEntry, gPanic(EOffOpEntryShouldBeFolder)); + CMsvEntrySelection* selection = iServiceEntry->ChildrenWithTypeL(KUidMsvFolderEntry); + CleanupStack::PushL(selection); + + TInt folder; + TInt nr = selection->Count(); + for ( folder = 0 ; folder < nr; folder ++ ) + { + iServiceEntry->SetEntryL( (*selection)[ folder ] ); + RestoreQueuedListL(*iQueuedList); + ProcessFoldersL(); + } + + CleanupStack::PopAndDestroy();//selection + } + +void CImOperationQueueList::ConstructL() +// +// Create the list of queued operations. +// + { + iQueuedList = CImQueuedList::NewL(); + iDeletedList = CImQueuedList::NewL(); + + iDeletedList->Reset(); + iQueuedList->Reset(); + ProcessFoldersL(); + } + +EXPORT_C void CImOperationQueueList::DeleteL(TInt aLine) +// +// Remove operation from list of queued operations locally. +// + { + TQueuedOperation deletedOperation; + deletedOperation.CopyL((*iQueuedList)[aLine]); + iQueuedList->Delete(aLine); + iDeletedList->AppendL(deletedOperation); + } + +void CImOperationQueueList::RestoreQueuedListL(CImQueuedList &aList) +// +// Append contents of current entry (pointed to by iServiceEntry) +// to aList. +// + { + __ASSERT_DEBUG( iServiceEntry->Entry().iMtm == KUidMsgTypeIMAP4, gPanic(EOffOpBadMtmTypeUid)); + __ASSERT_DEBUG( iServiceEntry->Entry().iType == KUidMsvFolderEntry || + iServiceEntry->Entry().iType == KUidMsvServiceEntry, gPanic(EOffOpEntryShouldBeFolder)); + + TInt err=KErrNone; + CMsvStore* store=NULL; +// Leaves with KErrNotFound if no store exists. + TRAP(err,store=iServiceEntry->ReadStoreL()); + if (err) + return; + CleanupStack::PushL(store); + + aList.SetFolder(iServiceEntry->Entry().Id()); + aList.ResetLineCounter(); + + CImOffLineArrayStore internaliser(aList); + internaliser.RestoreL(*store); + CleanupStack::PopAndDestroy();//store + } + +void CImOperationQueueList::StoreQueuedListL(CImQueuedList &aList) +// +// Store contents of aList back in current entry (pointed to by iServiceEntry) +// to aList. +// + { + __ASSERT_DEBUG( iServiceEntry->Entry().iMtm == KUidMsgTypeIMAP4, gPanic(EOffOpBadMtmTypeUid)); + __ASSERT_DEBUG( iServiceEntry->Entry().iType == KUidMsvFolderEntry || + iServiceEntry->Entry().iType == KUidMsvServiceEntry, gPanic(EOffOpEntryShouldBeFolder)); + CMsvStore* store = iServiceEntry->EditStoreL(); + CleanupStack::PushL(store); + CImOffLineArrayStore externaliser(aList); + externaliser.StoreL(*store); + store->CommitL(); + CleanupStack::PopAndDestroy();//store + } + +EXPORT_C void CImOperationQueueList::ExpungeDeletedOperationsL() +// +// Remove the queued operations that were marked as deleted from the folder stores. +// + { + // First sort so that each store only has to be visited once, and queued operations + // can be deleted back-to-front. Starting at the back leaves the other delete commands + // valid. + TQueuedOperationKey key(*iDeletedList); + TQueuedOperationSwap swap(*iDeletedList); + User::QuickSort(iDeletedList->CountOperations(),key,swap); + + // Current folder being updated + TMsvId lastFolderRead = KMsvNullIndexEntryId; + // list holds the list of queued operations for the current folder + CImQueuedList *list = CImQueuedList::NewL(); + CleanupStack::PushL(list); + + TInt line; + + TInt nr = iDeletedList->CountOperations(); + for ( line = 0 ; line < nr; line ++ ) + { + // Get item to delete + TQueuedOperation toDelete; + toDelete.CopyL((*iDeletedList)[ 0 ]); + iDeletedList->Delete(0); + + // See if item belongs to different folder. + if (lastFolderRead != toDelete.FolderId()) + { + // Store changes to previous list + if (lastFolderRead != KMsvNullIndexEntryId) + { + StoreQueuedListL(*list); + } + + // go to folder to delete item from. + iServiceEntry->SetEntryL(toDelete.FolderId()); + __ASSERT_DEBUG( iServiceEntry->Entry().iMtm == KUidMsgTypeIMAP4, gPanic(EOffOpBadMtmTypeUid)); + __ASSERT_DEBUG(iServiceEntry->Entry().iType == KUidMsvFolderEntry, gPanic(EOffOpEntryShouldBeFolder)); + + // Initialise for the next folder + lastFolderRead = toDelete.FolderId(); + // Get the list of queued operations + list->Reset(); + RestoreQueuedListL(*list); + } + + // Sanity check: the data contained in toDelete should be EXACTLY the same as + // the queued operation it refers to (as retrieved from the folder) + if (toDelete != (*list)[ toDelete.OperationIndex() ]) + { + gPanic(EOffOpListOutOfSync); + continue; + } + + // Undo changes made in server to reflect the disconnected operation. + iUndoOffline->UndoOffLineChangesL(toDelete.Operation(), toDelete.FolderId()); + // Delete queued operation from list + list->Delete(toDelete.OperationIndex()); + } + + // Store changes to last folder. + if (lastFolderRead != KMsvNullIndexEntryId) + { + StoreQueuedListL(*list); + } + CleanupStack::PopAndDestroy(); //list + } + +// +// TQueuedOperationSwap +EXPORT_C TQueuedOperationSwap::TQueuedOperationSwap(CImQueuedList& aList) + : iList(aList) + { + }; + +void TQueuedOperationSwap::Swap(TInt aLeft,TInt aRight) const + { + Mem::Swap(&iList[aLeft],&iList[aRight],sizeof(TQueuedOperation)); + } + +// +// TQueuedOperationKey +EXPORT_C TQueuedOperationKey::TQueuedOperationKey(CImQueuedList& aList) + : iList(aList) + { + } + +TInt TQueuedOperationKey::Compare(TInt aLeft,TInt aRight) const + { + if (aLeft == aRight) + return 0; + if (iList[ aLeft ].FolderId() != iList[ aRight ].FolderId()) + return iList[ aLeft ].FolderId() - iList[ aRight ].FolderId(); + // Sort in descending order, so last lines will be deleted first + TInt diff = iList[ aRight ].OperationIndex() - iList[ aLeft ].OperationIndex(); + __ASSERT_DEBUG(diff != 0, gPanic(EOffOpTwoSameLinesNotAllowed)); + return diff; + } +TAny *TQueuedOperationKey::At(TInt anIndex) const + { + return &iList[ anIndex ]; + } + +