email/pop3andsmtpmtm/clientmtms/src/CACHEMAN.CPP
changeset 0 72b543305e3a
child 34 84197e66a4bd
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 // Copyright (c) 1999-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 // CACHEMAN.CPP
       
    15 //
       
    16 
       
    17 #include "CACHEMAN.H"
       
    18 #include "MIUTHDR.H"
       
    19 #include <msvapi.h>
       
    20 #include <msvuids.h>
       
    21 #include <msvids.h>
       
    22 #include <mmsvattachmentmanager.h>
       
    23 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    24 #include <cimprunemessage.h>
       
    25 #include "cimfinder.h"
       
    26 #include "timrfc822datefield.h"
       
    27 #include "msvconsts.h"
       
    28 #endif
       
    29 
       
    30 // The CImEntryStack implementation
       
    31 
       
    32 CImFinder::CImEntryStack* CImFinder::CImEntryStack::NewL()
       
    33 	{
       
    34 	CImFinder::CImEntryStack* self;
       
    35 	self = new (ELeave) CImFinder::CImEntryStack();
       
    36 	CleanupStack::PushL(self);
       
    37 	self->ConstructL();
       
    38 	CleanupStack::Pop(); // self
       
    39 	return self;
       
    40 	}
       
    41 
       
    42 CImFinder::CImEntryStack::~CImEntryStack()
       
    43 	{
       
    44 	delete iFolders;
       
    45 	}
       
    46 
       
    47 void CImFinder::CImEntryStack::PushL(TMsvId aId)
       
    48 	{
       
    49 	iFolders->AppendL(aId);
       
    50 	}
       
    51 
       
    52 void CImFinder::CImEntryStack::Reset()
       
    53 	{
       
    54 	iFolders->Reset();
       
    55 	}
       
    56 
       
    57 TMsvId CImFinder::CImEntryStack::PopL()
       
    58 	{
       
    59 	TInt32 count = iFolders->Count();
       
    60 	if (count == 0)
       
    61 		{
       
    62 		User::Leave(KErrOverflow);
       
    63 		}
       
    64 	
       
    65 	TMsvId folderId = (*iFolders)[count - 1];
       
    66 	iFolders->Delete(count-1);
       
    67 	return folderId;
       
    68 	}
       
    69 
       
    70 void CImFinder::CImEntryStack::ConstructL()
       
    71 	{
       
    72 	iFolders = new (ELeave) CMsvEntrySelection;
       
    73 	}
       
    74 
       
    75 TBool CImFinder::CImEntryStack::Empty() const
       
    76 	{
       
    77 	return (iFolders->Count() == 0);
       
    78 	}
       
    79 
       
    80 
       
    81 // Implementation of abstract CImFinder class
       
    82 
       
    83 EXPORT_C void CImFinder::FindFirstL(TMsvId aRootEntry, TRequestStatus &aStatus)
       
    84 	{
       
    85 	iEntryStack->Reset();
       
    86 	iEntryStack->PushL(aRootEntry);
       
    87 	ASSERT(iState != EImmfFindingEntry);
       
    88 	FindNextL(aStatus);
       
    89 	}
       
    90 
       
    91 void CImFinder::FindFirstL(const CMsvEntrySelection& aInitialSelection, TRequestStatus &aStatus)
       
    92 	{
       
    93 	iEntryStack->Reset();
       
    94 
       
    95 	TInt index = aInitialSelection.Count();
       
    96 	while (index--)
       
    97 		// Push each given entry on the stack so that we will visit it later.
       
    98 		{
       
    99 		iEntryStack->PushL(aInitialSelection[index]);
       
   100 		}
       
   101 
       
   102 	ASSERT(iState != EImmfFindingEntry);
       
   103 	FindNextL(aStatus);
       
   104 	}
       
   105 
       
   106 EXPORT_C CImFinder::~CImFinder()
       
   107 	{
       
   108 	delete iEntryStack;
       
   109 	}
       
   110 
       
   111 void CImFinder::ConstructL()
       
   112 	{
       
   113 	iEntryStack = CImEntryStack::NewL();
       
   114 	CActiveScheduler::Add(this);
       
   115 	}
       
   116 
       
   117 void CImFinder::DoRunL()
       
   118 	{	
       
   119 	if (iState == EImmfFindingEntry)
       
   120 		{
       
   121 		FindNextL(iStatus);
       
   122 		}
       
   123 	}
       
   124 
       
   125 CImFinder::CImFinder(CMsvEntry& aEntry) : CMsgActive(EPriorityStandard), 	iCurrentEntry(aEntry)
       
   126 	{
       
   127 	}
       
   128 
       
   129 EXPORT_C void CImFinder::FindNextL(TRequestStatus &aStatus)
       
   130 	{
       
   131 	TImmfState tempState = iState;
       
   132 	
       
   133 	if (!(iEntryStack->Empty()))
       
   134 		// If there are entries on the stack then check them.
       
   135 		{
       
   136 		iCurrentEntry.SetEntryL(iEntryStack->PopL());
       
   137 		TUid entryType = iCurrentEntry.Entry().iType;
       
   138 		
       
   139 		AddChildEntriesL();
       
   140 
       
   141 		iStatus=KRequestPending;
       
   142 		SetActive();
       
   143 		TRequestStatus* status=&iStatus;
       
   144 		User::RequestComplete(status, KErrNone);
       
   145 
       
   146 		if (IsRequiredEntryType(entryType))
       
   147 			// If the entry is of a required type then return it.
       
   148 			{
       
   149 			iState = EImmfEntryFound;
       
   150 			}
       
   151 		else
       
   152 			// Otherwise keep looking for one.
       
   153 			{
       
   154 			iState = EImmfFindingEntry;
       
   155 			}
       
   156 		}
       
   157 	else
       
   158 		// If there is nothing on the stack then there are no more entries.
       
   159 		{
       
   160 		iStatus=KRequestPending;
       
   161 		SetActive();
       
   162 		TRequestStatus* status=&iStatus;
       
   163 		User::RequestComplete(status, KErrNotFound);
       
   164 		iState = EImmfNothingFound;
       
   165 		}
       
   166 
       
   167 	if (tempState != EImmfFindingEntry)
       
   168 		{
       
   169 		Queue(aStatus);
       
   170 		}
       
   171 	}
       
   172 
       
   173 
       
   174 
       
   175 // Implementation of CImMessageFinder class
       
   176 
       
   177 EXPORT_C CImMessageFinder* CImMessageFinder::NewL(CMsvEntry& aEntry)
       
   178 	{
       
   179 	CImMessageFinder* self = CImMessageFinder::NewLC(aEntry);
       
   180 	CleanupStack::Pop(); // self
       
   181 	return self;
       
   182 	}
       
   183 
       
   184 EXPORT_C CImMessageFinder* CImMessageFinder::NewLC(CMsvEntry& aEntry)
       
   185 	{
       
   186 	CImMessageFinder* self = new (ELeave) CImMessageFinder(aEntry);
       
   187 	CleanupStack::PushL(self);
       
   188 	self->ConstructL();
       
   189 	return self;
       
   190 	}
       
   191 
       
   192 void CImMessageFinder::AddChildEntriesL()
       
   193 	{
       
   194 	if ((iCurrentEntry.Entry().iType == KUidMsvFolderEntry)
       
   195 		|| (iCurrentEntry.Entry().iType == KUidMsvServiceEntry))
       
   196 		{
       
   197 		// Push the folders on to the entry stack
       
   198 		TMsvSelectionOrdering ordering;
       
   199 		ordering.SetShowInvisibleEntries(EFalse);
       
   200 		iCurrentEntry.SetSortTypeL(ordering);
       
   201 		CMsvEntrySelection* entrySelection = iCurrentEntry.ChildrenWithTypeL(KUidMsvFolderEntry);
       
   202 		CleanupStack::PushL(entrySelection);
       
   203 		TInt counter;
       
   204 		TInt count = entrySelection->Count();
       
   205 		for (counter = 0; counter < count; counter++)
       
   206 			{
       
   207 			iEntryStack->PushL((*entrySelection)[counter]);
       
   208 			}
       
   209 		CleanupStack::PopAndDestroy(); // entrySelection
       
   210 
       
   211 		// Push the messages on to the entry stack
       
   212 		entrySelection = iCurrentEntry.ChildrenWithTypeL(KUidMsvMessageEntry);
       
   213 		CleanupStack::PushL(entrySelection);
       
   214 		count = entrySelection->Count();
       
   215 		for (counter = 0; counter < count; counter++)
       
   216 			{
       
   217 			iEntryStack->PushL((*entrySelection)[counter]);
       
   218 			}
       
   219 		CleanupStack::PopAndDestroy(); // entrySelection
       
   220 		}
       
   221 	}
       
   222 
       
   223 TBool CImMessageFinder::IsRequiredEntryType(TUid aEntryType) const
       
   224 	{
       
   225 	if (aEntryType == KUidMsvMessageEntry)
       
   226 		return ETrue;
       
   227 	else
       
   228 		return EFalse;
       
   229 	}
       
   230 
       
   231 CImMessageFinder::CImMessageFinder(CMsvEntry& aEntry) : CImFinder(aEntry)
       
   232 	{
       
   233 	}
       
   234 
       
   235 
       
   236 
       
   237 // Implementation of CImMessageFinder class
       
   238 
       
   239 EXPORT_C CImEntryFinder* CImEntryFinder::NewL(CMsvEntry& aEntry)
       
   240 	{
       
   241 	CImEntryFinder* self = CImEntryFinder::NewLC(aEntry);
       
   242 	CleanupStack::Pop(); // self
       
   243 	return self;
       
   244 	}
       
   245 
       
   246 EXPORT_C CImEntryFinder* CImEntryFinder::NewLC(CMsvEntry& aEntry)
       
   247 	{
       
   248 	CImEntryFinder* self = new (ELeave) CImEntryFinder(aEntry);
       
   249 	CleanupStack::PushL(self);
       
   250 	self->ConstructL();
       
   251 	return self;
       
   252 	}
       
   253 	
       
   254 void CImEntryFinder::AddChildEntriesL()
       
   255 	{
       
   256 	if (iCurrentEntry.Entry().Owner())
       
   257 		{
       
   258 		// Push the child entries on to the entry stack
       
   259 		TMsvSelectionOrdering ordering;
       
   260 		ordering.SetShowInvisibleEntries(ETrue);
       
   261 		iCurrentEntry.SetSortTypeL(ordering);
       
   262 		CMsvEntrySelection* entrySelection = iCurrentEntry.ChildrenL();
       
   263 		CleanupStack::PushL(entrySelection);
       
   264 		TInt counter;
       
   265 		TInt count = entrySelection->Count();
       
   266 		for (counter = 0; counter < count; counter++)
       
   267 			{
       
   268 			iEntryStack->PushL((*entrySelection)[counter]);
       
   269 			}
       
   270 		CleanupStack::PopAndDestroy(); // entrySelection		
       
   271 		}
       
   272 	}
       
   273 
       
   274 TBool CImEntryFinder::IsRequiredEntryType(TUid /*aEntryType*/) const
       
   275 // Always true because all entry types are needed.
       
   276 	{
       
   277 	return ETrue;
       
   278 	}
       
   279 
       
   280 CImEntryFinder::CImEntryFinder(CMsvEntry& aEntry) : CImFinder(aEntry)
       
   281 	{
       
   282 	}
       
   283 
       
   284 
       
   285 
       
   286 // Implementation of CImMessage Finder
       
   287 
       
   288 EXPORT_C CImMessageCounter* CImMessageCounter::NewL(CMsvEntry& aEntry)
       
   289 	{
       
   290 	CImMessageCounter* self = CImMessageCounter::NewLC(aEntry);
       
   291 	CleanupStack::Pop(); // self
       
   292 	return self;
       
   293 	}
       
   294 
       
   295 EXPORT_C CImMessageCounter* CImMessageCounter::NewLC(CMsvEntry& aEntry)
       
   296 	{
       
   297 	CImMessageCounter* self = new (ELeave) CImMessageCounter(aEntry);
       
   298 	CleanupStack::PushL(self);
       
   299 	self->ConstructL();
       
   300 	return self;
       
   301 	}
       
   302 
       
   303 EXPORT_C TInt CImMessageCounter::Count()
       
   304 	{
       
   305 	return iCount;
       
   306 	}
       
   307 
       
   308 void CImMessageCounter::AddChildEntriesL()
       
   309 	{
       
   310 	if ((iCurrentEntry.Entry().iType == KUidMsvFolderEntry)
       
   311 		|| (iCurrentEntry.Entry().iType == KUidMsvServiceEntry))
       
   312 		{
       
   313 		// Push the folders on to the entry stack
       
   314 		TMsvSelectionOrdering ordering;
       
   315 		ordering.SetShowInvisibleEntries(EFalse);
       
   316 		iCurrentEntry.SetSortTypeL(ordering);
       
   317 		CMsvEntrySelection* entrySelection = iCurrentEntry.ChildrenWithTypeL(KUidMsvFolderEntry);
       
   318 		CleanupStack::PushL(entrySelection);
       
   319 		TInt counter;
       
   320 		TInt count = entrySelection->Count();
       
   321 		for (counter = 0; counter < count; counter++)
       
   322 			{
       
   323 			iEntryStack->PushL((*entrySelection)[counter]);
       
   324 			}
       
   325 		CleanupStack::PopAndDestroy(); // entrySelection
       
   326 
       
   327 		// Count the messages in the folder
       
   328 		entrySelection = iCurrentEntry.ChildrenWithTypeL(KUidMsvMessageEntry);
       
   329 		CleanupStack::PushL(entrySelection);
       
   330 		iCount += entrySelection->Count();
       
   331 		CleanupStack::PopAndDestroy(); // entrySelection
       
   332 		}
       
   333 	else if (iCurrentEntry.Entry().iType == KUidMsvMessageEntry)
       
   334 		{ // count itself if it's a message entry
       
   335 		iCount++;
       
   336 		}
       
   337 	}
       
   338 
       
   339 TBool CImMessageCounter::IsRequiredEntryType(TUid) const
       
   340 	{
       
   341 	// The message counter doesn't require any entry types to be returned.
       
   342 	return EFalse;
       
   343 	}
       
   344 
       
   345 CImMessageCounter::CImMessageCounter(CMsvEntry& aEntry) : CImFinder(aEntry)
       
   346 	{
       
   347 
       
   348 	}
       
   349 
       
   350 
       
   351 // Implementation of CImPruneMessage
       
   352 
       
   353 EXPORT_C CImPruneMessage* CImPruneMessage::NewL(CMsvEntry& aEntry, RFs& aFs)
       
   354 /** Allocates and constructs a new CImPruneMessage object.
       
   355 
       
   356 @param aEntry CMsvEntry for use by the object in performing the delete operations. 
       
   357 It does not need to be set to any particular message context. The caller retains 
       
   358 ownership.
       
   359 @param aFs Open file server session handle
       
   360 @return New CImPruneMessage object */
       
   361 	{
       
   362 	CImPruneMessage* self = CImPruneMessage::NewLC(aEntry, aFs);
       
   363 	CleanupStack::Pop(); // self
       
   364 	return self;
       
   365 	}
       
   366 
       
   367 EXPORT_C CImPruneMessage* CImPruneMessage::NewLC(CMsvEntry& aEntry, RFs& aFs)
       
   368 /** Allocates and constructs a new CImPruneMessage object, leaving the object on 
       
   369 the cleanup stack.
       
   370 
       
   371 @param aEntry CMsvEntry for use by the object in performing the delete operations. 
       
   372 It does not need to be set to any particular message context. The caller retains 
       
   373 ownership.
       
   374 @param aFs Open file server session handle
       
   375 @return New CImPruneMessage object */
       
   376 	{
       
   377 	CImPruneMessage* self = new (ELeave) CImPruneMessage(aEntry, aFs);
       
   378 	CleanupStack::PushL(self);
       
   379 	self->ConstructL();
       
   380 	return self;
       
   381 	}
       
   382 
       
   383 EXPORT_C void CImPruneMessage::StartL(TMsvId aMessageEntry, TRequestStatus &aStatus)
       
   384 /** Starts the asynchronous message clean operation.
       
   385 
       
   386 @param aMessageEntry The ID of the entry from which to delete the body text 
       
   387 and attachment data
       
   388 @param aStatus Asynchronous status word that completes with KErrNone when the 
       
   389 body text and all of the attachments have been deleted. */
       
   390 	{
       
   391 	iCurrentEntry.SetEntryL(aMessageEntry);
       
   392 	TMsvEmailEntry entry(iCurrentEntry.Entry());
       
   393 
       
   394 	if (entry.Complete() || entry.BodyTextComplete())
       
   395 		{
       
   396 		entry.SetComplete(EFalse);
       
   397 		entry.SetBodyTextComplete(EFalse);
       
   398 		iChangeOperation = iCurrentEntry.ChangeL(entry, iStatus);
       
   399 		SetActive();
       
   400 		}
       
   401 	else
       
   402 		{
       
   403 		iStatus=KRequestPending;
       
   404 		SetActive();
       
   405 		TRequestStatus* status = &iStatus;
       
   406 		User::RequestComplete(status, KErrNone);
       
   407 		}
       
   408 
       
   409 	iState = EImPruneUpdatingFirstEntry;
       
   410 	Queue(aStatus);
       
   411 	iRootEntryId = aMessageEntry;
       
   412 	}
       
   413 
       
   414 CImPruneMessage::~CImPruneMessage()
       
   415 /** Destructor. */
       
   416 	{
       
   417 	Cancel();
       
   418 	delete iEntryFinder;
       
   419 	delete iFileManager;
       
   420 	delete iStore;
       
   421 	delete iChangeOperation;	
       
   422 	}
       
   423 
       
   424 void CImPruneMessage::ConstructL()
       
   425 	{
       
   426 	CActiveScheduler::Add(this);
       
   427 	iEntryFinder = CImEntryFinder::NewL(iCurrentEntry);
       
   428 	iFileManager = CFileMan::NewL(iFs);
       
   429 	}
       
   430 
       
   431 void CImPruneMessage::DoRunL()
       
   432 	{
       
   433 	TInt error = KErrNone;
       
   434 	switch (iState)
       
   435 		{
       
   436 		case EImPruneUpdatingFirstEntry:
       
   437 			delete iChangeOperation;
       
   438 			iChangeOperation = 0;
       
   439 			PruneEntryL();
       
   440 			iState = EImPruneFindFirstEntry;			
       
   441 			SetActive();
       
   442 			break;
       
   443 		case EImPruneFindFirstEntry:
       
   444 			ResetStoreL();
       
   445 			iEntryFinder->FindFirstL(iRootEntryId, iStatus);
       
   446 			iState = EImPruneFindingEntry;
       
   447 			SetActive();
       
   448 			break;
       
   449 		case EImPruneUpdatingEntry:
       
   450 			delete iChangeOperation;
       
   451 			iChangeOperation = 0;
       
   452 			PruneEntryL();
       
   453 			iState = EImPruneFindNextEntry;
       
   454 			SetActive();
       
   455 			break;
       
   456 		case EImPruneFindNextEntry:
       
   457 			ResetStoreL();
       
   458 			iEntryFinder->FindNextL(iStatus);
       
   459 			iState = EImPruneFindingEntry;
       
   460 			SetActive();
       
   461 			break;
       
   462 		case EImPruneFindingEntry:
       
   463 			delete iStore;
       
   464 			iStore = NULL;
       
   465 			if (iStatus == KErrNone)
       
   466 				// An entry has been found, so prune it.
       
   467 				{
       
   468 				// Ignore any error as it probably just means that the entry is locked.
       
   469 				// We can afford to skip locked entries.
       
   470 				if (iCurrentEntry.Entry().Complete())
       
   471 					{
       
   472 					TMsvEntry entry = iCurrentEntry.Entry();
       
   473 					entry.SetComplete(EFalse);
       
   474 					TRAPD(ignore, iChangeOperation = iCurrentEntry.ChangeL(entry, iStatus));
       
   475 					}
       
   476 
       
   477 				if (!iChangeOperation)
       
   478 					{
       
   479 					TRequestStatus* status = &iStatus;
       
   480 					iStatus=KRequestPending;
       
   481 					User::RequestComplete(status, KErrNone);	
       
   482 					}
       
   483 				iState = EImPruneUpdatingEntry;
       
   484 				SetActive();
       
   485 				}
       
   486 			break;
       
   487 		}
       
   488 	}
       
   489 
       
   490 void CImPruneMessage::DoComplete(TInt& status)
       
   491 	{
       
   492 	if ((iState == EImPruneFindingEntry) && (status == KErrNotFound))
       
   493 	// The not found status is expected, it just means that the entry finder has already found all the entries.
       
   494 		{
       
   495 		status = KErrNone;
       
   496 		}
       
   497 	}
       
   498 
       
   499 void CImPruneMessage::DoCancel()
       
   500 	{
       
   501 	iEntryFinder->Cancel();
       
   502 	if (iChangeOperation)
       
   503 		iChangeOperation->Cancel();
       
   504 	CMsgActive::DoCancel();
       
   505 	}
       
   506 
       
   507 CImPruneMessage::CImPruneMessage(CMsvEntry& aEntry, RFs& aFs) 
       
   508 	: CMsgActive(EPriorityStandard), 
       
   509 	iCurrentEntry(aEntry), 
       
   510 	iFs(aFs)
       
   511 	{
       
   512 	__DECLARE_NAME(_S("CImPruneMessage"));
       
   513 	}
       
   514 
       
   515 void CImPruneMessage::PruneEntryL()
       
   516 	{
       
   517 	// delete the rich text stream
       
   518 	iStore = iCurrentEntry.EditStoreL();
       
   519 	if (iStore->IsPresentL(KMsvEntryRichTextBody))
       
   520 		{	
       
   521 		iStore->DeleteBodyTextL();
       
   522 		iStore->CommitL();
       
   523 		}
       
   524 		
       
   525 	// If the entry has an attachment we need to remove it.
       
   526 	// In order to preserve the message structure, we won't delete the attachment
       
   527 	// completely, but instead we will set the file size to 0 and mark the attachment
       
   528 	// as not complete.
       
   529 	
       
   530 	TBool completeSelf = ETrue;
       
   531 		
       
   532 	MMsvAttachmentManager& attachmentMgr = iStore->AttachmentManagerL();
       
   533 	
       
   534 	// as this is email attachment entry , it has one attachment per entry
       
   535 	if(attachmentMgr.AttachmentCount() > 0)
       
   536 		{
       
   537 		CMsvAttachment* attachmentInfo = attachmentMgr.GetAttachmentInfoL(0);
       
   538 		CleanupStack::PushL(attachmentInfo);
       
   539 
       
   540 		// We only want to remove file attachments
       
   541 		if (attachmentInfo->Type() == CMsvAttachment::EMsvFile)
       
   542 			{
       
   543 			RFile file = attachmentMgr.GetAttachmentFileForWriteL(0);
       
   544 			TInt error = file.SetSize(0);
       
   545 			file.Close();
       
   546 
       
   547 			if (error == KErrNone)
       
   548 				{
       
   549 				attachmentInfo->SetComplete(EFalse);
       
   550 				attachmentMgr.ModifyAttachmentInfoL(attachmentInfo, iStatus);
       
   551 				// ModifyAttachmentInfoL takes ownership of the attachment info, so just pop
       
   552 				// it off the cleanup stack and set the pointer to NULL to show we don't
       
   553 				// own it
       
   554 				CleanupStack::Pop(attachmentInfo);
       
   555 				attachmentInfo = NULL;
       
   556 
       
   557 				// We have called an async routine, so set the flag to show that we don't
       
   558 				// need to complete ourself
       
   559 				completeSelf = EFalse;
       
   560 				}
       
   561 			}
       
   562 
       
   563 		if (attachmentInfo != NULL)
       
   564 			{
       
   565 			CleanupStack::PopAndDestroy(attachmentInfo);
       
   566 			}	
       
   567 		}
       
   568 	
       
   569 	if (completeSelf)
       
   570 		{
       
   571 		TRequestStatus* status = &iStatus;
       
   572 		iStatus=KRequestPending;
       
   573 		User::RequestComplete(status, KErrNone);
       
   574 		}
       
   575 	}
       
   576 
       
   577 void CImPruneMessage::ResetStoreL()
       
   578 	{
       
   579 	if (iStore != NULL)
       
   580 	   {
       
   581 	   iStore->CommitL();
       
   582 	   delete iStore;
       
   583 	   iStore = NULL;	
       
   584 	   }
       
   585 	}
       
   586 
       
   587 // Implementation of CImCacheManager
       
   588 
       
   589 EXPORT_C void CImCacheManager::StartL(TMsvId aRootEntry, TRequestStatus &aStatus)
       
   590 /** Performs a recursive cache cleanup starting from a specified root entry.
       
   591 
       
   592 Cached data for entries below the specified root are cleaned-up if they meet 
       
   593 the criteria specified by the implementation of Filter().
       
   594 
       
   595 @param aRootEntry Entry from which to start cache cleanup
       
   596 @param aStatus Asynchronous status word signalled when the operation is complete */
       
   597 	{
       
   598 	delete iMessagesToPrune;
       
   599 	iMessagesToPrune = 0;
       
   600 	iState = EImcmCountingMessages;
       
   601 	aStatus = KRequestPending;
       
   602 	iReport = &aStatus;
       
   603 	iMessageCounter->FindFirstL(aRootEntry, iStatus);
       
   604 	iRootEntry = aRootEntry;
       
   605 	SetActive();
       
   606 	}
       
   607 
       
   608 EXPORT_C void CImCacheManager::StartL(const CMsvEntrySelection& aSelection, TRequestStatus &aStatus)
       
   609 /** Performs a recursive cache cleanup for a specified selection of root entries.
       
   610 
       
   611 Cached data for entries below the specified roots are cleaned-up if they meet 
       
   612 the criteria specified by the implementation of Filter().
       
   613 
       
   614 @param aSelection List of entries from which to start cache cleanup
       
   615 @param aStatus Asynchronous status word signalled when the operation is complete */
       
   616 	{
       
   617 	delete iMessagesToPrune;
       
   618 	iMessagesToPrune = 0;
       
   619 	iState = EImcmCountingMessages;
       
   620 	aStatus = KRequestPending;
       
   621 	iReport = &aStatus;
       
   622 
       
   623 	// Save the selection for later as we need it when we actually prune the messages
       
   624 	iMessagesToPrune = new (ELeave) CMsvEntrySelection();
       
   625 	TInt index = aSelection.Count();
       
   626 	while (index--)
       
   627 		{
       
   628 		iMessagesToPrune->AppendL(aSelection[index]);
       
   629 		}
       
   630 
       
   631 	// Set off the operation to count all the messages
       
   632 	iMessageCounter->FindFirstL(aSelection, iStatus);
       
   633 
       
   634 	SetActive();
       
   635 	}
       
   636 
       
   637 
       
   638 EXPORT_C void CImCacheManager::ConstructL()
       
   639 /** Second phase constructor.
       
   640 
       
   641 All classes derived from CImCacheManager must call this function before StartL() 
       
   642 is called. */
       
   643 	{
       
   644 	TMsvSelectionOrdering ordering;
       
   645 	iCurrentEntry = CMsvEntry::NewL(iSession, KMsvRootIndexEntryId, ordering);
       
   646 	iMessageFinder = CImMessageFinder::NewL(*iCurrentEntry);
       
   647 	iMessageCounter = CImMessageCounter::NewL(*iCurrentEntry);
       
   648 	iProgress.iTotalMessages = 1;
       
   649 	iProgress.iMessagesProcessed = 0;
       
   650 	CActiveScheduler::Add(this);
       
   651 	}
       
   652 
       
   653 EXPORT_C const TDesC8& CImCacheManager::ProgressL()
       
   654 /** Gets information on the progress of the operation.
       
   655 
       
   656 @return Packaged TImCacheManagerProgress object holding operation progress 
       
   657 details */
       
   658 	{
       
   659 	if (iProgress.iTotalMessages == 0)
       
   660 		{
       
   661 		iProgress.iTotalMessages = 1;
       
   662 		}
       
   663 
       
   664 	if (iProgress.iMessagesProcessed > iProgress.iTotalMessages)
       
   665 		{
       
   666 		iProgress.iMessagesProcessed = iProgress.iTotalMessages;
       
   667 		}
       
   668 
       
   669 	iProgressBuf = iProgress;
       
   670 	return iProgressBuf;
       
   671 	}
       
   672 
       
   673 /** Implements the active object completion protocol for a cache cleanup operation.   
       
   674 
       
   675 @see CActive::RunL() */
       
   676 EXPORT_C void CImCacheManager::RunL()
       
   677 	{
       
   678 	TInt error = iStatus.Int();
       
   679 	
       
   680 	if ((iState == EImcmCountingMessages)
       
   681 		&& (error == KErrNotFound))
       
   682 		// A KErrNotFound is a normal condition from the message counter.
       
   683 		{
       
   684 		error = KErrNone;
       
   685 		}
       
   686 
       
   687 	if (error == KErrNone)
       
   688 		{
       
   689 		TRAP(error, DoRunL());
       
   690 		}
       
   691 
       
   692 	if(error != KErrNone)
       
   693 		{
       
   694 		if (error == KErrNotFound)
       
   695 			// A KErrNotFound is a normal condition from the message finder.
       
   696 			{
       
   697 			error = KErrNone;
       
   698 			}
       
   699 
       
   700 		User::RequestComplete(iReport, error);
       
   701 		}
       
   702 	}
       
   703 
       
   704 /** Implements the active object cancellation protocol for a cache cleanup operation.
       
   705 
       
   706 As the cache manager is an active object, a cache cleanup  
       
   707 operation started by Start() can be cancelled using CActive::Cancel().
       
   708 
       
   709 Cancellation halts any further deletion of message data, but does 
       
   710 not restore any data that has already been deleted by the cleanup operation.    
       
   711 
       
   712 @see CActive::Cancel() */
       
   713 EXPORT_C void CImCacheManager::DoCancel()
       
   714 	{
       
   715 	iMessageFinder->Cancel();
       
   716 	iMessageCounter->Cancel();
       
   717 
       
   718 	if (iDeleteOperation)
       
   719 		iDeleteOperation->Cancel();
       
   720 
       
   721 	User::RequestComplete(iReport,KErrCancel);
       
   722 	}
       
   723 
       
   724 void CImCacheManager::DoRunL()
       
   725 	{
       
   726 	switch (iState)
       
   727 		{
       
   728 		case EImcmCountingMessages:
       
   729 			iProgress.iTotalMessages = iMessageCounter->Count();
       
   730 			
       
   731 			if (iMessagesToPrune)
       
   732 				// If we are pruning a selection the prune from the selection
       
   733 				iMessageFinder->FindFirstL(*iMessagesToPrune, iStatus);
       
   734 			else
       
   735 				// otherwise start at the root entry
       
   736 				iMessageFinder->FindFirstL(iRootEntry, iStatus);
       
   737 
       
   738 			iState = EImcmLookingForMessage;
       
   739 			SetActive();
       
   740 			break;
       
   741 
       
   742 		case EImcmLookingForMessage:
       
   743 			if (iStatus == KErrNone)
       
   744 				{
       
   745 				if (Filter())
       
   746 					{
       
   747 					PruneMessageL();
       
   748 					}
       
   749 				else
       
   750 					{
       
   751 					iMessageFinder->FindNextL(iStatus);
       
   752 					iState = EImcmLookingForMessage;
       
   753 					SetActive();
       
   754 					}
       
   755 				}
       
   756 			iProgress.iMessagesProcessed++;
       
   757 			break;
       
   758 
       
   759 		case EImcmPruningMessages:
       
   760 		case EImcmSkippingPrune:
       
   761 			// The current message has been pruned, find another one.
       
   762 			if (iDeleteOperation)
       
   763 				{
       
   764 				delete iDeleteOperation;
       
   765 				iDeleteOperation = 0;
       
   766 				}
       
   767 			iMessageFinder->FindNextL(iStatus);
       
   768 			iState = EImcmLookingForMessage;
       
   769 			SetActive();
       
   770 			break;
       
   771 
       
   772 		default:
       
   773 			break;
       
   774 		}
       
   775 
       
   776 	}
       
   777 
       
   778 void CImCacheManager::PruneMessageL()
       
   779 	{
       
   780 	if (iCurrentEntry->Entry().Owner())
       
   781 		{
       
   782 		iState = EImcmPruningMessages;
       
   783 
       
   784 		// Remove any associated store 
       
   785 		if (iCurrentEntry->HasStoreL())
       
   786 			{
       
   787 			CMsvStore* store=iCurrentEntry->EditStoreL();
       
   788 			CleanupStack::PushL(store);
       
   789 			store->DeleteL();
       
   790 			CleanupStack::PopAndDestroy(store);
       
   791 			}
       
   792 
       
   793 		// Get a list of the child entries
       
   794 		CMsvEntrySelection* children = iCurrentEntry->ChildrenL();
       
   795 		CleanupStack::PushL(children);
       
   796 
       
   797 		// Delete the child entries
       
   798 		// The Complete and BodyTextComplete flags are cleared by the
       
   799 		// server MTM when the delete is processed.
       
   800 		iDeleteOperation = iCurrentEntry->DeleteL(*children, iStatus);
       
   801 		SetActive();
       
   802 		CleanupStack::PopAndDestroy(children);
       
   803 		}
       
   804 	else
       
   805 		{
       
   806 		// If this entry doesn't own any children,
       
   807 		// or we can't do the ChangeL then skip this entry and move on.
       
   808 		iState = EImcmSkippingPrune;
       
   809 		iStatus=KRequestPending;
       
   810 		SetActive();		
       
   811 		TRequestStatus* status = &iStatus;
       
   812 		User::RequestComplete(status, KErrNone);
       
   813 		}
       
   814 	}
       
   815 
       
   816 EXPORT_C CImCacheManager::CImCacheManager(CMsvSession& aSession, TRequestStatus& aObserverRequestStatus) 
       
   817 	: CMsvOperation(aSession, EPriorityStandard, aObserverRequestStatus), 
       
   818 	iSession(aSession)
       
   819 /** Constructor.
       
   820 
       
   821 @param aSession Message server session
       
   822 @param aObserverRequestStatus Unused */
       
   823 	{
       
   824 	__DECLARE_NAME(_S("CImCacheManager"));
       
   825 	}
       
   826 
       
   827 EXPORT_C CImCacheManager::~CImCacheManager()
       
   828 /** Destructor.
       
   829 
       
   830 This cancels any operation in progress. */
       
   831 	{
       
   832 	Cancel();
       
   833 	delete iCurrentEntry;
       
   834 	delete iMessageFinder;
       
   835 	delete iMessageCounter;
       
   836 	delete iMessagesToPrune;
       
   837 	delete iDeleteOperation;
       
   838 	}