email/pop3andsmtpmtm/clientmtms/src/OFFOP.CPP
changeset 0 72b543305e3a
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #if !defined(__MSVAPI_H__)
       
    17 #include <msvapi.h>
       
    18 #endif
       
    19 
       
    20 #include "OFFOP.H"
       
    21 #include "MIUTQUE.H"
       
    22 
       
    23 #include "MIUT_ERR.H"
       
    24 #include "MIUTSET.H"	// KUidMsgTypeIMAP4
       
    25 
       
    26 
       
    27 const TUid KUidImQueuedOperationList = {0x10001794};	// 2648441492 dec.
       
    28 
       
    29 
       
    30 //
       
    31 // CImOffLineOperation
       
    32 EXPORT_C CImOffLineOperation::CImOffLineOperation() 
       
    33     : iOpType(EOffLineOpNone), iMessageId(KMsvNullIndexEntryId), iTargetMessageId(KMsvNullIndexEntryId),iMtmFunctionId(0),iMtmParameters(NULL)
       
    34     {
       
    35     };
       
    36 
       
    37 EXPORT_C TBool CImOffLineOperation::Equals(const CImOffLineOperation& aOperation) const
       
    38     {
       
    39     if (iOpType				!= aOperation.iOpType			||
       
    40         iMessageId			!= aOperation.iMessageId		||
       
    41         iTargetMessageId	!= aOperation.iTargetMessageId	||
       
    42 		iMtmFunctionId		!= aOperation.iMtmFunctionId)
       
    43         return EFalse;
       
    44 
       
    45     if (iMtmParameters)
       
    46         {
       
    47         if (!aOperation.iMtmParameters)
       
    48             return EFalse;
       
    49         if (iMtmParameters->Des().Compare(aOperation.iMtmParameters->Des()))
       
    50             return EFalse;
       
    51         }
       
    52     
       
    53     return ETrue;
       
    54     }
       
    55 
       
    56 EXPORT_C void CImOffLineOperation::CopyL(const CImOffLineOperation& aOperation)
       
    57     {
       
    58     DeleteBuffer();
       
    59     iOpType				= aOperation.iOpType; 
       
    60     iMessageId			= aOperation.iMessageId;
       
    61     iTargetMessageId	= aOperation.iTargetMessageId;
       
    62 	iMtmFunctionId		= aOperation.iMtmFunctionId;
       
    63     if (aOperation.iMtmParameters)
       
    64         {
       
    65         iMtmParameters = aOperation.iMtmParameters->Des().AllocL();
       
    66         }
       
    67     }
       
    68 
       
    69 EXPORT_C CImOffLineOperation::~CImOffLineOperation()
       
    70     {
       
    71     DeleteBuffer();
       
    72     }
       
    73 
       
    74 EXPORT_C void CImOffLineOperation::DeleteBuffer()
       
    75     {
       
    76     delete iMtmParameters;
       
    77     iMtmParameters = NULL;
       
    78     }
       
    79 
       
    80 EXPORT_C void CImOffLineOperation::DetachMtmParameters()
       
    81     {
       
    82     iMtmParameters = NULL;
       
    83     }
       
    84 
       
    85 EXPORT_C void CImOffLineOperation::SetMtmSpecificCommandL(TMsvId aMessageId, TMsvId aTargetMessageId, TInt aMtmFunctionId, const TDesC8& aParameters)
       
    86     {
       
    87     HBufC8* parameters = aParameters.AllocL();
       
    88     SetOperation(EOffLineOpMtmSpecific, aMessageId, aTargetMessageId, aMtmFunctionId, parameters);
       
    89     }
       
    90 
       
    91 
       
    92 EXPORT_C void CImOffLineOperation::SetOperation(TOffLineOpType aOpType, TMsvId aMessageId, TMsvId aTargetMessageId, TInt aMtmFunctionId, HBufC8* aParameters)
       
    93     {
       
    94     DeleteBuffer();
       
    95     iOpType				= aOpType;
       
    96     iMessageId			= aMessageId;
       
    97     iTargetMessageId	= aTargetMessageId;
       
    98     iMtmFunctionId		= aMtmFunctionId;
       
    99     iMtmFunctionId		= aMtmFunctionId;
       
   100     iMtmParameters		= aParameters;
       
   101     }
       
   102 
       
   103 EXPORT_C void CImOffLineOperation::SetOperation(TOffLineOpType aOpType, TMsvId aMessageId, TMsvId aTargetMessageId)
       
   104     {
       
   105     DeleteBuffer();
       
   106     iOpType				= aOpType;
       
   107     iMessageId			= aMessageId;
       
   108     iTargetMessageId	= aTargetMessageId;
       
   109     iMtmFunctionId		= 0;
       
   110     }
       
   111 
       
   112 EXPORT_C void CImOffLineOperation::ExternalizeL( RMsvWriteStream& aWriteStream ) const
       
   113 	{
       
   114     aWriteStream.WriteInt32L(iOpType);
       
   115     aWriteStream.WriteInt32L(iMessageId);
       
   116     aWriteStream.WriteInt32L(iTargetMessageId);
       
   117     aWriteStream.WriteInt32L(iMtmFunctionId);
       
   118 
       
   119     if (iMtmParameters)
       
   120         {
       
   121         TInt length = iMtmParameters->Length();
       
   122         aWriteStream.WriteInt32L(length);
       
   123         if (length > 0)
       
   124             aWriteStream << TPtrC8(*iMtmParameters);
       
   125         }
       
   126     else
       
   127         {
       
   128         aWriteStream.WriteInt32L(0);
       
   129         }
       
   130 	return;
       
   131 	}
       
   132 
       
   133 EXPORT_C void CImOffLineOperation::InternalizeL( RMsvReadStream& aReadStream )
       
   134     {                        
       
   135     DeleteBuffer();
       
   136     iOpType				= TOffLineOpType(aReadStream.ReadInt32L());
       
   137     iMessageId			= TMsvId(aReadStream.ReadInt32L());
       
   138     iTargetMessageId	= TMsvId(aReadStream.ReadInt32L());
       
   139     iMtmFunctionId		= aReadStream.ReadInt32L();
       
   140 
       
   141     TInt length			= aReadStream.ReadInt32L();
       
   142     
       
   143     if (length > 0)
       
   144         {               
       
   145         iMtmParameters = HBufC8::NewL(aReadStream, length);
       
   146         }
       
   147 	return;
       
   148 	}
       
   149 
       
   150 EXPORT_C int CImOffLineOperation::operator ==(const CImOffLineOperation& otherOperation) const
       
   151 	{
       
   152 	TBool result;
       
   153 
       
   154 	if ((iMessageId == otherOperation.iMessageId)
       
   155 		&& (iMtmFunctionId == otherOperation.iMtmFunctionId)
       
   156 		&& (iOpType == otherOperation.iOpType)
       
   157 		&& (iTargetMessageId == otherOperation.iTargetMessageId))
       
   158 		{
       
   159 		result = ETrue;
       
   160 		}
       
   161 	else
       
   162 		{
       
   163 		result = EFalse;
       
   164 		}
       
   165 
       
   166 	if (iMtmParameters != otherOperation.iMtmParameters)
       
   167 		{
       
   168 		if ((iMtmParameters == NULL) || (otherOperation.iMtmParameters == NULL))
       
   169 			{
       
   170 			result = EFalse;
       
   171 			}
       
   172 		else if (*iMtmParameters != *(otherOperation.iMtmParameters))
       
   173 			{
       
   174 			result = EFalse;
       
   175 			}
       
   176 		}
       
   177 
       
   178 	return result;
       
   179 	}
       
   180 
       
   181 
       
   182 //
       
   183 // CImOffLineOperationArrayStore
       
   184 
       
   185 EXPORT_C void CImOffLineArrayStore::StoreL(CMsvStore& aMsvStore) const
       
   186 	{
       
   187 	RMsvWriteStream out;
       
   188 	out.AssignLC( aMsvStore, KUidImQueuedOperationList ); 
       
   189 	ExternalizeL(out);
       
   190 	out.CommitL();
       
   191 	CleanupStack::PopAndDestroy();
       
   192 	}
       
   193 
       
   194 
       
   195 EXPORT_C void CImOffLineArrayStore::RestoreL(const CMsvStore& aMessageStore )
       
   196 	{
       
   197 	if (aMessageStore.IsPresentL(KUidImQueuedOperationList))
       
   198 		{
       
   199 		RMsvReadStream in;
       
   200 		in.OpenLC( aMessageStore, KUidImQueuedOperationList ); // pushes 'in' to the stack
       
   201 		InternalizeL(in);
       
   202 		CleanupStack::PopAndDestroy();
       
   203 		}
       
   204 	}
       
   205 
       
   206 EXPORT_C void CImOffLineArrayStore::ExternalizeL(RMsvWriteStream& aWriteStream) const
       
   207     {
       
   208     TInt nr = iArray->CountOperations();
       
   209     aWriteStream.WriteUint16L(iVersion);
       
   210     aWriteStream.WriteInt32L(nr);
       
   211     
       
   212     TInt i;
       
   213     for ( i = 0 ; i < nr ; i++)
       
   214         {
       
   215         iArray->Operation( i ).ExternalizeL(aWriteStream);
       
   216         }
       
   217     }
       
   218 
       
   219 EXPORT_C void CImOffLineArrayStore::InternalizeL(RMsvReadStream& aReadStream)
       
   220     {
       
   221     TInt nr;
       
   222     TUint16 version = aReadStream.ReadUint16L();
       
   223     if (version > iVersion)
       
   224         return;
       
   225     
       
   226     nr = aReadStream.ReadInt32L();
       
   227     CImOffLineOperation *operation=new(ELeave)CImOffLineOperation;
       
   228     CleanupStack::PushL(operation);
       
   229     
       
   230     TInt i;
       
   231     for (i = 0 ; i < nr ; i++)
       
   232         {
       
   233         operation->InternalizeL(aReadStream);
       
   234         iArray->AppendOperationL(*operation);
       
   235         }
       
   236     CleanupStack::PopAndDestroy();//operation
       
   237     }
       
   238 
       
   239 
       
   240 //
       
   241 // COffLineOperationArrayStore
       
   242 EXPORT_C CImOffLineOperationArray* CImOffLineOperationArray::NewL()
       
   243     {
       
   244     CImOffLineOperationArray* self = new(ELeave)CImOffLineOperationArray();
       
   245     CleanupStack::PushL(self);
       
   246     self->ConstructL();
       
   247     CleanupStack::Pop();//self
       
   248     return self;
       
   249     }
       
   250 
       
   251 EXPORT_C void CImOffLineOperationArray::ConstructL()
       
   252     {
       
   253     iArray = new(ELeave)CArrayFixFlat<CImOffLineOperation>(10);
       
   254     }
       
   255 
       
   256 CImOffLineOperationArray::CImOffLineOperationArray()
       
   257     {
       
   258     }
       
   259 
       
   260 EXPORT_C CImOffLineOperationArray::~CImOffLineOperationArray()
       
   261     {
       
   262 	if (iArray)
       
   263 		{
       
   264 		TInt i;
       
   265 		TInt nr = CountOperations();
       
   266 		for (i=0;i<nr;i++)
       
   267 			{
       
   268 			(*iArray)[i].DeleteBuffer();
       
   269 			}
       
   270 		delete iArray;
       
   271 		}
       
   272     }
       
   273 
       
   274 TInt CImOffLineOperationArray::CountOperations() const
       
   275     {
       
   276     return iArray->Count();
       
   277     }
       
   278 
       
   279 const CImOffLineOperation& CImOffLineOperationArray::Operation(TInt aIndex) const
       
   280     {
       
   281     return iArray->At(aIndex);
       
   282     }
       
   283 
       
   284 void CImOffLineOperationArray::AppendOperationL(const CImOffLineOperation& aOperation)
       
   285     {
       
   286     CImOffLineOperation *operation=new(ELeave)CImOffLineOperation;
       
   287     CleanupStack::PushL(operation);
       
   288     operation->CopyL(aOperation);      // Construct by hand
       
   289     iArray->AppendL(*operation);
       
   290     operation->DetachMtmParameters();  // Delete by hand
       
   291     CleanupStack::PopAndDestroy();//operation 
       
   292     }
       
   293 
       
   294 EXPORT_C void CImOffLineOperationArray::InsertOperationL(CImOffLineOperation& aOperation, TInt aPosition)
       
   295     {
       
   296     CImOffLineOperation *operation=new(ELeave)CImOffLineOperation;
       
   297     CleanupStack::PushL(operation);
       
   298     operation->CopyL(aOperation);      // Construct by hand
       
   299 	iArray->InsertL(aPosition,*operation);
       
   300     operation->DetachMtmParameters();  // Delete by hand
       
   301     CleanupStack::PopAndDestroy();//operation 
       
   302     }
       
   303 
       
   304 void CImOffLineOperationArray::Delete(TInt aIndex)
       
   305 	{
       
   306 	(*iArray)[aIndex].DeleteBuffer();
       
   307 	iArray->Delete(aIndex);
       
   308 	}
       
   309 
       
   310 //
       
   311 // TQueuedOperation
       
   312 
       
   313 
       
   314 EXPORT_C TQueuedOperation* TQueuedOperation::NewL(TMsvId aFolderId,TInt aOperationIndex, const CImOffLineOperation& aStoredOperation)
       
   315     {
       
   316     TQueuedOperation* self = new(ELeave)TQueuedOperation(aFolderId,aOperationIndex);
       
   317     CleanupStack::PushL(self);
       
   318     self->iStoredOperation.CopyL(aStoredOperation);
       
   319     CleanupStack::Pop();//self
       
   320     return self;
       
   321     }
       
   322 
       
   323 
       
   324 TQueuedOperation::TQueuedOperation(TMsvId aFolderId,TInt aOperationIndex)
       
   325 	: iFolderId(aFolderId),iOperationIndex(aOperationIndex)
       
   326 	{
       
   327     }
       
   328 
       
   329 EXPORT_C TQueuedOperation::TQueuedOperation()
       
   330     : iFolderId(KMsvNullIndexEntryId), iOperationIndex(0), iStoredOperation()
       
   331     {
       
   332     }
       
   333 
       
   334 EXPORT_C void TQueuedOperation::CopyL(const TQueuedOperation& aOperation)
       
   335     {
       
   336 	iFolderId       = aOperation.iFolderId;
       
   337 	iOperationIndex = aOperation.iOperationIndex;
       
   338 	iStoredOperation.CopyL(aOperation.iStoredOperation);
       
   339     }
       
   340 
       
   341 EXPORT_C TBool TQueuedOperation::operator!=(const TQueuedOperation& aOp)
       
   342 	{
       
   343 	return (iFolderId       != aOp.iFolderId || 
       
   344             iOperationIndex != aOp.iOperationIndex ||
       
   345             !iStoredOperation.Equals(aOp.iStoredOperation));
       
   346 	}
       
   347 
       
   348 //
       
   349 // CImQueuedList
       
   350 
       
   351 EXPORT_C CImQueuedList* CImQueuedList::NewL()
       
   352     {
       
   353     CImQueuedList* self = new(ELeave)CImQueuedList();
       
   354     CleanupStack::PushL(self);
       
   355     self->iArray = new(ELeave)CArrayFixFlat<TQueuedOperation>(10);
       
   356     CleanupStack::Pop();//self
       
   357     return self;
       
   358     }
       
   359 
       
   360 CImQueuedList::CImQueuedList() 
       
   361     : iFolderId(KMsvNullIndexEntryId), iLine(0)
       
   362     {
       
   363     }
       
   364 
       
   365 EXPORT_C CImQueuedList::~CImQueuedList() 
       
   366     {
       
   367 	if (iArray)
       
   368 		{
       
   369 		TInt i;
       
   370 		TInt nr = CountOperations();
       
   371 		for (i=0;i<nr;i++)
       
   372 			{
       
   373 			(*iArray)[i].Operation().DeleteBuffer();
       
   374 			}
       
   375 		delete iArray;
       
   376 		}
       
   377     }
       
   378 
       
   379 EXPORT_C void CImQueuedList::SetFolder(TMsvId  aFolderId) 
       
   380     { 
       
   381     iFolderId = aFolderId;
       
   382     }
       
   383 
       
   384 EXPORT_C void CImQueuedList::ResetLineCounter() 
       
   385     { 
       
   386     iLine = 0; 
       
   387     }
       
   388 
       
   389 EXPORT_C TQueuedOperation& CImQueuedList::operator[](TInt anIndex)
       
   390     {
       
   391     return (*iArray)[anIndex];
       
   392     }
       
   393 
       
   394 EXPORT_C TInt CImQueuedList::CountOperations() const
       
   395     {
       
   396     return iArray->Count();
       
   397     }
       
   398 
       
   399 EXPORT_C const CImOffLineOperation& CImQueuedList::Operation(TInt aIndex) const
       
   400     {
       
   401     return iArray->At(aIndex).Operation();
       
   402     }
       
   403 
       
   404 EXPORT_C void CImQueuedList::AppendOperationL(const CImOffLineOperation& aOperation)
       
   405     {
       
   406     TQueuedOperation *operation=TQueuedOperation::NewL(iFolderId, iLine, aOperation);
       
   407     CleanupStack::PushL(operation);
       
   408     iArray->AppendL(*operation);
       
   409     operation->Operation().DetachMtmParameters();
       
   410     CleanupStack::Pop();//operation
       
   411     delete operation;
       
   412     iLine++;
       
   413     }
       
   414 
       
   415 EXPORT_C void CImQueuedList::Delete(TInt aIndex)
       
   416     {
       
   417     (*iArray)[aIndex].Operation().DeleteBuffer();
       
   418     iArray->Delete(aIndex);
       
   419     }
       
   420 
       
   421 EXPORT_C void CImQueuedList::Reset()
       
   422     {
       
   423     TInt i;
       
   424     TInt nr = iArray->Count();
       
   425     for (i=0;i<nr;i++)
       
   426         {
       
   427         (*iArray)[i].Operation().DeleteBuffer();
       
   428         }
       
   429     iArray->Reset();
       
   430     }
       
   431 
       
   432 EXPORT_C void CImQueuedList::AppendL(TQueuedOperation& aOperation)
       
   433     {
       
   434     iArray->AppendL(aOperation);
       
   435     aOperation.Operation().DetachMtmParameters();
       
   436     }
       
   437 
       
   438 //
       
   439 // CImOperationQueueList
       
   440 //
       
   441 // definition of class CImOperationQueueList. This class is responsible for gathering all
       
   442 // the queued information of a MTM service, traversing folders to gather that
       
   443 // information. It will then give access to the queued operations in the list, allowing
       
   444 // queued elements to be deleted.
       
   445 //
       
   446 
       
   447 EXPORT_C CImOperationQueueList* CImOperationQueueList::NewL(CMsvEntry& aServiceEntry, MImUndoOffLineOperation *aImUndoOffLineOperation)
       
   448 //
       
   449 // Create new list of queued operations for service entry aServiceEntry is set to.
       
   450 //
       
   451 	{
       
   452 	CImOperationQueueList* self = new (ELeave) CImOperationQueueList(aServiceEntry, aImUndoOffLineOperation);
       
   453 	CleanupStack::PushL(self);
       
   454 	self->ConstructL();
       
   455 	CleanupStack::Pop();//self
       
   456 	return self;
       
   457 	}
       
   458 
       
   459 EXPORT_C CImOperationQueueList::~CImOperationQueueList() 
       
   460 	{
       
   461 	delete iServiceEntry;
       
   462 	delete iQueuedList;
       
   463 	delete iDeletedList;
       
   464 	}
       
   465 
       
   466 CImOperationQueueList::CImOperationQueueList(CMsvEntry& aServiceEntry, MImUndoOffLineOperation *aImUndoOffLineOperation) 
       
   467 	: iServiceEntry(&aServiceEntry) , iUndoOffline(aImUndoOffLineOperation)
       
   468 	{
       
   469 	iServiceId = iServiceEntry->Entry().Id();
       
   470 	};
       
   471 
       
   472 void CImOperationQueueList::ProcessFoldersL()
       
   473 //
       
   474 // Usage: reset iQueuedList, set iServiceEntry to the service entry, and 
       
   475 // call this function if a complete list of all queued operations stored
       
   476 // under the folders within the service is needed.
       
   477 //
       
   478 	{
       
   479 	__ASSERT_DEBUG( iServiceEntry->Entry().iType == KUidMsvFolderEntry ||
       
   480 				    iServiceEntry->Entry().iType == KUidMsvServiceEntry, gPanic(EOffOpEntryShouldBeFolder));
       
   481 	CMsvEntrySelection* selection = iServiceEntry->ChildrenWithTypeL(KUidMsvFolderEntry);
       
   482 	CleanupStack::PushL(selection);
       
   483 
       
   484 	TInt folder;
       
   485 	TInt nr = selection->Count();
       
   486 	for ( folder = 0 ; folder < nr; folder ++ )
       
   487 		{
       
   488 		iServiceEntry->SetEntryL( (*selection)[ folder ] );
       
   489 		RestoreQueuedListL(*iQueuedList);
       
   490 		ProcessFoldersL();
       
   491 		}
       
   492 
       
   493 	CleanupStack::PopAndDestroy();//selection
       
   494 	}
       
   495 
       
   496 void CImOperationQueueList::ConstructL()
       
   497 //
       
   498 // Create the list of queued operations.
       
   499 //
       
   500 	{
       
   501     iQueuedList  = CImQueuedList::NewL();
       
   502     iDeletedList = CImQueuedList::NewL();
       
   503     
       
   504     iDeletedList->Reset();
       
   505 	iQueuedList->Reset();
       
   506 	ProcessFoldersL();
       
   507 	}
       
   508 
       
   509 EXPORT_C void CImOperationQueueList::DeleteL(TInt aLine)
       
   510 //
       
   511 // Remove operation from list of queued operations locally.
       
   512 //
       
   513 	{
       
   514 	TQueuedOperation deletedOperation;
       
   515     deletedOperation.CopyL((*iQueuedList)[aLine]);
       
   516 	iQueuedList->Delete(aLine);
       
   517 	iDeletedList->AppendL(deletedOperation);
       
   518 	}
       
   519 
       
   520 void CImOperationQueueList::RestoreQueuedListL(CImQueuedList &aList)
       
   521 //
       
   522 // Append contents of current entry (pointed to by iServiceEntry)
       
   523 // to aList.
       
   524 //	
       
   525 	{
       
   526 	__ASSERT_DEBUG( iServiceEntry->Entry().iMtm  == KUidMsgTypeIMAP4, gPanic(EOffOpBadMtmTypeUid));
       
   527 	__ASSERT_DEBUG( iServiceEntry->Entry().iType == KUidMsvFolderEntry ||
       
   528 				    iServiceEntry->Entry().iType == KUidMsvServiceEntry, gPanic(EOffOpEntryShouldBeFolder));
       
   529 
       
   530     TInt err=KErrNone;
       
   531     CMsvStore* store=NULL;
       
   532 // Leaves with KErrNotFound if no store exists.
       
   533 	TRAP(err,store=iServiceEntry->ReadStoreL());
       
   534  	if (err)
       
   535         return;
       
   536     CleanupStack::PushL(store);
       
   537 
       
   538     aList.SetFolder(iServiceEntry->Entry().Id());
       
   539     aList.ResetLineCounter();
       
   540 
       
   541     CImOffLineArrayStore internaliser(aList);
       
   542     internaliser.RestoreL(*store);
       
   543     CleanupStack::PopAndDestroy();//store
       
   544 	}
       
   545 
       
   546 void CImOperationQueueList::StoreQueuedListL(CImQueuedList &aList)
       
   547 //
       
   548 // Store contents of aList back in current entry (pointed to by iServiceEntry)
       
   549 // to aList.
       
   550 //	
       
   551 	{
       
   552 	__ASSERT_DEBUG( iServiceEntry->Entry().iMtm  == KUidMsgTypeIMAP4, gPanic(EOffOpBadMtmTypeUid));
       
   553 	__ASSERT_DEBUG( iServiceEntry->Entry().iType == KUidMsvFolderEntry ||
       
   554 				    iServiceEntry->Entry().iType == KUidMsvServiceEntry, gPanic(EOffOpEntryShouldBeFolder));
       
   555 	CMsvStore* store = iServiceEntry->EditStoreL();
       
   556 	CleanupStack::PushL(store);
       
   557     CImOffLineArrayStore externaliser(aList);
       
   558     externaliser.StoreL(*store);
       
   559 	store->CommitL();
       
   560 	CleanupStack::PopAndDestroy();//store
       
   561 	}
       
   562 
       
   563 EXPORT_C void CImOperationQueueList::ExpungeDeletedOperationsL()
       
   564 //
       
   565 // Remove the queued operations that were marked as deleted from the folder stores.
       
   566 //
       
   567 	{
       
   568     // First sort so that each store only has to be visited once, and queued operations
       
   569     // can be deleted back-to-front. Starting at the back leaves the other delete commands
       
   570     // valid.
       
   571     TQueuedOperationKey key(*iDeletedList);
       
   572 	TQueuedOperationSwap swap(*iDeletedList);
       
   573 	User::QuickSort(iDeletedList->CountOperations(),key,swap);
       
   574 
       
   575     // Current folder being updated
       
   576     TMsvId lastFolderRead = KMsvNullIndexEntryId;
       
   577     // list holds the list of queued operations for the current folder
       
   578     CImQueuedList *list = CImQueuedList::NewL();
       
   579 	CleanupStack::PushL(list);
       
   580 
       
   581 	TInt line;
       
   582 
       
   583 	TInt nr = iDeletedList->CountOperations();
       
   584 	for ( line = 0 ; line < nr; line ++ )
       
   585 		{
       
   586 		// Get item to delete
       
   587 		TQueuedOperation toDelete;
       
   588         toDelete.CopyL((*iDeletedList)[ 0 ]);
       
   589 		iDeletedList->Delete(0);
       
   590 
       
   591 		// See if item belongs to different folder.
       
   592 		if (lastFolderRead != toDelete.FolderId())
       
   593 			{
       
   594 			// Store changes to previous list
       
   595 			if (lastFolderRead != KMsvNullIndexEntryId)
       
   596 				{
       
   597 				StoreQueuedListL(*list);
       
   598 				}
       
   599  
       
   600 			// go to folder to delete item from.
       
   601 			iServiceEntry->SetEntryL(toDelete.FolderId());
       
   602 			__ASSERT_DEBUG( iServiceEntry->Entry().iMtm  == KUidMsgTypeIMAP4, gPanic(EOffOpBadMtmTypeUid));
       
   603 			__ASSERT_DEBUG(iServiceEntry->Entry().iType == KUidMsvFolderEntry, gPanic(EOffOpEntryShouldBeFolder));
       
   604 
       
   605             // Initialise for the next folder
       
   606 			lastFolderRead = toDelete.FolderId();
       
   607 			// Get the list of queued operations
       
   608 			list->Reset();
       
   609 			RestoreQueuedListL(*list);
       
   610 			}
       
   611 
       
   612         // Sanity check: the data contained in toDelete should be EXACTLY the same as 
       
   613         // the queued operation it refers to (as retrieved from the folder)
       
   614         if (toDelete != (*list)[ toDelete.OperationIndex() ])
       
   615 			{
       
   616 			gPanic(EOffOpListOutOfSync);
       
   617 			continue;
       
   618 			}
       
   619 
       
   620         // Undo changes made in server to reflect the disconnected operation.
       
   621 		iUndoOffline->UndoOffLineChangesL(toDelete.Operation(), toDelete.FolderId());
       
   622 		// Delete queued operation from list
       
   623         list->Delete(toDelete.OperationIndex());
       
   624 		}
       
   625 
       
   626 	// Store changes to last folder.
       
   627 	if (lastFolderRead != KMsvNullIndexEntryId)
       
   628 		{
       
   629 		StoreQueuedListL(*list);
       
   630 		}
       
   631 	CleanupStack::PopAndDestroy(); //list
       
   632     }
       
   633 
       
   634 //
       
   635 // TQueuedOperationSwap
       
   636 EXPORT_C TQueuedOperationSwap::TQueuedOperationSwap(CImQueuedList& aList) 
       
   637     : iList(aList) 
       
   638     {
       
   639     };
       
   640 
       
   641 void TQueuedOperationSwap::Swap(TInt aLeft,TInt aRight) const
       
   642 	{
       
   643     Mem::Swap(&iList[aLeft],&iList[aRight],sizeof(TQueuedOperation));
       
   644     }
       
   645 
       
   646 //
       
   647 // TQueuedOperationKey
       
   648 EXPORT_C TQueuedOperationKey::TQueuedOperationKey(CImQueuedList& aList) 
       
   649     : iList(aList) 
       
   650     {
       
   651     }
       
   652 
       
   653 TInt TQueuedOperationKey::Compare(TInt aLeft,TInt aRight) const
       
   654 	{
       
   655 	if (aLeft == aRight)
       
   656 		return 0;
       
   657 	if (iList[ aLeft ].FolderId() != iList[ aRight ].FolderId())
       
   658 		return iList[ aLeft ].FolderId() - iList[ aRight ].FolderId();
       
   659 	// Sort in descending order, so last lines will be deleted first
       
   660 	TInt diff = iList[ aRight ].OperationIndex() - iList[ aLeft ].OperationIndex();
       
   661 	__ASSERT_DEBUG(diff != 0, gPanic(EOffOpTwoSameLinesNotAllowed));
       
   662 	return diff;
       
   663 	}
       
   664 TAny *TQueuedOperationKey::At(TInt anIndex) const
       
   665 	{
       
   666 	return &iList[ anIndex ];
       
   667 	}
       
   668 
       
   669