email/pop3andsmtpmtm/popservermtm/src/POPSOFFL.CPP
changeset 0 72b543305e3a
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 
       
     2 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 // All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 //
       
     9 // Initial Contributors:
       
    10 // Nokia Corporation - initial contribution.
       
    11 //
       
    12 // Contributors:
       
    13 //
       
    14 // Description:
       
    15 //
       
    16 
       
    17 #include <msventry.h>
       
    18 #include <offop.h>
       
    19 #include "POPSOFFL.H"
       
    20 #include "popstran.h"
       
    21 #include "POPS.PAN"
       
    22 
       
    23 // API
       
    24 // ===
       
    25 // The CImPop3OfflineOperationFinder class is used to find and order offline
       
    26 // operations. It can also be used to obtain progress information eg. the
       
    27 // number of operations queued of a particular type.
       
    28 
       
    29 // Offline operations are retrieved by first calling the asynchronous
       
    30 // FindFirstL function. After completetion call the OperationFound function
       
    31 // to find out whether or not an offline operation has been found, if it has
       
    32 // then the OfflineOperation function should be called to retrive it.
       
    33 //
       
    34 // The FindNextL function should be called to find other offline operations
       
    35 // (in conjunction with the OperationFound and OfflineOperations functions.)
       
    36 // It should be noted that the FindNextL function is synchronous.
       
    37 
       
    38 // The DeleteCurrentOperationL() function deletes the current entry from the
       
    39 // message store.
       
    40 
       
    41 // OperationDetails returns TOperationDetails which can be used for providing
       
    42 // progress information.
       
    43 
       
    44 
       
    45 // Implementaiton
       
    46 // ==============
       
    47 // The asynchronous FindFirstL function builds up a list of
       
    48 // CImOffLineOperationArray objects, each array holds a list of operations
       
    49 // of a particular type.
       
    50 
       
    51 // The operations are stored this way to facilitate easy ordering based on
       
    52 // operation type as well as being useful for generating progress
       
    53 // information.
       
    54 
       
    55 // The operations are retrieved by first visiting each message under the
       
    56 // service, this potentially slow operation is handled by the asynchronous
       
    57 // function.
       
    58 
       
    59 CImPop3OfflineOperationFinder* CImPop3OfflineOperationFinder::NewL(CMsvServerEntry& aEntry)
       
    60 	{
       
    61 	CImPop3OfflineOperationFinder* self = NewLC(aEntry);
       
    62 	CleanupStack::Pop(); // self
       
    63 	return self;
       
    64 	}
       
    65 
       
    66 CImPop3OfflineOperationFinder* CImPop3OfflineOperationFinder::NewLC(CMsvServerEntry& aEntry)
       
    67 	{
       
    68 	CImPop3OfflineOperationFinder* self = new (ELeave) CImPop3OfflineOperationFinder(aEntry);
       
    69 	CleanupStack::PushL(self);
       
    70 	self->ConstructL();
       
    71 	return self;
       
    72 	}
       
    73 
       
    74 void CImPop3OfflineOperationFinder::FindFirstL(TMsvId aServiceId, TBool aQuitting, TRequestStatus &aStatus)
       
    75 // Asynchronous function for finding all the offline operations and setting
       
    76 // the current operation (iOperationArrayIndex and iOperationIndex) to point
       
    77 // to the first one.
       
    78 
       
    79 // Use OperationFound(), OfflineOperation() and OperationDetails() to access
       
    80 // the results of this search.
       
    81 	{
       
    82 	TInt index = 0;
       
    83 	// Delete each of the CImOffLineOperationArrays
       
    84 	while (index < iOfflineOperations->Count())
       
    85 		{
       
    86 		delete (*iOfflineOperations)[index];
       
    87 		index++;
       
    88 		}
       
    89 	iOfflineOperations->Reset();
       
    90 
       
    91 	iServiceId = aServiceId;
       
    92 	iState = EPopsOffOpLookingForMessages;
       
    93 	iQuitting = aQuitting;
       
    94 
       
    95 	if (iChildMessages)
       
    96 		{
       
    97 		delete iChildMessages;
       
    98 		iChildMessages = 0;
       
    99 		}
       
   100 
       
   101 	iChildMessages = new (ELeave) CMsvEntrySelection();
       
   102 
       
   103 	User::LeaveIfError(iEntry.GetChildren(*iChildMessages));
       
   104 	iMessageIndex = 0;
       
   105 	Queue(aStatus);
       
   106 	if (iChildMessages->Count())
       
   107 		{
       
   108 		// Check the first message for offline operations.
       
   109 		CheckNextChildMessageL();
       
   110 		}
       
   111 	else
       
   112 		{
       
   113 		// There are no messages found so complete and stop searching here.
       
   114 		delete iChildMessages;
       
   115 		iChildMessages = 0;
       
   116 		Complete(KErrNone);
       
   117 		}
       
   118 	}
       
   119 
       
   120 void CImPop3OfflineOperationFinder::CheckNextChildMessageL()
       
   121 // Check the current message (iMessageIndex) and append any offline operations
       
   122 // to the offline operations list.
       
   123 	{
       
   124 	if (iMessageIndex < iChildMessages->Count())
       
   125 		{
       
   126 		iEntry.SetEntry((*iChildMessages)[iMessageIndex]);
       
   127 		TMsvEmailEntry entry = iEntry.Entry();
       
   128 		if (entry.DisconnectedOperation() != ENoDisconnectedOperations)
       
   129 			// If the entry has offline operations queued then add it to the list.
       
   130 			{
       
   131 			AppendOfflineOpsL();
       
   132 			}
       
   133 		}
       
   134 
       
   135 	SetActive();
       
   136 	TRequestStatus* status = &iStatus;
       
   137 	User::RequestComplete(status, KErrNone);
       
   138 	}
       
   139 
       
   140 void CImPop3OfflineOperationFinder::AppendOfflineOpsL()
       
   141 // This private help function appends the offline operations associated with the
       
   142 // current message to the appropriate offline operations array.
       
   143 // The array to which it is added depends on the operation type. If there
       
   144 // is currently no array for this operation type then one is created.
       
   145 	{
       
   146 	// Get the offline operations for the current message.
       
   147 	CImOffLineOperationArray* localOfflineOpArray = CImOffLineOperationArray::NewL();
       
   148 	CleanupStack::PushL(localOfflineOpArray);
       
   149 	CImOffLineArrayStore* offlineArrayStore = new (ELeave) CImOffLineArrayStore(*localOfflineOpArray);
       
   150 	CleanupStack::PushL(offlineArrayStore);
       
   151 	CMsvStore* messageStore = iEntry.ReadStoreL();
       
   152 	CleanupStack::PushL(messageStore);
       
   153 	offlineArrayStore->RestoreL(*messageStore);
       
   154 	
       
   155 	// Append the local offline operations to the correct operations list.
       
   156 	TInt opCounter;
       
   157 	TInt offlineOps = localOfflineOpArray->CountOperations();
       
   158 	const CImOffLineOperation* newOperation;
       
   159 	for (opCounter = 0; opCounter < offlineOps; opCounter++)
       
   160 		{
       
   161 		newOperation = &localOfflineOpArray->Operation(opCounter);
       
   162 		// Append newOperation to the correct list as each list holds a different operation type.
       
   163 
       
   164 		// Find the appropriate offline operation list.
       
   165 		CImOffLineOperationArray* operationArray = 0;
       
   166 		if (iOfflineOperations->Count() == 0)
       
   167 			{
       
   168 			// If there are no arrays then create the first one.
       
   169 			operationArray = CImOffLineOperationArray::NewL();
       
   170 			CleanupStack::PushL(operationArray);
       
   171 			iOfflineOperations->AppendL(operationArray, sizeof(void*));
       
   172 			CleanupStack::Pop(operationArray);
       
   173 			}
       
   174 		else
       
   175 			{
       
   176 			TBool found = EFalse;
       
   177 			TInt index = 0;
       
   178 			// Search the different arrays for one that contains the correct operation types.
       
   179 			while ((!found) && (index < iOfflineOperations->Count()))
       
   180 				{
       
   181 				if ((*iOfflineOperations)[index]->CountOperations())
       
   182 					{
       
   183 					if (((*iOfflineOperations)[index]->Operation(0)).OpType() == newOperation->OpType())
       
   184 						{
       
   185 						found = ETrue;
       
   186 						operationArray = (*iOfflineOperations)[index];
       
   187 						}
       
   188 					}
       
   189 				index++;
       
   190 				}
       
   191 
       
   192 			if (!found)
       
   193 				{
       
   194 				// If there are no appropriate arrays then create a new one.
       
   195 				operationArray = CImOffLineOperationArray::NewL();
       
   196 				CleanupStack::PushL(operationArray);
       
   197 				iOfflineOperations->AppendL(operationArray, sizeof(void*));
       
   198 				CleanupStack::Pop(operationArray);
       
   199 				}
       
   200 			}
       
   201 
       
   202 		operationArray->AppendOperationL(*newOperation);
       
   203 		}
       
   204 
       
   205 	CleanupStack::PopAndDestroy(3); // offlineArrayStore, messageStore, localOfflineOperationArray
       
   206 	}
       
   207 
       
   208 
       
   209 TBool CImPop3OfflineOperationFinder::AppropriateOperation(const CImOffLineOperation& aOperation) const
       
   210 	{
       
   211 // Returns true if the operation should be run at this point.
       
   212 // Delete operations should be run at the end of the session, all others at the start.
       
   213 	return (aOperation.OpType()==CImOffLineOperation::EOffLineOpDelete) ? iQuitting : (!iQuitting);
       
   214 	}
       
   215 
       
   216 
       
   217 void CImPop3OfflineOperationFinder::FindNext()
       
   218 // Finds the next offline operations.
       
   219 // The results of this function call are valid as soon as the function returns.
       
   220 	{
       
   221 	TBool go = ETrue;
       
   222 
       
   223 	CImOffLineOperationArray* operationArray = 0;
       
   224 	iOperationIndex++;
       
   225 	while (go)
       
   226 		{
       
   227 		go = ETrue;
       
   228 
       
   229 		if (iOfflineOperations->Count())
       
   230 			{
       
   231 			operationArray = (*iOfflineOperations)[iOperationArrayIndex];
       
   232 			}
       
   233 		else
       
   234 			{
       
   235 			operationArray = 0;
       
   236 			}
       
   237 
       
   238 		if (operationArray == 0)
       
   239 			{
       
   240 			go = EFalse;
       
   241 			}
       
   242 		else if (iOperationIndex == operationArray->CountOperations())
       
   243 		// If there are no more operations in this array then move on to the next one.
       
   244 			{
       
   245 			iOperationArrayIndex++;
       
   246 			iOperationIndex = 0;
       
   247 			}
       
   248 		else if (!AppropriateOperation(operationArray->Operation(0)))
       
   249 		// If the operations in this array aren't of an appropriate type then move on to the next one.
       
   250 			{
       
   251 			iOperationArrayIndex++;
       
   252 			iOperationIndex = 0;
       
   253 			}
       
   254 		else
       
   255 		// An appropriate operation has been found.
       
   256 			{
       
   257 			go = EFalse;
       
   258 			}
       
   259 
       
   260 		if (iOperationArrayIndex == iOfflineOperations->Count())
       
   261 		// If there are no more operation arrays then don't carry on looking.
       
   262 			{
       
   263 			go = EFalse;
       
   264 			}
       
   265 		}
       
   266 
       
   267 	// Set the operaitons details for later.
       
   268 	if (OperationFound())
       
   269 		{
       
   270 		iOperationDetails.iOpType = OfflineOperation().OpType();
       
   271 		iOperationDetails.iOperationNumber = iOperationIndex;
       
   272 		iOperationDetails.iOperationsOfType = ((*iOfflineOperations)[iOperationArrayIndex])->CountOperations();
       
   273 		}
       
   274 	else
       
   275 		{
       
   276 		iOperationDetails.iOpType = CImOffLineOperation::EOffLineOpNone;
       
   277 		}
       
   278 	}
       
   279 
       
   280 TBool CImPop3OfflineOperationFinder::OperationFound() const
       
   281 // Returns true if an operation has been found.
       
   282 	{
       
   283 	return (iOperationArrayIndex < (iOfflineOperations->Count()));
       
   284 	}
       
   285 
       
   286 const CImOffLineOperation& CImPop3OfflineOperationFinder::OfflineOperation() const
       
   287 // Returns the current offline operations.
       
   288 	{
       
   289 	return ((*iOfflineOperations)[iOperationArrayIndex])->Operation(iOperationIndex);
       
   290 	}
       
   291 
       
   292 const CImPop3OfflineOperationFinder::TOperationDetails& CImPop3OfflineOperationFinder::OperationDetails() const
       
   293 // Returns the details for the current operation.
       
   294 	{
       
   295 	return iOperationDetails;
       
   296 	}
       
   297 
       
   298 CImPop3OfflineOperationFinder::~CImPop3OfflineOperationFinder()
       
   299 	{
       
   300 	delete iChildMessages;
       
   301 	TInt index = 0;
       
   302 	if (iOfflineOperations)
       
   303 		{
       
   304 		// Delete each of the CImOffLineOperationArrays
       
   305 		while (index < iOfflineOperations->Count())
       
   306 			{
       
   307 			delete (*iOfflineOperations)[index];
       
   308 			index++;
       
   309 			}
       
   310 		delete iOfflineOperations;
       
   311 		}
       
   312 	}
       
   313 
       
   314 void CImPop3OfflineOperationFinder::DoRunL()
       
   315 	{
       
   316 	++iMessageIndex;
       
   317 	if (iMessageIndex < iChildMessages->Count())
       
   318 		// If there are more messages then check them for offline operations.
       
   319 		{
       
   320 		CheckNextChildMessageL();
       
   321 		}
       
   322 	else
       
   323 		// If there are no more messages then go back and find all the offline operations.
       
   324 		{
       
   325 		delete iChildMessages;
       
   326 		iChildMessages = 0;
       
   327 
       
   328 		// Move the offline copy opertion array to the front of the list.
       
   329 		TInt index = 0;
       
   330 		TBool go = ETrue;
       
   331 		while ((index < iOfflineOperations->Count())
       
   332 				&& go)
       
   333 			{
       
   334 			CImOffLineOperation::TOffLineOpType opType = ((*iOfflineOperations)[index]->Operation(0)).OpType();
       
   335 			if (opType == CImOffLineOperation::EOffLineOpCopyToLocal)
       
   336 				{
       
   337 				// Move the offline copy operation array to the front of the list.
       
   338 				go = EFalse;
       
   339 				CImOffLineOperationArray* populateOperationList = (*iOfflineOperations)[index];
       
   340 				iOfflineOperations->Delete(index);
       
   341 				iOfflineOperations->InsertL(index, populateOperationList, sizeof(void*));
       
   342 				}
       
   343 			else
       
   344 				{
       
   345 				index++;
       
   346 				}
       
   347 			}
       
   348 
       
   349 		// Move the offline populate opertion array to the front of the list.
       
   350 		index = 0;
       
   351 		go = ETrue;
       
   352 		while ((index < iOfflineOperations->Count())
       
   353 				&& go)
       
   354 			{
       
   355 			CImOffLineOperation::TOffLineOpType opType = ((*iOfflineOperations)[index]->Operation(0)).OpType();
       
   356 			if (opType == CImOffLineOperation::EOffLineOpCopyWithinService)
       
   357 				{
       
   358 				// Move the offline populate operation array to the front of the list.
       
   359 				go = EFalse;
       
   360 				CImOffLineOperationArray* populateOperationList = (*iOfflineOperations)[index];
       
   361 				iOfflineOperations->Delete(index);
       
   362 				iOfflineOperations->InsertL(index, populateOperationList, sizeof(void*));
       
   363 				}
       
   364 			else
       
   365 				{
       
   366 				index++;
       
   367 				}
       
   368 			}
       
   369 
       
   370 		// Set the iOperationIndex to the first appropriate operation.
       
   371 		iOperationArrayIndex = 0;
       
   372 		iOperationIndex = -1;
       
   373 		FindNext();
       
   374 
       
   375 		Complete(KErrNone);
       
   376 		}
       
   377 	}
       
   378 
       
   379 void CImPop3OfflineOperationFinder::DoCancel()
       
   380 	{
       
   381 	CMsgActive::DoCancel();
       
   382 	}
       
   383 
       
   384 void CImPop3OfflineOperationFinder::DoComplete()
       
   385 	{
       
   386 
       
   387 	}
       
   388 
       
   389 void CImPop3OfflineOperationFinder::ConstructL()
       
   390 	{
       
   391 	CActiveScheduler::Add(this);
       
   392 	iOfflineOperations = new (ELeave) CArrayVarFlat<CImOffLineOperationArray*>(3);
       
   393 	}
       
   394 
       
   395 CImPop3OfflineOperationFinder::CImPop3OfflineOperationFinder(CMsvServerEntry& aEntry) : CMsgActive(EPriorityStandard), iEntry(aEntry)
       
   396 	{
       
   397 
       
   398 	}
       
   399 
       
   400 
       
   401 
       
   402 
       
   403 
       
   404 
       
   405 // API
       
   406 // ===
       
   407 // The CImPop3SetOfflineOps class provides a means of asynchronously adding
       
   408 // offline operations to the message stores of the appropriate messages.
       
   409 
       
   410 // Use the AddOfflineOperationL to add the offline operations.
       
   411 
       
   412 
       
   413 CImPop3SetOfflineOps* CImPop3SetOfflineOps::NewL(CMsvServerEntry& aEntry)
       
   414 	{
       
   415 	CImPop3SetOfflineOps* self = NewLC(aEntry);
       
   416 	CleanupStack::Pop(); // self
       
   417 	return self;
       
   418 	}
       
   419 
       
   420 CImPop3SetOfflineOps* CImPop3SetOfflineOps::NewLC(CMsvServerEntry& aEntry)
       
   421 	{
       
   422 	CImPop3SetOfflineOps* self = new (ELeave) CImPop3SetOfflineOps(aEntry);
       
   423 	CleanupStack::PushL(self);
       
   424 	self->ConstructL();
       
   425 	CActiveScheduler::Add(self);
       
   426 	//	ConstructL();
       
   427 	return self;
       
   428 	}
       
   429 
       
   430 void CImPop3SetOfflineOps::AddOfflineOperationL(const CMsvEntrySelection *aMessageSelection,
       
   431 							CImOffLineOperation::TOffLineOpType aOperationType,
       
   432 							TMsvId aTargetFolderId,
       
   433 							TRequestStatus& aStatus)
       
   434 // Adds the aOperationType operation to each message in aMessageSelection.
       
   435 // The aTargetFolderId is not used for some operation types, eg. deleting.
       
   436 	{
       
   437 	iState = EAddingOfflineOperations;
       
   438 
       
   439 	iMessageCounter = 0;
       
   440 	iOperationType = aOperationType;
       
   441 	iDestinationEntryId = aTargetFolderId;
       
   442 
       
   443 	delete iSourceMessages;
       
   444 	iSourceMessages = 0;
       
   445 
       
   446 	delete iMessagesToCopyLocally;
       
   447 	iMessagesToCopyLocally = new (ELeave) CMsvEntrySelection;
       
   448 
       
   449 	iSourceMessages = aMessageSelection->CopyL();
       
   450 	
       
   451 	TInt count = iSourceMessages->Count();
       
   452 	iOfflineOperationArrayFlag.Reset();
       
   453 	
       
   454 	for(TInt i=0; i< count; ++i )
       
   455 		{
       
   456 		iOfflineOperationArrayFlag.AppendL(EFalse);	
       
   457 		}
       
   458 	
       
   459 	
       
   460 	Queue(aStatus);
       
   461 
       
   462 	AddOfflineOperationL();
       
   463 	}
       
   464 
       
   465 
       
   466 void CImPop3SetOfflineOps::CancelOfflineOperationsL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
       
   467 // Cancel all pending operations on each message in aSelection.
       
   468 	{
       
   469 	iState = ECancellingOfflineOperations;
       
   470 	iMessageCounter = 0;
       
   471 	
       
   472 	delete iSourceMessages;
       
   473 	iSourceMessages = 0;
       
   474 
       
   475 	iSourceMessages = aSelection.CopyL();
       
   476 	Queue(aStatus);
       
   477 
       
   478 	CancelOfflineOperationL();
       
   479 	}
       
   480 
       
   481 // Resumes a cancelled "Cancel Offline Operations" operation.
       
   482 void CImPop3SetOfflineOps::ResumeCancelOfflineOperationsL(TRequestStatus& aStatus)
       
   483 	{
       
   484 	Queue(aStatus);
       
   485 	CancelOfflineOperationL();
       
   486 	}
       
   487 
       
   488 void CImPop3SetOfflineOps::AddOfflineOperationL()
       
   489 	{
       
   490 	// Set the current entry, ready for the operation to be attached to it.
       
   491 	User::LeaveIfError(iEntry.SetEntry((*iSourceMessages)[iMessageCounter]));
       
   492 
       
   493 	iModifiedOperationType = iOperationType;
       
   494 
       
   495 	if ((iEntry.Entry()).Complete())
       
   496 	// Any messages that have already been populated can be copied locally without
       
   497 	// the need to be online.
       
   498 	// This is done after any offline operations have been added but they are
       
   499 	// saved for later here:
       
   500 		{
       
   501 		if (iOperationType == CImOffLineOperation::EOffLineOpCopyToLocal)
       
   502 			{
       
   503 			iMessagesToCopyLocally->AppendL(iEntry.Entry().Id());
       
   504 			iModifiedOperationType = CImOffLineOperation::EOffLineOpNone;
       
   505 			}
       
   506 
       
   507 		if (iOperationType == CImOffLineOperation::EOffLineOpMoveToLocal)
       
   508 			{
       
   509 			iMessagesToCopyLocally->AppendL(iEntry.Entry().Id());
       
   510 			iModifiedOperationType = CImOffLineOperation::EOffLineOpDelete;
       
   511 			}
       
   512 		}
       
   513 
       
   514 	if (iModifiedOperationType == CImOffLineOperation::EOffLineOpNone)
       
   515 		{
       
   516 		iStatus = KRequestPending;
       
   517 		SetActive();
       
   518 		TRequestStatus* status = &iStatus;
       
   519 		User::RequestComplete(status, KErrNone);
       
   520 		return;
       
   521 		}
       
   522 
       
   523 	CImOffLineOperationArray* operationArray = CImOffLineOperationArray::NewL();
       
   524 	CleanupStack::PushL(operationArray);
       
   525 	CImOffLineArrayStore* operationStore = new (ELeave) CImOffLineArrayStore(*operationArray);
       
   526 	CleanupStack::PushL(operationStore);
       
   527 	CMsvStore* messageStore = iEntry.EditStoreL();
       
   528 	CleanupStack::PushL(messageStore);
       
   529 
       
   530 	// Get the array of operations currently attached to the message.
       
   531 	operationStore->RestoreL(*messageStore);
       
   532 
       
   533 	// If the operation is a move or delete then ensure that it doesn't interfere with any existing operations.
       
   534 	if ((iModifiedOperationType == CImOffLineOperation::EOffLineOpMoveToLocal)
       
   535 		|| (iModifiedOperationType == CImOffLineOperation::EOffLineOpDelete))
       
   536 		{
       
   537 		// Find out if there is a move or a delete operation already pending on the message.
       
   538 		TBool moveOrDeleteAlreadyPending = EFalse;
       
   539 		CImOffLineOperation::TOffLineOpType opType;
       
   540 		TInt counter = operationArray->CountOperations();
       
   541 
       
   542 		while (counter > 0)
       
   543 			{
       
   544 			counter--;
       
   545 			opType = (operationArray->Operation(counter)).OpType();
       
   546 			if ((opType == CImOffLineOperation::EOffLineOpMoveToLocal)
       
   547 				|| (opType == CImOffLineOperation::EOffLineOpDelete))
       
   548 				{
       
   549 				moveOrDeleteAlreadyPending = ETrue;
       
   550 				counter = 0;
       
   551 				}
       
   552 			}
       
   553 
       
   554 		if (moveOrDeleteAlreadyPending)
       
   555 			{
       
   556 			if (iModifiedOperationType == CImOffLineOperation::EOffLineOpMoveToLocal)
       
   557 				{
       
   558 				// Change the move operation to a copy, it will be deleted by the existing move or delete.
       
   559 				iModifiedOperationType = CImOffLineOperation::EOffLineOpCopyToLocal;
       
   560 				}
       
   561 
       
   562 			if (iModifiedOperationType == CImOffLineOperation::EOffLineOpDelete)
       
   563 				{
       
   564 				// No need to append this delete operation as it will be delete be the existing move or delete.
       
   565 				iModifiedOperationType = CImOffLineOperation::EOffLineOpNone;
       
   566 				}
       
   567 			}
       
   568 		}
       
   569 
       
   570 	CImOffLineOperation* operation = new (ELeave) CImOffLineOperation();
       
   571 	CleanupStack::PushL(operation);
       
   572 
       
   573 	TMsvEmailEntry entry = iEntry.Entry();
       
   574 
       
   575 	switch (iModifiedOperationType)
       
   576 		{
       
   577 		case CImOffLineOperation::EOffLineOpCopyFromLocal:
       
   578 		case CImOffLineOperation::EOffLineOpMoveFromLocal:
       
   579 		case CImOffLineOperation::EOffLineOpMoveWithinService:
       
   580 		case CImOffLineOperation::EOffLineOpChange:
       
   581 		case CImOffLineOperation::EOffLineOpCreate:
       
   582 		case CImOffLineOperation::EOffLineOpMtmSpecific:
       
   583 			User::Leave(KErrNotSupported);
       
   584 
       
   585 		case CImOffLineOperation::EOffLineOpCopyToLocal:
       
   586 			operation->SetCopyToLocal((*iSourceMessages)[iMessageCounter], iDestinationEntryId);
       
   587 			break;
       
   588 
       
   589 		case CImOffLineOperation::EOffLineOpDelete:
       
   590 			operation->SetDelete((*iSourceMessages)[iMessageCounter]);
       
   591 			break;
       
   592 
       
   593 		case CImOffLineOperation::EOffLineOpCopyWithinService:
       
   594 			operation->SetCopyWithinService((*iSourceMessages)[iMessageCounter], iDestinationEntryId);
       
   595 			break;
       
   596 
       
   597 		case CImOffLineOperation::EOffLineOpMoveToLocal:
       
   598 			operation->SetMoveToLocal((*iSourceMessages)[iMessageCounter], iDestinationEntryId);
       
   599 			break;
       
   600 
       
   601 		case CImOffLineOperation::EOffLineOpNone:
       
   602 			break;
       
   603 
       
   604 		default:
       
   605 			User::Leave(KErrNotSupported);
       
   606 		}
       
   607 	
       
   608 
       
   609 	if (iModifiedOperationType != CImOffLineOperation::EOffLineOpNone)
       
   610 		{
       
   611 		operationArray->AppendOperationL(*operation);
       
   612 		entry.SetOperation(ETrue);
       
   613 		iOfflineOperationArrayFlag[iMessageCounter] = ETrue;
       
   614 		}
       
   615 
       
   616 	CImPop3OfflineUtilities::SetOfflineFlags(*operationArray, entry);
       
   617 
       
   618 	operationStore->StoreL(*messageStore);
       
   619 	iEntry.ChangeEntry(entry);
       
   620 	messageStore->CommitL();
       
   621 	CleanupStack::PopAndDestroy(4); // operation, messageStore, operationStore, operationArray
       
   622 	iStatus = KRequestPending;
       
   623 	SetActive();
       
   624 	TRequestStatus* status = &iStatus;
       
   625 	User::RequestComplete(status, KErrNone);
       
   626 	}
       
   627 
       
   628 void CImPop3SetOfflineOps::CancelOfflineOperationL()
       
   629 	{
       
   630 	SetActive();
       
   631 
       
   632 	// Set the current entry, ready for the operation to be attached to it.
       
   633 	User::LeaveIfError(iEntry.SetEntry((*iSourceMessages)[iMessageCounter]));
       
   634 	TMsvEmailEntry entry = iEntry.Entry();
       
   635 	CImOffLineOperationArray* operationArray = CImOffLineOperationArray::NewL();
       
   636 	CleanupStack::PushL(operationArray);
       
   637 	CImOffLineArrayStore* operationStore = new (ELeave) CImOffLineArrayStore(*operationArray);
       
   638 	CleanupStack::PushL(operationStore);
       
   639 	CMsvStore* messageStore = iEntry.EditStoreL();
       
   640 	CleanupStack::PushL(messageStore);
       
   641 
       
   642 	// Get the array of operations currently attached to the message.
       
   643 	operationStore->RestoreL(*messageStore);
       
   644 
       
   645 	TInt counter = operationArray->CountOperations();
       
   646 	while (counter > 0)
       
   647 		{
       
   648 		counter--;
       
   649 		operationArray->Delete(counter);
       
   650 		}
       
   651 
       
   652 	operationStore->StoreL(*messageStore);
       
   653 	messageStore->CommitL();
       
   654 	entry.SetOperation(EFalse);
       
   655 	entry.SetDisconnectedOperation(ENoDisconnectedOperations);
       
   656 	iEntry.ChangeEntry(entry);
       
   657 	CleanupStack::PopAndDestroy(3); // messageStore, operationStore, operationArray
       
   658 	TRequestStatus* status = &iStatus;
       
   659 	User::RequestComplete(status, KErrNone);
       
   660 	}
       
   661 
       
   662 void CImPop3SetOfflineOps::CopyLocalMessageL()
       
   663 	// Copy the current local message.
       
   664 	{
       
   665 	User::LeaveIfError(iEntry.SetEntry((*iSourceMessages)[iMessageCounter]));
       
   666 	User::LeaveIfError(iEntry.SetEntry(iEntry.Entry().Parent()));
       
   667 
       
   668 	iStatus = KRequestPending;
       
   669 	iTransfer->StartL((*iSourceMessages)[iMessageCounter], iDestinationEntryId, CImPop3TransferMessage::EImPop3CopyTransfer, iStatus);
       
   670 
       
   671 	SetActive();
       
   672 	}
       
   673 
       
   674 CImPop3SetOfflineOps::~CImPop3SetOfflineOps()
       
   675 	{
       
   676 	Cancel();
       
   677 	delete iSourceMessages;
       
   678 	delete iMessagesToCopyLocally;
       
   679 	delete iTransfer;
       
   680 	iOfflineOperationArrayFlag.Close();
       
   681 	}
       
   682 
       
   683 void CImPop3SetOfflineOps::Progress(TPop3Progress& rPop3Progress) const
       
   684 	{
       
   685 	// It is only necessary to report the progress when it is in the
       
   686 	// ECopyingLocalEntries state. All other states should be near-instantaneous
       
   687 	// and a 0 filled progress will do.
       
   688 
       
   689 	switch (iState)
       
   690 		{
       
   691 		case ECopyingLocalEntries:
       
   692  			if (iOperationType == CImOffLineOperation::EOffLineOpMoveToLocal)
       
   693  				{
       
   694  				rPop3Progress.iPop3Progress = TPop3Progress::EPopMoving;
       
   695  				rPop3Progress.iPop3SubStateProgress = TPop3Progress::EPopMoving;
       
   696  				}
       
   697  			else
       
   698   				{
       
   699  				rPop3Progress.iPop3Progress = TPop3Progress::EPopCopying;
       
   700  				rPop3Progress.iPop3SubStateProgress = TPop3Progress::EPopCopying;
       
   701  				}
       
   702 			rPop3Progress.iTotalMsgs = iMessagesToCopyLocally->Count();
       
   703 			rPop3Progress.iMsgsToProcess = rPop3Progress.iTotalMsgs - iMessageCounter;
       
   704 			rPop3Progress.iBytesDone = 0;
       
   705 			rPop3Progress.iTotalBytes = 0;
       
   706 			rPop3Progress.iErrorCode = 0;
       
   707 			break;
       
   708 
       
   709 		case EAddingOfflineOperations:
       
   710 			if (iOperationType == CImOffLineOperation::EOffLineOpDelete)
       
   711 				{
       
   712 				rPop3Progress.iPop3Progress = TPop3Progress::EPopDeleting;
       
   713 				rPop3Progress.iTotalMsgs = iSourceMessages->Count();
       
   714 				rPop3Progress.iMsgsToProcess = rPop3Progress.iTotalMsgs - iMessageCounter;
       
   715 				rPop3Progress.iBytesDone = 0;
       
   716 				rPop3Progress.iTotalBytes = 0;
       
   717 				rPop3Progress.iErrorCode = 0;
       
   718 				rPop3Progress.iPop3SubStateProgress = TPop3Progress::EPopDeleting;
       
   719 				}
       
   720   			else if (iOperationType == CImOffLineOperation::EOffLineOpMoveToLocal)
       
   721  				{
       
   722  				rPop3Progress.iPop3Progress = TPop3Progress::EPopMoving;
       
   723  				rPop3Progress.iTotalMsgs = iSourceMessages->Count();
       
   724  				rPop3Progress.iMsgsToProcess = rPop3Progress.iTotalMsgs - iMessageCounter;
       
   725  				rPop3Progress.iBytesDone = 0;
       
   726 				rPop3Progress.iTotalBytes = 0;
       
   727  				if(rPop3Progress.iErrorCode != KErrDisconnected)
       
   728  					{
       
   729  					rPop3Progress.iErrorCode = 0;
       
   730  					}
       
   731  				rPop3Progress.iPop3SubStateProgress = TPop3Progress::EPopMoving;
       
   732  				}
       
   733   			else if ((iOperationType == CImOffLineOperation::EOffLineOpCopyToLocal) ||
       
   734  				(iOperationType == CImOffLineOperation::EOffLineOpCopyWithinService))
       
   735  				{
       
   736  				rPop3Progress.iPop3Progress = TPop3Progress::EPopCopying;
       
   737  				rPop3Progress.iTotalMsgs = iSourceMessages->Count();
       
   738  				rPop3Progress.iMsgsToProcess = rPop3Progress.iTotalMsgs - iMessageCounter;
       
   739  				rPop3Progress.iBytesDone = 0;
       
   740  				rPop3Progress.iTotalBytes = 0;
       
   741  				if(rPop3Progress.iErrorCode  != KErrDisconnected)
       
   742  					{
       
   743  					rPop3Progress.iErrorCode = 0; 					
       
   744  					}
       
   745  				rPop3Progress.iPop3SubStateProgress = TPop3Progress::EPopCopying;
       
   746  				}
       
   747 			break;
       
   748 
       
   749 		case ECancellingOfflineOperations:
       
   750 			rPop3Progress.iPop3Progress = TPop3Progress::EPopCancellingOfflineOps;
       
   751 			rPop3Progress.iTotalMsgs = iSourceMessages->Count();
       
   752 			rPop3Progress.iMsgsToProcess = rPop3Progress.iTotalMsgs - iMessageCounter;
       
   753 			rPop3Progress.iBytesDone = 0;
       
   754 			rPop3Progress.iTotalBytes = 0;
       
   755 			rPop3Progress.iErrorCode = 0;
       
   756 			rPop3Progress.iPop3SubStateProgress = TPop3Progress::EPopCancellingOfflineOps;
       
   757 			break;
       
   758 
       
   759 		default:
       
   760             {
       
   761             _LIT(KPop3Session,"Pop3 session");
       
   762 			__ASSERT_DEBUG(EFalse, 	User::Panic(KPop3Session, EPopInvalidState));
       
   763             }
       
   764 			break;
       
   765 		}
       
   766 	}
       
   767 
       
   768 //private:
       
   769 void CImPop3SetOfflineOps::DoRunL()
       
   770 	{
       
   771 	// Create the ghost destination entry if one is required.
       
   772 	switch (iState)
       
   773 		{
       
   774 		case EAddingOfflineOperations:
       
   775 			if ((iModifiedOperationType == CImOffLineOperation::EOffLineOpCopyToLocal)
       
   776 				|| (iModifiedOperationType == CImOffLineOperation::EOffLineOpMoveToLocal))
       
   777 				{
       
   778 				User::LeaveIfError(iEntry.SetEntry((*iSourceMessages)[iMessageCounter]));
       
   779 				TMsvEntry ghostEntry = iEntry.Entry();
       
   780 				ghostEntry.iRelatedId = iEntry.Entry().Id();
       
   781 				ghostEntry.SetComplete(EFalse);
       
   782 				User::LeaveIfError(iEntry.SetEntry(iDestinationEntryId));
       
   783 				iEntry.CreateEntry(ghostEntry);
       
   784 				}
       
   785 
       
   786 			iMessageCounter++;
       
   787 			if (iMessageCounter < iSourceMessages->Count())
       
   788 				{
       
   789 				AddOfflineOperationL();
       
   790 				}
       
   791 			else
       
   792 				{
       
   793 				iMessageCounter = 0;
       
   794 				if (iMessageCounter < iMessagesToCopyLocally->Count())
       
   795 					{
       
   796 					iState = ECopyingLocalEntries;
       
   797 					CopyLocalMessageL();
       
   798 					}
       
   799 				}
       
   800 			break;
       
   801 
       
   802 		case ECancellingOfflineOperations:
       
   803 			iMessageCounter++;
       
   804 			if (iMessageCounter < iSourceMessages->Count())
       
   805 				{
       
   806 				CancelOfflineOperationL();
       
   807 				}
       
   808 			break;
       
   809 
       
   810 		case ECopyingLocalEntries:
       
   811 			iMessageCounter++;
       
   812 			if (iMessageCounter < iMessagesToCopyLocally->Count())
       
   813 				{
       
   814 				CopyLocalMessageL();
       
   815 				}
       
   816 			break;
       
   817 		}
       
   818 	}
       
   819 
       
   820 void CImPop3SetOfflineOps::DoCancel()
       
   821 	{
       
   822 	iTransfer->Cancel();
       
   823 	
       
   824 		switch(iState)
       
   825 			{
       
   826 			case ECopyingLocalEntries:
       
   827 				{
       
   828 				TInt messageCounter = iMessageCounter;
       
   829 				
       
   830 				// Loop to delete all the operations attached to the messages in iSourceMessages.
       
   831 				for(TInt i = iSourceMessages->Count() - messageCounter; i > 0; -- i)
       
   832 					{
       
   833 					DeleteOfflineOperationL(messageCounter);
       
   834 					messageCounter++;
       
   835 					}
       
   836 				break;
       
   837 				}
       
   838 			
       
   839 			case EAddingOfflineOperations:
       
   840 				{
       
   841 				// Loop to delete all the operations attached to the messages in iSourceMessages.
       
   842 				for(TInt count = 0; count <= iMessageCounter; ++count)
       
   843 					{
       
   844 					DeleteOfflineOperationL(count);
       
   845 					}
       
   846 				break;
       
   847 				}
       
   848 			
       
   849 			case ECancellingOfflineOperations:
       
   850 			default:
       
   851 				{
       
   852 				// Nothing to be done here.
       
   853 				break;
       
   854 				}
       
   855 			}
       
   856 		iOfflineOperationArrayFlag.Reset();
       
   857 		CMsgActive::DoCancel();
       
   858 	}
       
   859 
       
   860 
       
   861 void CImPop3SetOfflineOps::DeleteOfflineOperationL(TInt aMessageCounter)
       
   862 	{
       
   863 	// Set the current entry, ready for the operation to be attached to it.
       
   864 	User::LeaveIfError(iEntry.SetEntry((*iSourceMessages)[aMessageCounter]));
       
   865 	TMsvEmailEntry entry = iEntry.Entry();
       
   866 	
       
   867 	if(iOfflineOperationArrayFlag[aMessageCounter])
       
   868 		{
       
   869 		CImOffLineOperationArray* operationArray = CImOffLineOperationArray::NewL();
       
   870 		CleanupStack::PushL(operationArray);
       
   871 		CImOffLineArrayStore* operationStore = new (ELeave) CImOffLineArrayStore(*operationArray);
       
   872 		CleanupStack::PushL(operationStore);
       
   873 		CMsvStore* messageStore = iEntry.EditStoreL();
       
   874 		CleanupStack::PushL(messageStore);
       
   875 
       
   876 		// Get the array of operations currently attached to the message.
       
   877 		operationStore->RestoreL(*messageStore);
       
   878 
       
   879 		TInt counter = operationArray->CountOperations();
       
   880 		if (counter > 0)
       
   881 			{
       
   882 			counter--;
       
   883 			operationArray->Delete(counter);
       
   884 			}
       
   885 		
       
   886 		operationStore->StoreL(*messageStore);
       
   887 		messageStore->CommitL();
       
   888 		
       
   889 		if(counter == 0)
       
   890 			{
       
   891 			entry.SetOperation(EFalse);
       
   892 			entry.SetDisconnectedOperation(ENoDisconnectedOperations);	
       
   893 			}
       
   894 		else
       
   895 			{
       
   896 			CImPop3OfflineUtilities::SetOfflineFlags(*operationArray, entry);		
       
   897 			}
       
   898 		iEntry.ChangeEntry(entry);
       
   899 		CleanupStack::PopAndDestroy(3); // messageStore, operationStore, operationArray	
       
   900 		}
       
   901 	}
       
   902 	
       
   903 
       
   904 void CImPop3SetOfflineOps::DoComplete(TInt& /*status*/)
       
   905 	{
       
   906 
       
   907 	}
       
   908 
       
   909 CImPop3SetOfflineOps::CImPop3SetOfflineOps(CMsvServerEntry& aEntry) : CMsgActive(EPriorityStandard), iEntry(aEntry)
       
   910 	{
       
   911 
       
   912 	}
       
   913 
       
   914 void CImPop3SetOfflineOps::ConstructL()
       
   915 	{
       
   916 	iTransfer = CImPop3TransferMessage::NewL(iEntry);
       
   917 	}
       
   918 
       
   919 
       
   920 
       
   921 void CImPop3OfflineUtilities::DeleteL(const CImOffLineOperation& aOperation, CMsvServerEntry& aEntry)
       
   922 // Finds the specified operation in the message tree and then deletes it.
       
   923 	{
       
   924 	aEntry.SetEntry(aOperation.MessageId());
       
   925 	CImOffLineOperationArray* localOperationArray = CImOffLineOperationArray::NewL();
       
   926 	CleanupStack::PushL(localOperationArray);
       
   927 	CImOffLineArrayStore* operationStore = new (ELeave) CImOffLineArrayStore(*localOperationArray);
       
   928 	CleanupStack::PushL(operationStore);
       
   929 	CMsvStore* messageStore = aEntry.EditStoreL();
       
   930 	CleanupStack::PushL(messageStore);
       
   931 
       
   932 	// Get the array of operations currently attached to the message.
       
   933 	operationStore->RestoreL(*messageStore);
       
   934 
       
   935 	// Look for the offline operation
       
   936 	TBool found = EFalse;
       
   937 	TInt index = 0;
       
   938 	while ((!found) && (index < localOperationArray->CountOperations()))
       
   939 		{
       
   940 		if (aOperation == localOperationArray->Operation(index))
       
   941 			{
       
   942 			found = ETrue;
       
   943 			}
       
   944 		else
       
   945 			{
       
   946 			index++;
       
   947 			}
       
   948 		}
       
   949 
       
   950 	if (found)
       
   951 		{
       
   952 		// Remove the entry from the list
       
   953 		localOperationArray->Delete(index);
       
   954 
       
   955 		// Write out the list to the stream
       
   956 		operationStore->StoreL(*messageStore);
       
   957 		messageStore->CommitL();
       
   958 
       
   959 		// Set the TMsvEmailEntry details
       
   960 		TMsvEmailEntry entry = aEntry.Entry();
       
   961 		SetOfflineFlags(*localOperationArray, entry);
       
   962 		aEntry.ChangeEntry(entry);
       
   963 		}
       
   964 
       
   965 	CleanupStack::PopAndDestroy(3); // messageStore, operationStore, operationArray
       
   966 	}
       
   967 
       
   968 void CImPop3OfflineUtilities::SetOfflineFlags(const CImOffLineOperationArray& aOperationArray, TMsvEmailEntry& aEntry)
       
   969 	{
       
   970 	// Sets the DisconnectedOperation flag on the given TMsvEmailEntry.
       
   971 	// Note that it is NOT commited to the index.
       
   972 	TImDisconnectedOperationType operationType = ENoDisconnectedOperations;
       
   973 	TInt index = 0;
       
   974 	while (index < aOperationArray.CountOperations())
       
   975 		{
       
   976 		if (operationType != ENoDisconnectedOperations)
       
   977 			{
       
   978 			operationType = EDisconnectedMultipleOperation;
       
   979 			}
       
   980 		else
       
   981 			{
       
   982 			switch (aOperationArray.Operation(index).OpType())
       
   983 				{
       
   984 				case CImOffLineOperation::EOffLineOpCopyToLocal:
       
   985 					operationType = EDisconnectedCopyToOperation;
       
   986 					break;
       
   987 				case CImOffLineOperation::EOffLineOpCopyFromLocal:
       
   988 					operationType = EDisconnectedCopyFromOperation;
       
   989 					break;
       
   990 				case CImOffLineOperation::EOffLineOpCopyWithinService:
       
   991 					operationType = EDisconnectedCopyWithinServiceOperation;
       
   992 					break;
       
   993 				case CImOffLineOperation::EOffLineOpMoveToLocal:
       
   994 					operationType = EDisconnectedMoveToOperation;
       
   995 					break;
       
   996 				case CImOffLineOperation::EOffLineOpMoveFromLocal:
       
   997 					operationType = EDisconnectedMoveFromOperation;
       
   998 					break;
       
   999 				case CImOffLineOperation::EOffLineOpMoveWithinService:
       
  1000 					operationType = EDisconnectedMoveWithinServiceOperation;
       
  1001 					break;
       
  1002 				case CImOffLineOperation::EOffLineOpDelete:
       
  1003 					operationType = EDisconnectedDeleteOperation;
       
  1004 					break;
       
  1005 				case CImOffLineOperation::EOffLineOpChange:
       
  1006 					operationType = EDisconnectedChangeOperation;
       
  1007 					break;
       
  1008 				case CImOffLineOperation::EOffLineOpCreate:
       
  1009 					operationType = EDisconnectedCreateOperation;
       
  1010 					break;
       
  1011 				case CImOffLineOperation::EOffLineOpMtmSpecific:
       
  1012 					operationType = EDisconnectedSpecialOperation;
       
  1013 					break;
       
  1014 				default:
       
  1015 					operationType = EDisconnectedUnknownOperation;
       
  1016 					break;
       
  1017 				}
       
  1018 			}
       
  1019 		index++;
       
  1020 		}
       
  1021 	aEntry.SetDisconnectedOperation(operationType);
       
  1022 	}
       
  1023 
       
  1024