email/pop3andsmtpmtm/imapservermtm/src/IMPSMTM.CPP
changeset 25 84d9eb65b26f
equal deleted inserted replaced
23:238255e8b033 25:84d9eb65b26f
       
     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 #include "impspan.h"
       
    17 
       
    18 #include "impsmtm.h"
       
    19 #include <msventry.h>
       
    20 #include <imapset.h>
       
    21 #include <miutset.h>
       
    22 #include <offop.h>
       
    23 #include <msvreg.h>
       
    24 #include <imapcmds.h>
       
    25 #include <logwrap.h>
       
    26 #include <imcvutil.h>
       
    27 #include <cemailaccounts.h>
       
    28 
       
    29 #include "imapsess.h"
       
    30 #include "fldsync.h"
       
    31 #include "imapsync.h"
       
    32 #include "imapcomp.h"
       
    33 #include "imapoffl.h"
       
    34 #include "impsutil.h"
       
    35 
       
    36 #ifdef _DEBUG
       
    37 #define LOG_COMMANDS(a) iPrimarySession->iSession->LogText a
       
    38 #define DBG(a) a
       
    39 #define PRINTING
       
    40 #else
       
    41 #define LOG_COMMANDS(a)
       
    42 #define DBG(a)
       
    43 #undef PRINTING
       
    44 #endif
       
    45 
       
    46 // Type of MTM request: used only in this file
       
    47 enum
       
    48 	{
       
    49 	EMtmCopyToLocal=1,
       
    50 	EMtmMoveToLocal,
       
    51 	EMtmCopyFromLocal,
       
    52 	EMtmMoveFromLocal,
       
    53 	EMtmCopyWithinService,
       
    54 	EMtmMoveWithinService,
       
    55 	EMtmPopulate
       
    56 	};
       
    57 
       
    58 // Code for the active wrapper
       
    59 CActiveWrapper* CActiveWrapper::NewL(TInt aID)
       
    60 	{
       
    61 	CActiveWrapper* self=new(ELeave)CActiveWrapper(aID);
       
    62 	CleanupStack::PushL(self);
       
    63 	self->ConstructL();
       
    64 	CActiveScheduler::Add( self );
       
    65 	CleanupStack::Pop();
       
    66 	return self;
       
    67 	}
       
    68 
       
    69 CActiveWrapper::CActiveWrapper(TInt aID) : CActive(0), iID(aID)
       
    70 	{
       
    71 	}
       
    72 
       
    73 void CActiveWrapper::ConstructL()
       
    74 	{
       
    75 	// The object is a session
       
    76 	iSession=CImImap4Session::NewL(iID, *this);
       
    77 
       
    78 	// Get a compound operation
       
    79 	iCompound=CImImap4Compound::NewL(iSession);
       
    80 
       
    81 	// If we're the primary session, we get a fullsync object too
       
    82 	if (iID==1)
       
    83 		iFullSync=CImImap4Synchronise::NewL(iSession);
       
    84 	}
       
    85 
       
    86 void CActiveWrapper::StartL(MActiveWrapperObserver* aManager)
       
    87 	{
       
    88 	DBG((iSession->LogText(_L8("CActiveWrapper::StartL(ID=%d)"),iID)));
       
    89 
       
    90 	// The request has already been issued with our iStatus, so here all we
       
    91 	// do is note down the completion information and do a SetActive()
       
    92 	iParentPtr=aManager;
       
    93 	// Activate the observer as well, in case the request is cancelled.
       
    94 	iParentPtr->Activate();
       
    95 	SetActive();
       
    96 	}
       
    97 
       
    98 // Pointer to ActiveWrapper's iStatus, so direct commands to session (see above)
       
    99 // use the correct iStatus.
       
   100 TRequestStatus* CActiveWrapper::SessionStatus()
       
   101 	{
       
   102 	// Return the pointer
       
   103 	return(&iStatus);
       
   104 	}
       
   105 
       
   106 // Set entry pointers for classes the wrapper owns
       
   107 void CActiveWrapper::SetEntry(CMsvServerEntry* aEntry)
       
   108 	{
       
   109 	iSession->SetEntry(aEntry);
       
   110 	iCompound->SetEntry(aEntry);
       
   111 	if (iFullSync)
       
   112 		iFullSync->SetEntry(aEntry);
       
   113 	}
       
   114 
       
   115 void CActiveWrapper::DoCancel()
       
   116 	{
       
   117 	DBG((iSession->LogText(_L8("CActiveWrapper::DoCancel(ID=%d)"),iID)));
       
   118 
       
   119 	// Cancel anything we might have outstanding
       
   120 	if (iFullSync)
       
   121 		iFullSync->Cancel();
       
   122 	iCompound->Cancel();
       
   123 	if( !iSession->IsCancelling())
       
   124 		{
       
   125 		// Can only cancel the session if we're not waiting for a cancelled fetch
       
   126 		// to complete.
       
   127 		iSession->Cancel();	
       
   128 		}
       
   129 
       
   130 	// Tell parent we've completed: DON'T complete it ourselves.
       
   131 	iParentPtr->RequestCompleted(iID,KErrCancel);
       
   132 	}
       
   133 
       
   134 #ifdef PRINTING
       
   135 void CActiveWrapper::DoComplete(TInt aStatus)
       
   136 #else
       
   137 void CActiveWrapper::DoComplete(TInt /*aStatus*/)
       
   138 #endif
       
   139 	{
       
   140 	DBG((iSession->LogText(_L8("CActiveWrapper::DoComplete(%d, id=%d)"),aStatus,iID)));
       
   141 	}
       
   142 
       
   143 void CActiveWrapper::RunL()
       
   144 	{
       
   145 	// IMPORTANT: The contents of this CActiveWrapper::RunL() MUST NOT ever User::Leave()
       
   146 	DBG((iSession->LogText(_L8("ActiveWrapper RunL(ID=%d, result=%d)"),iID,iStatus.Int())));
       
   147 
       
   148 	TInt error=iStatus.Int();
       
   149 	Cancel(); // Obvious to do it here
       
   150 	iParentPtr->RequestCompleted(iID,error);
       
   151 	}
       
   152 
       
   153 CActiveWrapper::~CActiveWrapper()
       
   154 	{
       
   155 	Cancel();
       
   156 	delete iSession;
       
   157 	delete iCompound;
       
   158 	delete iFullSync;
       
   159 	}
       
   160 
       
   161 void CActiveWrapper::NonCompletedFailure()
       
   162 	{
       
   163 	DBG((iSession->LogText(_L8("ActiveWrapper::NonCompletedFailure (%d)"), iID)));
       
   164 
       
   165 	// A failure has occured on the session, but there is no outstanding asynchronous
       
   166 	// request on it. This can happen if for instance we get a disconnect while doing
       
   167 	// a cancel and idle operation. Pass the failure on to the parent.
       
   168 
       
   169 	iParentPtr->NonCompletedFailureOnSession(iID);
       
   170 	}
       
   171 
       
   172 // Return of current imap session
       
   173 CImImap4Session* CActiveWrapper::GetImap4Session()
       
   174 	{
       
   175 	return iSession;	
       
   176 	}
       
   177 
       
   178 // -----------------------------------------------------------------------
       
   179 
       
   180 // The actual MTM
       
   181 EXPORT_C CImap4ServerMtm* CImap4ServerMtm::NewL(CRegisteredMtmDll& aRegisteredMtmDll,CMsvServerEntry* aEntry)
       
   182 	{
       
   183 	CImap4ServerMtm* self=new CImap4ServerMtm(aRegisteredMtmDll,aEntry);
       
   184 	if (self==NULL)
       
   185 		{
       
   186 		aRegisteredMtmDll.ReleaseLibrary();
       
   187 		User::Leave(KErrNoMemory);
       
   188 		}
       
   189 	CleanupStack::PushL(self);
       
   190 	self->ConstructL();
       
   191 	CleanupStack::Pop();
       
   192 	return self;
       
   193 	}
       
   194 
       
   195 void CImap4ServerMtm::ConstructL()
       
   196 	{
       
   197 	// Make an Imap4 session: make it under the activewrapper, so we can have
       
   198 	// more than one at a time
       
   199 
       
   200 	// The primary session is the one that does the full sync
       
   201 	iPrimarySession=CActiveWrapper::NewL(1);
       
   202 
       
   203 	// The secondary session is used if we get fetch requests while the
       
   204 	// primary session is busy
       
   205 	iSecondarySession=CActiveWrapper::NewL(2);
       
   206 
       
   207 	// create an offline op controller
       
   208 	iOffLineControl=CImap4OffLineControl::NewL(iServerEntry, iPrimarySession->iSession);
       
   209 
       
   210 	// create the utils object
       
   211 	iUtils = CImap4Utils::NewL(iServerEntry);
       
   212 	
       
   213 	// tell the FullSync session about them
       
   214 	iPrimarySession->iFullSync->SetOffLineControl(iOffLineControl);
       
   215 	iPrimarySession->iFullSync->SetUtils(iUtils);
       
   216 
       
   217 	// Get an entry selection
       
   218 	iSelection=new (ELeave) CMsvEntrySelection;
       
   219 
       
   220 	// We're disconnected at first
       
   221 	iLastSessionState=TImap4GenericProgress::EDisconnected;
       
   222 
       
   223 	// We need to see invisible entries
       
   224 	TMsvSelectionOrdering invisible;
       
   225 	invisible=iServerEntry->Sort();
       
   226 	invisible.SetShowInvisibleEntries(ETrue);
       
   227 	iServerEntry->SetSort(invisible);
       
   228 
       
   229 	// Tell sessions and foldersync about it
       
   230 	iPrimarySession->SetEntry(iServerEntry);
       
   231 	iSecondarySession->SetEntry(iServerEntry);
       
   232 	}
       
   233 
       
   234 // MTM destructor: clean up - this involves removing the sessions.
       
   235 CImap4ServerMtm::~CImap4ServerMtm()
       
   236 	{
       
   237 	// We may still be active
       
   238 	Cancel();
       
   239 
       
   240 	// Ensure service is marked as offline (if the serviceid was initialised, anyway)
       
   241 	if (iServiceId && iServiceSettings)
       
   242 		{
       
   243 		// Make stuff invisible as necessary
       
   244 		TRAP_IGNORE(MarkOnOrOfflineL(EFalse));
       
   245 
       
   246 		// Get rid of settings
       
   247 		delete iServiceSettings;
       
   248 		}
       
   249 
       
   250 	// Clean up
       
   251 	delete iSelection;
       
   252 	delete iOneSelection;
       
   253 	delete iPrimarySession;
       
   254 	delete iSecondarySession;
       
   255 	delete iOffLineControl;
       
   256 	delete iUtils;
       
   257 	}
       
   258 
       
   259 // Do setentry, leave if there is an error
       
   260 void CImap4ServerMtm::SetEntryL(const TMsvId aId)
       
   261 	{
       
   262 	User::LeaveIfError(iServerEntry->SetEntry(aId));
       
   263 	}
       
   264 
       
   265 // Change entry, leave if error
       
   266 void CImap4ServerMtm::ChangeEntryL(const TMsvEntry& aEntry)
       
   267 	{
       
   268 	User::LeaveIfError(iServerEntry->ChangeEntry(aEntry));
       
   269 	}
       
   270 
       
   271 // Get children, leave if error
       
   272 void CImap4ServerMtm::GetChildrenL(CMsvEntrySelection& aSelection)
       
   273 	{
       
   274 	User::LeaveIfError(iServerEntry->GetChildren(aSelection));
       
   275 	}
       
   276 
       
   277 // remove an id, leave if error, moves to the parent first
       
   278 void CImap4ServerMtm::DeleteEntryL(TMsvId aId)
       
   279 	{
       
   280 	SetEntryL(aId);
       
   281 	SetEntryL(iServerEntry->Entry().Parent());
       
   282 	User::LeaveIfError(iServerEntry->DeleteEntry(aId));
       
   283 	}
       
   284 
       
   285 // Hierarchically make all folders visible/invisible: we go down until we can't
       
   286 // find any more folders, so this won't affect messages with subfolders.
       
   287 //
       
   288 // We don't use the bulk functions as we don't want to affect messages in the
       
   289 // folder, and we have to scan the entries to check for recursion anyway.
       
   290 void CImap4ServerMtm::ChangeVisibilityL(TMsvId aParent, TBool aInvisible)
       
   291 	{
       
   292 	ChangeVisibilityL(aParent, aInvisible, ETrue, KUidMsvFolderEntry);
       
   293 	}
       
   294 
       
   295 void CImap4ServerMtm::ChangeVisibilityL(TMsvId aParent, TBool aInvisible, TBool aRecurse, TUid aType)
       
   296 	{
       
   297 	DBG((iPrimarySession->iSession->LogText(_L8("ChangeVisibilityL(%x, %d)"),aParent,aInvisible)));
       
   298 
       
   299 	// Get children at this level
       
   300 	CMsvEntrySelection* selection=new (ELeave) CMsvEntrySelection;
       
   301 	CleanupStack::PushL(selection);
       
   302 
       
   303 	CMsvEntrySelection* folders=new (ELeave) CMsvEntrySelection;
       
   304 	CleanupStack::PushL(folders);
       
   305 
       
   306 	SetEntryL(aParent);
       
   307 	GetChildrenL(*selection);
       
   308 
       
   309 	if (selection->Count())
       
   310 		{
       
   311 		DBG((iPrimarySession->iSession->LogText(_L8("  Found %d children"),selection->Count())));
       
   312 
       
   313 		for(TInt child=0;child<selection->Count();child++)
       
   314 			{
       
   315 			// Move to this child
       
   316 			SetEntryL((*selection)[child]);
       
   317 			TMsvEntry message=iServerEntry->Entry();
       
   318 
       
   319 			DBG((iPrimarySession->iSession->LogText(_L8("  type %x visible %d"),message.iType,message.Visible())));
       
   320 			
       
   321 			// Is this the type we want to change?
       
   322 			if (message.iType==aType)
       
   323 				{
       
   324 				// Add to selection to do bulk change on, if necessary
       
   325 				if ((message.Visible() && aInvisible) ||
       
   326 					(!message.Visible() && !aInvisible))
       
   327 					{
       
   328 					DBG((iPrimarySession->iSession->LogText(_L8("  Adding %x to change list"),message.Id())));
       
   329 
       
   330 					folders->AppendL(message.Id());
       
   331 					}
       
   332 				}
       
   333 			
       
   334 			// Recurse downwards
       
   335 			if (aRecurse && message.iType==KUidMsvFolderEntry)
       
   336 				ChangeVisibilityL(message.Id(),aInvisible,aRecurse,aType);
       
   337 			}
       
   338 
       
   339 		// Change its visibility off all children if necessary
       
   340 		if (folders->Count())
       
   341 			{
       
   342 			// Do the change to the invisible flag (actual constant for the
       
   343 			// flag we want is private :( )
       
   344 			SetEntryL(aParent);
       
   345 			User::LeaveIfError(iServerEntry->ChangeAttributes(*folders,
       
   346 								aInvisible?0:KMsvVisibilityAttribute,
       
   347 								aInvisible?KMsvVisibilityAttribute:0));
       
   348 			}
       
   349 		}
       
   350 
       
   351 	// Release the service entry
       
   352 	SetEntryL(KMsvNullIndexEntryId);
       
   353 
       
   354 	// Get rid of selection
       
   355 	CleanupStack::PopAndDestroy(2);
       
   356 	}
       
   357 void CImap4ServerMtm::ClearNewFlagL(TMsvId aParent)
       
   358 	{
       
   359 	// Get children at this level
       
   360 	CMsvEntrySelection* selection=new (ELeave) CMsvEntrySelection;
       
   361 	CleanupStack::PushL(selection);
       
   362 	CMsvEntrySelection* msgs=new (ELeave) CMsvEntrySelection;
       
   363 	CleanupStack::PushL(msgs);
       
   364 	SetEntryL(aParent);
       
   365 	GetChildrenL(*selection);
       
   366 	// for each child
       
   367 	TInt count=selection->Count();
       
   368 	for(TInt child=0;child<count;child++)
       
   369 		{
       
   370 		SetEntryL((*selection)[child]);
       
   371 		TMsvEntry entry=iServerEntry->Entry();
       
   372 		if (entry.New()&& entry.iType==KUidMsvMessageEntry)
       
   373 			msgs->AppendL(entry.Id());
       
   374 		// if this is a folder then recurse
       
   375 		if (entry.iType==KUidMsvFolderEntry)
       
   376 			ClearNewFlagL((*selection)[child]);
       
   377 		}
       
   378 	if (msgs->Count())// change attribute only when it has finished looking at all the children
       
   379 		{
       
   380 		SetEntryL(aParent);
       
   381 		User::LeaveIfError(iServerEntry->ChangeAttributes(*msgs,0,KMsvNewAttribute));
       
   382 		iPrimarySession->iSession->LogText(_L8("number of new msgs = (%d)"),msgs->Count());
       
   383 		}
       
   384 	CleanupStack::PopAndDestroy(2); // selection,msgs
       
   385 	}
       
   386 
       
   387 
       
   388 
       
   389 // Mark service as on or offline
       
   390 void CImap4ServerMtm::MarkOnOrOfflineL(const TBool aOnline)
       
   391 	{
       
   392 	// Mark service entry as on/offline	
       
   393 	SetEntryL(iServiceId);
       
   394 	TMsvEntry entry=iServerEntry->Entry();
       
   395 	entry.SetConnected(aOnline);
       
   396 	ChangeEntryL(entry);
       
   397 
       
   398 	// Release the service entry
       
   399 	SetEntryL(KMsvNullIndexEntryId);
       
   400 
       
   401 	// Going offline?
       
   402 	if (!aOnline && iServiceSettings->DisconnectedUserMode())
       
   403 		{
       
   404 		// We're an expert user going offline: don't touch anything
       
   405 		return;
       
   406 		}
       
   407 
       
   408 	// Mark all immediate children of the service as invisible
       
   409 	if (!aOnline)
       
   410 		ChangeVisibilityL(iServiceId,!aOnline);
       
   411 	}
       
   412 
       
   413 // Do the misc bits we need to when we've gone offline
       
   414 void CImap4ServerMtm::GoneOffline()
       
   415 	{
       
   416 	DBG((iPrimarySession->iSession->LogText(_L8("GoneOffline called"))));
       
   417 
       
   418 	// Cancel sessions: parking might be dangerous otherwise
       
   419 	iPrimarySession->Cancel();
       
   420 	iSecondarySession->Cancel();
       
   421 
       
   422 	// Park entries (in case a move entry has been left somewhere dangerous by a
       
   423 	// leave)
       
   424 	iPrimarySession->iSession->Park();
       
   425 	iSecondarySession->iSession->Park();
       
   426 
       
   427 	// Only do this is we have a valid service - we may not, due to being called
       
   428 	// both by the state machine and the progress entry
       
   429 	if (iServiceId)
       
   430 		{
       
   431 		// Offline, make folders invisible if we're not a disconnected mode user
       
   432 		TRAP_IGNORE(MarkOnOrOfflineL(EFalse));
       
   433 	
       
   434 		// Clear serviceid, it's not valid anymore
       
   435 		iServiceId=0;
       
   436 		}
       
   437 
       
   438 	// Settings can be dumped now
       
   439 	delete iServiceSettings;
       
   440 	iServiceSettings=NULL;
       
   441 
       
   442 	// We can now be deleted
       
   443 	iCanBeDeletedNow=ETrue;
       
   444 	}
       
   445 
       
   446 // Check selection: all entries should be of appropriate
       
   447 // type. Messages in this context means complete messages, not RFC888
       
   448 // parts of another message. parts means attachment or text
       
   449 // bodies. Make a local copy of valid entries
       
   450 
       
   451 TInt CImap4ServerMtm::CheckSelectionL(const CMsvEntrySelection& aSelection,
       
   452 									  CMsvEntrySelection* aLocalCopy,
       
   453 									  const TBool aMessages,
       
   454 									  const TBool aParts,
       
   455 									  const TBool aFolders,
       
   456 									  const TBool aIsInService)
       
   457 	{
       
   458 	// Reset copy selection
       
   459 	aLocalCopy->Reset();
       
   460 
       
   461 	// Check all entries are messages
       
   462 	for(TInt a=0;a<aSelection.Count();a++)
       
   463 		{
       
   464 		// Does entry exist?
       
   465 		TBool addIt = EFalse;
       
   466 
       
   467 		if (iServerEntry->SetEntry(aSelection[a])==KErrNone)
       
   468 			{
       
   469 			TUid type = iServerEntry->Entry().iType;
       
   470 			if ((aMessages && type==KUidMsvMessageEntry) ||
       
   471 				(aParts && (type==KUidMsvEmailTextEntry || type==KUidMsvAttachmentEntry || type==KUidMsvMessageEntry)) ||
       
   472 				(aFolders && type==KUidMsvFolderEntry))
       
   473 				{
       
   474 				TBool inEnclosingMessage=EFalse;
       
   475 
       
   476 				// Do we need to check if it's in the local service or
       
   477 				// if it is a complete message
       
   478 				if (aIsInService || (!aParts && type==KUidMsvMessageEntry))
       
   479 					{
       
   480 					// Work up the tree until we get to the service or the root
       
   481 					do
       
   482 						{
       
   483 						SetEntryL(iServerEntry->Entry().Parent());
       
   484 						if (iServerEntry->Entry().iType==KUidMsvMessageEntry)
       
   485 							inEnclosingMessage=ETrue;
       
   486 						}
       
   487 					while(iServerEntry->Entry().iType!=KUidMsvServiceEntry &&
       
   488 						  iServerEntry->Entry().Id()!=KMsvRootIndexEntryId);		
       
   489 	
       
   490 					// Are we at the service that this MTM referrs to?
       
   491 					// SJM: if offline iServiceId==0 so allow all
       
   492 					if (!aIsInService || iServiceId==0 || iServerEntry->Entry().Id()==iServiceId)
       
   493 						{
       
   494 						// it's OK if it is not a message type (in
       
   495 						// which case it has already been checked and
       
   496 						// passed) or it is not within an enclosing message
       
   497 						if (type!=KUidMsvMessageEntry || !inEnclosingMessage || aParts)
       
   498 							addIt = ETrue;
       
   499 						}
       
   500 					}
       
   501 				else
       
   502 					{
       
   503 					// Add to local copy
       
   504 					addIt = ETrue;
       
   505 					}
       
   506 				}
       
   507 			}
       
   508 
       
   509 		if (addIt)
       
   510 			aLocalCopy->AppendL(aSelection[a]);
       
   511 #ifdef _DEBUG
       
   512 		// UI shouldn't really be giving us bogus items so panic
       
   513 		else
       
   514 			gPanic(EInvalidMsvTypeToCommand);
       
   515 #endif
       
   516 		}
       
   517 
       
   518 	// Anything to do?
       
   519 	if (!aLocalCopy->Count())
       
   520 		{
       
   521 		// Nothing valid to work with
       
   522 		User::RequestComplete(iRequest,KErrNotSupported);
       
   523 		return(KErrNotSupported);
       
   524 		}
       
   525 	
       
   526 	// All OK, the selection isn't empty
       
   527 	return(KErrNone);
       
   528 	}
       
   529 
       
   530 // aId has been unsubscribed. If it has no visible child folders then
       
   531 // make it invisible and check its parent with the same test
       
   532 void CImap4ServerMtm::PropagateInvisibleFlagL(TMsvId aId)
       
   533 	{
       
   534 	DBG((iPrimarySession->iSession->LogText(_L8("PropagateInvisibleFlagL: 0x%x"), aId)));
       
   535 
       
   536 	// finish if we've reached the top
       
   537 	if (aId == KMsvRootIndexEntryId)
       
   538 		return;
       
   539 	
       
   540 	SetEntryL(aId);
       
   541 
       
   542 	// finish if we've reached a service
       
   543 	if (iServerEntry->Entry().iType == KUidMsvServiceEntry)
       
   544 		return;
       
   545 
       
   546 	// return if we've found a subscribed folder since we can't make
       
   547 	// it invisible
       
   548 	if (((TMsvEmailEntry)iServerEntry->Entry()).LocalSubscription())
       
   549 		return;
       
   550 	
       
   551 	// check the children of this unsubscribed folder
       
   552 	CMsvEntrySelection* selection=new (ELeave) CMsvEntrySelection;
       
   553 	CleanupStack::PushL(selection);
       
   554 
       
   555 	GetChildrenL(*selection);
       
   556 
       
   557 	TBool visible=EFalse;
       
   558 	for (TInt i=0; i < selection->Count(); i++)
       
   559 		{
       
   560 		SetEntryL((*selection)[i]);
       
   561 
       
   562 		// look for a visible folder
       
   563 		TMsvEmailEntry entry = (TMsvEmailEntry)iServerEntry->Entry();
       
   564 		if (entry.iType == KUidMsvFolderEntry && entry.Visible())
       
   565 			{
       
   566 			visible=ETrue;
       
   567 			break;
       
   568 			}
       
   569 		}
       
   570 	
       
   571 	CleanupStack::PopAndDestroy(); // selection
       
   572 
       
   573 	// if no child folders were visible then make this folder
       
   574 	// invisible and continue up
       
   575 	if (!visible)
       
   576 		{
       
   577 		SetEntryL(aId);
       
   578 		
       
   579 		// make this invisible
       
   580 		TMsvEntry entry = iServerEntry->Entry();
       
   581 		entry.SetVisible(EFalse);
       
   582 		ChangeEntryL(entry);
       
   583 
       
   584 		// go up
       
   585 		PropagateInvisibleFlagL(entry.Parent());
       
   586 		}
       
   587 	}
       
   588 
       
   589 // Simply change local subscription flag on a folder immediately: This is used
       
   590 // as opposed to ChangeL() as this operation can occur offline.
       
   591 
       
   592 // SJM: If SubscribeStrategy is UpdateRemote or UpdateBoth then doing
       
   593 // this should trigger a RemoteSubscription?
       
   594 
       
   595 TInt CImap4ServerMtm::SetLocalSubscription(const TMsvId aFolder, TBool aSubscribed)
       
   596 	{
       
   597 	TInt err;
       
   598 
       
   599 	// Move to the entry
       
   600 	if ((err=iServerEntry->SetEntry(aFolder))!=KErrNone)
       
   601 		return(err);
       
   602 
       
   603 	// Check it's a folder
       
   604 	if (iServerEntry->Entry().iType!=KUidMsvFolderEntry)
       
   605 		return(KErrNotSupported);
       
   606 
       
   607 	DBG((iPrimarySession->iSession->LogText(_L8("SetLocalSubscription: 0x%x %d"), aFolder, aSubscribed)));
       
   608 		
       
   609 	// Twiddle flag
       
   610 	TMsvEmailEntry entry=iServerEntry->Entry();
       
   611 	entry.SetLocalSubscription(aSubscribed);
       
   612 	return(iServerEntry->ChangeEntry(entry));
       
   613 	}
       
   614 
       
   615 
       
   616 // Perform a general move/copy function: this tidies up a lot of the Copy/Move
       
   617 // MTM specifics into one place
       
   618 void CImap4ServerMtm::MtmCommandL(const TInt aType,const CMsvEntrySelection& aSelection,
       
   619 								  TMsvId aDestination, TRequestStatus& aStatus)
       
   620 	{
       
   621 	iRequest=&aStatus;
       
   622 	// reset error code
       
   623 	iProgressErrorCode=KErrNone;
       
   624 	
       
   625 	// Is source remote? Ensure we check it's from our service
       
   626 	TBool checksource=ETrue;
       
   627 	if (aType==EMtmCopyFromLocal || aType==EMtmMoveFromLocal)
       
   628 		checksource=EFalse;
       
   629 
       
   630 	// we can only handle parts of messages on Populate
       
   631 	TBool handleParts=EFalse;
       
   632 	if (aType==EMtmPopulate||aType==EMtmCopyToLocal)
       
   633 		handleParts=ETrue;
       
   634 	
       
   635 	// Check selection contains messages, or maybe parts
       
   636 	if (CheckSelectionL(aSelection,iSelection,ETrue,handleParts,EFalse,checksource))
       
   637 		return;
       
   638 
       
   639 	// Save destination
       
   640 	iDestination=aDestination;
       
   641 
       
   642 	// Are we online?
       
   643 	if (!iPrimarySession->iSession->Connected())
       
   644 		{
       
   645 		iProgressMsgsToDo=iSelection->Count();
       
   646 		iProgressMsgsDone=0;
       
   647 
       
   648 		// set state for dorunl
       
   649 		switch(aType)
       
   650 			{
       
   651 		case EMtmCopyToLocal:			
       
   652 			iState=iSavedState=EMtmStateOffLineCopyToLocal;
       
   653 			iRequestedOperation=TImap4GenericProgress::EOffLineCopyToLocal;
       
   654 			break;
       
   655 
       
   656 		case EMtmCopyFromLocal:
       
   657 			iState=iSavedState=EMtmStateOffLineCopyFromLocal;
       
   658 			iRequestedOperation=TImap4GenericProgress::EOffLineCopyFromLocal;
       
   659 			break;
       
   660 
       
   661 		case EMtmCopyWithinService:
       
   662 			iState=iSavedState=EMtmStateOffLineCopyWithinService;
       
   663 			iRequestedOperation=TImap4GenericProgress::EOffLineCopyWithinService;
       
   664 			break;
       
   665 
       
   666 		case EMtmMoveToLocal:
       
   667 			iState=iSavedState=EMtmStateOffLineMoveToLocal;
       
   668 			iRequestedOperation=TImap4GenericProgress::EOffLineMoveToLocal;
       
   669 			break;
       
   670 
       
   671 		case EMtmMoveFromLocal:
       
   672 			iState=iSavedState=EMtmStateOffLineMoveFromLocal;
       
   673 			iRequestedOperation=TImap4GenericProgress::EOffLineMoveFromLocal;
       
   674 			break;
       
   675 
       
   676 		case EMtmMoveWithinService:
       
   677 			iState=iSavedState=EMtmStateOffLineMoveWithinService;
       
   678 			iRequestedOperation=TImap4GenericProgress::EOffLineMoveWithinService;
       
   679 			break;
       
   680 
       
   681 		case EMtmPopulate:
       
   682 			{
       
   683 			iState=iSavedState=EMtmStateOffLinePopulate;
       
   684 			iRequestedOperation=TImap4GenericProgress::EOffLinePopulate;
       
   685 			break;
       
   686 			}
       
   687 		default:
       
   688 			break;
       
   689 			}
       
   690 		TRequestStatus* pS=(&iStatus);
       
   691 		User::RequestComplete(pS,KErrNone);
       
   692 		SetActive();
       
   693 		}
       
   694 	else
       
   695 		{
       
   696 		TRequestStatus* status;
       
   697 
       
   698 		// Default to primary session
       
   699 		iCurrentSession=iPrimarySession;
       
   700 		status=iCurrentSession->SessionStatus();
       
   701 
       
   702 		// Initialise messages to do, etc
       
   703 		iProgressMsgsToDo=iSelection->Count();
       
   704 		iProgressMsgsDone=0;
       
   705 
       
   706 		switch(aType)
       
   707 			{
       
   708 		case EMtmPopulate:
       
   709 		case EMtmCopyToLocal:
       
   710 			// We're online: is the primary session busy?
       
   711  			if( iBackgroundSyncInProgress || iCurrentSession->iSession->IsCancelling() ||
       
   712  							 		iPrimarySession->iSession->Busy())
       
   713 				{
       
   714 				DBG((iPrimarySession->iSession->LogText(_L8("Primary session busy, using secondary"))));
       
   715 
       
   716 				// We'll have to use the secondary session
       
   717 				iCurrentSession=iSecondarySession;
       
   718 
       
   719 				// Is the secondary session connected?
       
   720 				if (!iCurrentSession->iSession->Connected())
       
   721 					{
       
   722 					DBG((iPrimarySession->iSession->LogText(_L8("Connecting secondary"))));
       
   723 
       
   724 					// We need to connect the secondary session before
       
   725 					// continuing with the fetch. Do it. The source message
       
   726 					// selection has been checked and stored in iSelection,
       
   727 					// so it should be safe until the connect goes through
       
   728 					// for later issue.
       
   729 					iState=EMtmStateSecondaryConnect;
       
   730 					iSavedState=aType == EMtmPopulate ? EMtmStatePopulate : EMtmStateCopyToLocal;
       
   731 
       
   732 					// Issue the connect
       
   733 					iCurrentSession->StartL(this);
       
   734 					status=iCurrentSession->SessionStatus();
       
   735 					// Providing the reference of primary session 
       
   736 					iCurrentSession->iSession->SetPrimarySession(iPrimarySession);
       
   737 					iCurrentSession->iSession->ConnectL(*status,iServiceId);
       
   738 					break;
       
   739 					}
       
   740 				else if( iCurrentSession->iSession->IsCancelling() )
       
   741 					{
       
   742 					// Opps! Cannot do the populate currently - server busy.
       
   743 					DBG((iPrimarySession->iSession->LogText(_L8("Secondary already cancelling"))));
       
   744 					
       
   745 					User::RequestComplete(iRequest,KErrServerBusy);
       
   746 					return;
       
   747 					}
       
   748 
       
   749 				DBG((iPrimarySession->iSession->LogText(_L8("Secondary already connected, reusing"))));
       
   750 				}
       
   751 
       
   752 			// Calculate the total size of the messages to be downloaded in this selection.
       
   753 			iTotalSize = iCurrentSession->iSession->CalculateDownloadSizeL(*iSelection);
       
   754 
       
   755 			// Select relevant folder
       
   756 			iCurrentSession->StartL(this);
       
   757 			status=iCurrentSession->SessionStatus();
       
   758 			iUtils->SetUpLogMessageL((*iSelection)[0]);
       
   759 			if (aType == EMtmPopulate)
       
   760 				{
       
   761 				iState = EMtmStatePopulate;
       
   762 				// compound need to know the number of msgs to suspend imap idle calls if > 1
       
   763 				if(iProgressMsgsToDo > 0)
       
   764 					{
       
   765 					iCurrentSession->iCompound->SetMessageCount(iProgressMsgsToDo);
       
   766 					}
       
   767 				DBG((iPrimarySession->iSession->LogText(_L8("CImapMTM::MTMCommandL(): Calling iCurrentSession->iCompound->Populate()"))));
       
   768  				iCurrentSession->iCompound->PopulateL(*status,(*iSelection)[0],iPartialMailInfo);
       
   769 				}
       
   770 			else
       
   771 				{
       
   772 				iState = EMtmStateCopyToLocal;
       
   773 				iCurrentSession->iCompound->CopyToLocalL(*status,(*iSelection)[0],iDestination);
       
   774 				}
       
   775 			break;
       
   776 
       
   777 		case EMtmMoveToLocal:
       
   778 			// We're online, are we busy? (it's a write op, and so we must use the
       
   779 			// primary session)
       
   780 			if( iBackgroundSyncInProgress || iCurrentSession->iSession->IsCancelling() )
       
   781 				{
       
   782 				// Can't do it, we're busy
       
   783 				User::RequestComplete(iRequest,KErrServerBusy);
       
   784 				return;
       
   785 				}
       
   786 
       
   787 			// Calculate the total size of the messages to be downloaded in this selection.
       
   788 			iTotalSize = iCurrentSession->iSession->CalculateDownloadSizeL(*iSelection);
       
   789 
       
   790 			// Select relevant folder
       
   791 			iCurrentSession->StartL(this);
       
   792 			iState=EMtmStateMoveToLocal;
       
   793 			iUtils->SetUpLogMessageL((*iSelection)[0]);
       
   794 			iCurrentSession->iCompound->MoveToLocalL(*status,(*iSelection)[0],iDestination);
       
   795 			break;
       
   796 
       
   797 		case EMtmCopyFromLocal:
       
   798 		case EMtmMoveFromLocal:
       
   799 
       
   800 			// As this is a write operation, is must be done on the primary session:
       
   801 			// is it free?
       
   802 			if( iBackgroundSyncInProgress || iCurrentSession->iSession->IsCancelling() )
       
   803 				{
       
   804 				// Can't do it
       
   805 				User::RequestComplete(iRequest,KErrServerBusy);
       
   806 				return;
       
   807 				}
       
   808 
       
   809 			// Calculate the total size of the messages to be downloaded in this selection.
       
   810 			iTotalSize = iCurrentSession->iSession->CalculateDownloadSizeL(*iSelection);
       
   811 
       
   812 			iState=(aType==EMtmCopyFromLocal)?EMtmStateCopyFromLocal:EMtmStateMoveFromLocal;
       
   813 
       
   814 
       
   815 			// Start the first operation
       
   816 			iCurrentSession->StartL(this);
       
   817 			if (aType==EMtmCopyFromLocal)
       
   818 				iCurrentSession->iCompound->CopyFromLocalL(*status,(*iSelection)[0],iDestination);
       
   819 			else
       
   820 				iCurrentSession->iCompound->MoveFromLocalL(*status,(*iSelection)[0],iDestination);
       
   821 			break;
       
   822 
       
   823 		case EMtmCopyWithinService:
       
   824 		case EMtmMoveWithinService:
       
   825 			// As this is a write operation, is must be done on the primary session:
       
   826 			// is it free?
       
   827 			if( iBackgroundSyncInProgress || iCurrentSession->iSession->IsCancelling() )
       
   828 				{
       
   829 				// Can't do it
       
   830 				User::RequestComplete(iRequest,KErrServerBusy);
       
   831 				return;
       
   832 				}
       
   833 
       
   834 			// Set the state, as we may be dealing with multiple entries
       
   835 			iState=(aType==EMtmCopyWithinService)?EMtmStateCopyWithinService:
       
   836 												  EMtmStateMoveWithinService;
       
   837 
       
   838 			// Do the copy with the compound
       
   839 			iCurrentSession->StartL(this);
       
   840 			if (aType==EMtmCopyWithinService)
       
   841 				iCurrentSession->iCompound->CopyWithinServiceL(*status,*iSelection,iDestination);
       
   842 			else
       
   843 				iCurrentSession->iCompound->MoveWithinServiceL(*status,*iSelection,iDestination);
       
   844 			break;
       
   845 			}
       
   846 		}
       
   847 	}
       
   848 
       
   849 
       
   850 // CopyToLocal fetches message parts into the mirror: aDestination is currently
       
   851 // not used. This is the only command which can cause the second session to
       
   852 // connect, as it is for fetching *only* (not 'modifiable' commands which may
       
   853 // cause the current synchronisation in the primary session to hiccup). This
       
   854 // also rules out MoveToLocal, as it involves a delete on the remote server.
       
   855 void CImap4ServerMtm::CopyToLocalL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)
       
   856 	{
       
   857 	aStatus=KRequestPending;
       
   858 
       
   859 	LOG_COMMANDS((_L8("MTMCOMMAND CopyToLocal(%d items to %x)"),aSelection.Count(),aDestination));
       
   860 
       
   861 	iRequestedOperation=TImap4GenericProgress::ECopyToLocal;
       
   862 	iGetMailOptions=EGetImap4EmailBodyTextAndAttachments;
       
   863 	MtmCommandL(EMtmCopyToLocal,aSelection,aDestination,aStatus);
       
   864 	}
       
   865 
       
   866 // Move To Local moves a message from the remote server to a local folder:
       
   867 // this is performed as a fetch, then a delete on the remote server.
       
   868 void CImap4ServerMtm::MoveToLocalL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)
       
   869 	{
       
   870 	aStatus=KRequestPending;
       
   871 
       
   872 	LOG_COMMANDS((_L8("MTMCOMMAND MoveToLocal(%d items to %x)"),aSelection.Count(),aDestination));
       
   873 
       
   874 	// We can't do a 'movetolocal' with the destination being the same as the
       
   875 	// source, as then the mirror will be out of sync. We must be moving to somewhere
       
   876 	// outside this service. Check this.
       
   877 	if (!iOffLineControl->IdIsLocalL(aDestination))
       
   878 		{
       
   879 		TRequestStatus* status=&aStatus;
       
   880 		User::RequestComplete(status,KErrNotSupported);
       
   881 		}
       
   882 	else
       
   883 		{
       
   884 		iRequestedOperation=TImap4GenericProgress::EMoveToLocal;
       
   885 		iGetMailOptions=EGetImap4EmailBodyTextAndAttachments;
       
   886 		MtmCommandL(EMtmMoveToLocal,aSelection,aDestination,aStatus);
       
   887 		}
       
   888 	}
       
   889 
       
   890 // CopyFromLocal appends entire messages in the mirror to the server.
       
   891 void CImap4ServerMtm::CopyFromLocalL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)
       
   892 	{
       
   893 	aStatus=KRequestPending;
       
   894 
       
   895 	LOG_COMMANDS((_L8("MTMCOMMAND CopyFromLocal(%d items to %x)"),aSelection.Count(),aDestination));
       
   896 
       
   897 	iRequestedOperation=TImap4GenericProgress::ECopyFromLocal;
       
   898 	MtmCommandL(EMtmCopyFromLocal,aSelection,aDestination,aStatus);
       
   899 	}
       
   900 
       
   901 // Does a CopyFromLocal (ie, IMAP APPEND of the message), then deletes the local message
       
   902 // if it was sucessful.
       
   903 void CImap4ServerMtm::MoveFromLocalL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)
       
   904 	{
       
   905 	aStatus=KRequestPending;
       
   906 
       
   907 	LOG_COMMANDS((_L8("MTMCOMMAND MoveFromLocal(%d items to %x)"),aSelection.Count(),aDestination));
       
   908 
       
   909 	iRequestedOperation=TImap4GenericProgress::EMoveFromLocal;
       
   910 	MtmCommandL(EMtmMoveFromLocal,aSelection,aDestination,aStatus);
       
   911 	}
       
   912 
       
   913 // CopyWithinService copies entire messages to other folders on the server, using
       
   914 // the IMAP COPY command.
       
   915 void CImap4ServerMtm::CopyWithinServiceL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)
       
   916 	{
       
   917 	aStatus=KRequestPending;
       
   918 
       
   919 	LOG_COMMANDS((_L8("MTMCOMMAND CopyWithinService(%d items to %x)"),aSelection.Count(),aDestination));
       
   920 
       
   921 	iRequestedOperation=TImap4GenericProgress::ECopyWithinService;
       
   922 	MtmCommandL(EMtmCopyWithinService,aSelection,aDestination,aStatus);
       
   923 	}
       
   924 
       
   925 // MoveWithinService copies entire messages to other folders on the server, using
       
   926 // the IMAP COPY command, then deletes the original if the copy was sucessful,
       
   927 // so performing a move.
       
   928 void CImap4ServerMtm::MoveWithinServiceL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)
       
   929 	{
       
   930 	aStatus=KRequestPending;
       
   931 
       
   932 	LOG_COMMANDS((_L8("MTMCOMMAND MoveWithinService(%d items to %x)"),aSelection.Count(),aDestination));
       
   933 
       
   934 	iRequestedOperation=TImap4GenericProgress::EMoveWithinService;
       
   935 	MtmCommandL(EMtmMoveWithinService,aSelection,aDestination,aStatus);
       
   936 	}
       
   937 
       
   938 void CImap4ServerMtm::UndeleteAllL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
       
   939 	{
       
   940 	aStatus = KRequestPending;
       
   941 	LOG_COMMANDS((_L8("MTMCOMMAND UndeleteAll(%d items)"),aSelection.Count()));
       
   942 	if(IsActive())
       
   943 		{
       
   944 		TRequestStatus* request = &aStatus;
       
   945 		User::RequestComplete(request,KErrImapServerBusy);
       
   946 		return;
       
   947 		}
       
   948 		
       
   949 	iRequest=&aStatus;
       
   950 	iProgressErrorCode=KErrNone;
       
   951 
       
   952 	// Check selection contains only messages in the service
       
   953 	if (CheckSelectionL(aSelection,iSelection,ETrue,EFalse,EFalse,ETrue))
       
   954 		return;
       
   955 
       
   956 	iRequestedOperation=TImap4GenericProgress::EOffLineUndelete;
       
   957 
       
   958 	iProgressMsgsToDo=iSelection->Count();
       
   959 	iProgressMsgsDone=0;
       
   960 	iState=iSavedState=EMtmStateOffLineUndelete;
       
   961 
       
   962 	TRequestStatus* pS=(&iStatus);
       
   963 	User::RequestComplete(pS,KErrNone);
       
   964 	SetActive();
       
   965 	}
       
   966 
       
   967 
       
   968 void CImap4ServerMtm::DeleteAllL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
       
   969 	{
       
   970 	aStatus=KRequestPending;
       
   971 
       
   972 	LOG_COMMANDS((_L8("MTMCOMMAND DeleteAll(%d items)"),aSelection.Count()));
       
   973 
       
   974 	iRequest=&aStatus;
       
   975 	// reset error code
       
   976 	iProgressErrorCode=KErrNone;
       
   977 
       
   978 	if (PruneMessages(aSelection))
       
   979 		// Was this call to DeleteAllL an instruction to delete local parts of a message ?
       
   980 		// If so then we don't need to continue.
       
   981 		return;
       
   982    
       
   983 	// Are we online?
       
   984 	if (!iPrimarySession->iSession->Connected())
       
   985 		{
       
   986 		// SJM: Surely we need something like...
       
   987 		// Check selection contains only messages - not folders
       
   988 		if (CheckSelectionL(aSelection,iSelection,ETrue,EFalse,EFalse,EFalse))
       
   989 			return;
       
   990 
       
   991 		iRequestedOperation=TImap4GenericProgress::EOffLineDelete;
       
   992 
       
   993 		iProgressMsgsToDo=iSelection->Count();
       
   994 		iProgressMsgsDone=0;
       
   995 		iState=iSavedState=EMtmStateOffLineDelete;
       
   996 
       
   997 		TRequestStatus* pS=(&iStatus);
       
   998 		User::RequestComplete(pS,KErrNone);
       
   999 		SetActive();
       
  1000 		}
       
  1001 	else
       
  1002 		{
       
  1003 		iRequestedOperation=TImap4GenericProgress::EDelete;
       
  1004 
       
  1005 		// We need to do this in the primary session: is it busy?
       
  1006 		if (iBackgroundSyncInProgress || iPrimarySession->iSession->IsCancelling() ||
       
  1007 		    iPrimarySession->iSession->Busy())
       
  1008 			{
       
  1009 			// It's busy, we can't do it
       
  1010 			User::RequestComplete(iRequest,KErrServerBusy);
       
  1011 			return;
       
  1012 			}
       
  1013 
       
  1014 		// Message or folder to delete?
       
  1015 		DBG((iPrimarySession->iSession->LogText(_L8("First is %x"),aSelection[0])));
       
  1016 
       
  1017 		SetEntryL(aSelection[0]);
       
  1018 		if (iServerEntry->Entry().iType==KUidMsvMessageEntry)
       
  1019 			{
       
  1020 			DBG((iCurrentSession->iSession->LogText(_L8("Delete message"))));
       
  1021 
       
  1022 			// Check selection contains only messages
       
  1023 			if (CheckSelectionL(aSelection,iSelection,ETrue,EFalse,EFalse,ETrue))
       
  1024 				return;
       
  1025 
       
  1026 			iProgressMsgsToDo=iSelection->Count();
       
  1027 			iProgressMsgsDone=0;
       
  1028 			// Select parent folder of message
       
  1029 			iCurrentSession=iPrimarySession;
       
  1030 			iState=iSavedState=EMtmStateDelete;
       
  1031 			TRequestStatus* status=iCurrentSession->SessionStatus();
       
  1032 			iCurrentSession->iCompound->DeleteL(*status,*iSelection);
       
  1033 			iCurrentSession->StartL(this);
       
  1034 			}
       
  1035 		else if (iServerEntry->Entry().iType==KUidMsvFolderEntry)
       
  1036 			{
       
  1037 			DBG((iCurrentSession->iSession->LogText(_L8("Delete folder"))));
       
  1038 
       
  1039 			// Check selection contains only folders
       
  1040 			if (CheckSelectionL(aSelection,iSelection,EFalse,EFalse,ETrue,ETrue))
       
  1041 				return;
       
  1042 
       
  1043 			// Delete folder
       
  1044 			iCurrentSession=iPrimarySession;
       
  1045 			iState=iSavedState=EMtmStateDeleteFolder;
       
  1046 			TRequestStatus* status=iCurrentSession->SessionStatus();
       
  1047 			iCurrentSession->iCompound->DeleteFolderL(*status,(*iSelection)[0]);
       
  1048 			iCurrentSession->StartL(this);
       
  1049 			}
       
  1050 		else
       
  1051 			gPanic(EDeleteOfUnknownType);
       
  1052 		}
       
  1053 	}
       
  1054 
       
  1055 // Create: make a folder or mailbox. Can only happen online
       
  1056 void CImap4ServerMtm::CreateL(TMsvEntry aNewEntry, TRequestStatus& aStatus)
       
  1057 	{
       
  1058 	LOG_COMMANDS((_L8("MTMCOMMAND Create(parent %x)"),aNewEntry.Parent()));
       
  1059 
       
  1060 	aStatus=KRequestPending;
       
  1061 	iRequest=&aStatus;
       
  1062 	// reset error code
       
  1063 	iProgressErrorCode=KErrNone;
       
  1064 
       
  1065 	// Creating a folder?
       
  1066 	if (aNewEntry.iType!=KUidMsvFolderEntry)
       
  1067 		{
       
  1068 		// No - illegal op
       
  1069 		User::RequestComplete(iRequest,KErrNotSupported);
       
  1070 		return;
       
  1071 		}
       
  1072 
       
  1073 	// Are we online and not busy?
       
  1074 	if( iBackgroundSyncInProgress || iPrimarySession->iSession->IsCancelling() )
       
  1075 		{
       
  1076 		User::RequestComplete(iRequest,KErrServerBusy);
       
  1077 		return;
       
  1078 		}
       
  1079 
       
  1080 	// Folder or mailbox?
       
  1081 	TBool isfolder=ETrue;
       
  1082 	if (((TMsvEmailEntry)aNewEntry).Mailbox())
       
  1083 		isfolder=EFalse;
       
  1084 
       
  1085 	// Use primary session: issue create folder command
       
  1086 	iState=EMtmStateCreateFolder;
       
  1087 	iCurrentSession=iPrimarySession;
       
  1088 	TRequestStatus* status=iCurrentSession->SessionStatus();
       
  1089 	iCurrentSession->iCompound->CreateL(*status,aNewEntry.Parent(),aNewEntry.iDetails,isfolder);
       
  1090 	iCurrentSession->StartL(this);
       
  1091 	}
       
  1092 
       
  1093 void CImap4ServerMtm::ChangeL(TMsvEntry aNewEntry, TRequestStatus& aStatus)
       
  1094 	{
       
  1095 	LOG_COMMANDS((_L8("MTMCOMMAND Change(%x)"),aNewEntry.Id()));
       
  1096 
       
  1097 	User::LeaveIfError(iServerEntry->SetEntry( aNewEntry.Id() ));
       
  1098 	User::LeaveIfError(iServerEntry->ChangeEntry( aNewEntry ));
       
  1099 
       
  1100 	iRequest=&aStatus;
       
  1101 	// reset error code
       
  1102 	iProgressErrorCode=KErrNone;
       
  1103 	
       
  1104 	User::RequestComplete(iRequest, KErrNone);
       
  1105 	}
       
  1106 
       
  1107 // SJM: Old ChangeL entry. used to be able to update flags as well as
       
  1108 // rename folder. Change to only rename folder as its not obvious how
       
  1109 // you'd pass the flags across
       
  1110 TBool CImap4ServerMtm::RenameFolderL(TMsvId aId, const TImap4RenameFolder& aRename)
       
  1111 	{
       
  1112 	LOG_COMMANDS((_L8("MTMCOMMAND RenameFolder(%x) to %S"),aId,&aRename.iNewName));
       
  1113 
       
  1114 	// Are we online and not busy?
       
  1115 	if( iBackgroundSyncInProgress || iPrimarySession->iSession->IsCancelling() )
       
  1116 		{
       
  1117 		User::RequestComplete(iRequest,KErrServerBusy);
       
  1118 		return EFalse;
       
  1119 		}
       
  1120 
       
  1121 	// Issue a rename command on this object
       
  1122 	iState=EMtmStateRenameFolder;
       
  1123 	iCurrentSession=iPrimarySession;
       
  1124 	TRequestStatus* status=iCurrentSession->SessionStatus();
       
  1125 	iCurrentSession->iCompound->RenameL(*status, aId, aRename.iNewName);
       
  1126 	return ETrue;
       
  1127 	}
       
  1128 
       
  1129 // id can be either the service or anything below it. If it is not the
       
  1130 // service then we move up the tree until we find the service.
       
  1131 void CImap4ServerMtm::LoadSettingsL(TMsvId aId)
       
  1132 	{
       
  1133 	// Old settings shouldn't be hanging about, but...
       
  1134 	if (iServiceSettings)
       
  1135 		{
       
  1136 		delete iServiceSettings;
       
  1137 		iServiceSettings=NULL;
       
  1138 		}
       
  1139 
       
  1140 	// Get somewhere to store service settings
       
  1141 	iServiceSettings=new (ELeave) CImImap4Settings;
       
  1142 
       
  1143 	// find the service
       
  1144 	SetEntryL(aId);
       
  1145 	while (iServerEntry->Entry().iType != KUidMsvServiceEntry)
       
  1146 		SetEntryL(iServerEntry->Entry().Parent());
       
  1147 
       
  1148 	// Get settings for this service
       
  1149 	CEmailAccounts* account = CEmailAccounts::NewLC();
       
  1150 	TImapAccount id;
       
  1151 	id.iImapAccountId = iServerEntry->Entry().MtmData2();  // iMtmData2 of the service entry contains TImapAccountId
       
  1152 	id.iImapAccountName = iServerEntry->Entry().iDetails;
       
  1153 	id.iImapService = iServerEntry->Entry().iServiceId;
       
  1154 	id.iSmtpService = iServerEntry->Entry().iRelatedId;
       
  1155 
       
  1156 	account->LoadImapSettingsL(id, *iServiceSettings);
       
  1157    	CleanupStack::PopAndDestroy(account);    
       
  1158 	}
       
  1159 
       
  1160 void CImap4ServerMtm::StartCommandL(CMsvEntrySelection& aSelection, TInt aCommand, const TDesC8& aParameter, TRequestStatus& aStatus)
       
  1161 	{
       
  1162 	LOG_COMMANDS((_L8("MTMCOMMAND StartCommand(%x)"),aCommand));
       
  1163 	
       
  1164 	iTotalSize = 0;
       
  1165 	aStatus=KRequestPending;
       
  1166 	iRequest=&aStatus;
       
  1167 	// reset error code
       
  1168 	iProgressErrorCode=KErrNone;
       
  1169 	
       
  1170 	if(iPrimarySession->iSession->IsActive())
       
  1171 		LOG_COMMANDS((_L8("CImap4ServerMTM::StartCommand(): iPrimarySession->iSession is ACTIVE")));
       
  1172 	else
       
  1173 		LOG_COMMANDS((_L8("CImap4ServerMTM::StartCommand(): iPrimarySession->iSession is NOT ACTIVE")));
       
  1174 
       
  1175         
       
  1176 	// Who are we sending this request to? Get their session
       
  1177 	iCurrentSession=iPrimarySession;
       
  1178 	TRequestStatus* status=iCurrentSession->SessionStatus();
       
  1179 	
       
  1180 	// Certain commands require that we are online: check that we're online (the command may have
       
  1181 	// been queued when we were online, but we've lost the connection now)
       
  1182 	if (aCommand==KIMAP4MTMSynchronise || aCommand==KIMAP4MTMFullSync ||
       
  1183 		aCommand==KIMAP4MTMInboxNewSync || aCommand==KIMAP4MTMFolderFullSync ||
       
  1184 		aCommand==KIMAP4MTMRenameFolder || aCommand==KIMAP4MTMDisconnect ||
       
  1185 		aCommand==KIMAP4MTMSyncTree || aCommand==KIMAP4MTMSelect)
       
  1186 		{
       
  1187 		if (!iPrimarySession->iSession->Connected())
       
  1188 			{
       
  1189 			// Can't hack this!
       
  1190 			User::RequestComplete(iRequest,KErrDisconnected);
       
  1191 			return;
       
  1192 			}
       
  1193 		}
       
  1194 	
       
  1195 	// Save command, as when it completes we would like to know what happened...
       
  1196 	iState=EMtmStateMiscCommand;
       
  1197 	TBool notComplete=EFalse;
       
  1198 	switch(iLastCommand=aCommand)
       
  1199 		{
       
  1200 		case KIMAP4MTMIsConnected:
       
  1201 			// Are we connected?
       
  1202 			User::RequestComplete(iRequest,
       
  1203 								  iPrimarySession->iSession->Connected()?KErrNone:KErrDisconnected);
       
  1204 			break;
       
  1205 
       
  1206 		case KIMAP4MTMBusy:
       
  1207 			// Are we busy?
       
  1208 			if (iBackgroundSyncInProgress ||
       
  1209 				iSecondarySession->iSession->Busy())
       
  1210 				User::RequestComplete(iRequest,KErrServerBusy);
       
  1211 			else
       
  1212 				User::RequestComplete(iRequest,KErrNone);
       
  1213 			break;
       
  1214 
       
  1215 		case KIMAP4MTMConnect:
       
  1216 		case KIMAP4MTMConnectAndSynchronise:
       
  1217 			if (iPrimarySession->iSession->Busy() ||
       
  1218 			    iPrimarySession->iSession->Connected())
       
  1219 				{
       
  1220 				User::RequestComplete(iRequest,KErrServerBusy);
       
  1221 				}
       
  1222 			else
       
  1223 				{
       
  1224 				iServiceId=aSelection[0];
       
  1225 
       
  1226 				LoadSettingsL(iServiceId);
       
  1227 
       
  1228 				// We want to hang around for this one
       
  1229 				iCanBeDeletedNow=EFalse;
       
  1230 
       
  1231 				// The selection passed through will be any messages selected for download.
       
  1232 				// Inform the session about these as they may potentially be deleted during sync.
       
  1233 				iCurrentSession->iSession->SetSynchronisationSelectionL(aSelection);
       
  1234 
       
  1235 				// Queue a connect
       
  1236 				iRequestedOperation=TImap4GenericProgress::EConnect;
       
  1237 				iCurrentSession->iSession->ConnectL(*status,iServiceId);
       
  1238 
       
  1239 				notComplete = ETrue;
       
  1240 				}
       
  1241 			break;
       
  1242 
       
  1243 		case KIMAP4MTMStartBatch:
       
  1244 			// We're about to receive multiple commands from the client: ensure we
       
  1245 			// stay loaded by faking the CommandExpected() result to be ETrue
       
  1246 			iBatchInProgress=ETrue;
       
  1247 			User::RequestComplete(iRequest,KErrNone);
       
  1248 			break;
       
  1249 
       
  1250 		case KIMAP4MTMEndBatch:
       
  1251 			// Stop faking the CommandExpected(), the client has finished with their
       
  1252 			// batch of commands.
       
  1253 			iBatchInProgress=EFalse;
       
  1254 			User::RequestComplete(iRequest,KErrNone);
       
  1255 			break;
       
  1256 
       
  1257 		case KIMAP4MTMCancelBackgroundSynchronise:
       
  1258 			// Anything to cancel?
       
  1259 			if (iBackgroundSyncInProgress)
       
  1260 				{
       
  1261 				// Cancel it
       
  1262 				iPrimarySession->Cancel();
       
  1263 				iBackgroundSyncInProgress=EFalse;
       
  1264 				User::RequestComplete(iRequest,KErrCancel);
       
  1265 				}
       
  1266 			else
       
  1267 				User::RequestComplete(iRequest,KErrNone);
       
  1268 			break;
       
  1269 
       
  1270 		case KIMAP4MTMSelect:
       
  1271 			// Queue a selection command
       
  1272 			iRequestedOperation=TImap4GenericProgress::ESelect;
       
  1273 			iCurrentSession->iCompound->SelectL(*status,aSelection[0]);
       
  1274 			notComplete = ETrue;
       
  1275 			break;
       
  1276 
       
  1277 		case KIMAP4MTMSynchronise:
       
  1278 			// Queue a synchronise operation
       
  1279 			iRequestedOperation=TImap4GenericProgress::ESync;
       
  1280 			if (iClearNewFlagOnNextSync)
       
  1281 				{
       
  1282 				ClearNewFlagL(iServiceId);
       
  1283 				iClearNewFlagOnNextSync = EFalse;
       
  1284 				}
       
  1285 			
       
  1286 			iCurrentSession->iCompound->SynchroniseL(*status);
       
  1287 			notComplete = ETrue;
       
  1288 			break;
       
  1289 
       
  1290 		case KIMAP4MTMSyncTree:
       
  1291 			// Queue a Synchronise Tree operation
       
  1292 			if (iBackgroundSyncInProgress)
       
  1293 				{
       
  1294 				User::RequestComplete(iRequest,KErrServerBusy);
       
  1295 				return;
       
  1296 				}
       
  1297 			
       
  1298 			iRequestedOperation=TImap4GenericProgress::ESync;
       
  1299 			iCurrentSession->iFullSync->SynchroniseTreeL(*status,iServiceId,ETrue);
       
  1300 			notComplete = ETrue;
       
  1301 			break;
       
  1302 			
       
  1303 		case KIMAP4MTMLocalSubscribe:
       
  1304 			// Change local subscription flag on a folder
       
  1305 			User::RequestComplete(iRequest,SetLocalSubscription(aSelection[0],ETrue));
       
  1306 			break;
       
  1307 
       
  1308 		case KIMAP4MTMLocalUnsubscribe:
       
  1309 			{
       
  1310 			// Change local subscription flag on a folder
       
  1311 			TMsvId folder = aSelection[0];
       
  1312 			TInt err=SetLocalSubscription(folder,EFalse);
       
  1313 			if(err==KErrNone)
       
  1314 				{
       
  1315 				// if we don't have any service settings then load
       
  1316 				// them
       
  1317 				TBool loadedSettings = EFalse;
       
  1318 				if (iServiceSettings==NULL)
       
  1319 					{
       
  1320 					LoadSettingsL(folder);
       
  1321 					loadedSettings = ETrue;
       
  1322 					}
       
  1323 
       
  1324 				// if synchronisation setting is not remote only then
       
  1325 				// update the invisibility flags
       
  1326 				if (iServiceSettings->Synchronise() != EUseRemote)
       
  1327 					{
       
  1328 					PropagateInvisibleFlagL(folder);
       
  1329 					ChangeVisibilityL(folder,ETrue,EFalse,KUidMsvMessageEntry);
       
  1330 					}
       
  1331 
       
  1332 				// if we loaded settings especially then free them
       
  1333 				// again
       
  1334 				if (loadedSettings)
       
  1335 					{
       
  1336 					delete iServiceSettings;
       
  1337 					iServiceSettings=NULL;
       
  1338 					}
       
  1339 				}
       
  1340 			User::RequestComplete(iRequest,err);
       
  1341 			break;
       
  1342 			}
       
  1343 
       
  1344 		case KIMAP4MTMFullSync:
       
  1345 			// Do a full synchronise if we're not doing one already
       
  1346 			if (iBackgroundSyncInProgress)
       
  1347 				{
       
  1348 				// We're busy, go away
       
  1349 				User::RequestComplete(iRequest,KErrServerBusy);
       
  1350 				}
       
  1351 			else
       
  1352 				{
       
  1353 				iRequestedOperation=TImap4GenericProgress::ESync;
       
  1354 				if (iClearNewFlagOnNextSync)
       
  1355 					{
       
  1356 					ClearNewFlagL(iServiceId);
       
  1357 					iClearNewFlagOnNextSync = EFalse;
       
  1358 					}
       
  1359 
       
  1360 				// SJM: Note new folders should always be invisible as
       
  1361 				// they are not subscribed
       
  1362 				iCurrentSession->iFullSync->SynchroniseL(*status,iServiceId, ETrue,
       
  1363 														 !iServiceSettings->DeleteEmailsWhenDisconnecting());
       
  1364 				iState=EMtmStateForegroundSync;
       
  1365 				notComplete = ETrue;
       
  1366 				}
       
  1367 			break;
       
  1368 
       
  1369 		case KIMAP4MTMPopulate:
       
  1370 			// this function is just a copy to mirror.
       
  1371 			{
       
  1372 			iRequestedOperation=TImap4GenericProgress::EPopulate;
       
  1373 			if (aParameter.Length() > 0)
       
  1374 				{
       
  1375 				TImImap4GetPartialMailInfo imap4GetPartialMailInfo;	
       
  1376 				TPckgC<TImImap4GetPartialMailInfo> paramPartialPack(imap4GetPartialMailInfo);
       
  1377 				paramPartialPack.Set(aParameter);
       
  1378 				iPartialMailInfo = paramPartialPack();
       
  1379 				}
       
  1380 
       
  1381 			MtmCommandL(EMtmPopulate,aSelection,KMsvNullIndexEntryId,aStatus);
       
  1382 			break;
       
  1383 			}
       
  1384 			
       
  1385 		case KIMAP4MTMInboxNewSync:
       
  1386 			if (iBackgroundSyncInProgress)
       
  1387 				{
       
  1388 				// We're busy, go away
       
  1389 				User::RequestComplete(iRequest,KErrServerBusy);
       
  1390 				}
       
  1391 			else
       
  1392 				{
       
  1393 				// First of all, find the inbox
       
  1394 				CMsvEntrySelection *findinbox=new (ELeave) CMsvEntrySelection;
       
  1395 				CleanupStack::PushL(findinbox);
       
  1396 				SetEntryL(iServiceId);
       
  1397 				GetChildrenL(*findinbox);
       
  1398 				TMsvId inbox=0;
       
  1399 				for(TInt a=0;a<findinbox->Count();a++)
       
  1400 					{
       
  1401 					SetEntryL((*findinbox)[a]);
       
  1402 					if (iServerEntry->Entry().iDetails.CompareF(KIMAP_INBOX)==0)
       
  1403 						{
       
  1404 						inbox=(*findinbox)[a];
       
  1405 						break;
       
  1406 						}
       
  1407 					}
       
  1408 
       
  1409 				// Clean up
       
  1410 				CleanupStack::PopAndDestroy();
       
  1411 			
       
  1412 				// Found it?
       
  1413 				if (inbox)
       
  1414 					{
       
  1415 					// Start a new-only sync of the inbox
       
  1416 					iRequestedOperation=TImap4GenericProgress::ESync;
       
  1417 					iCurrentSession->iCompound->NewOnlySyncL(*status,inbox);
       
  1418 					notComplete = ETrue;
       
  1419 					}
       
  1420 				else
       
  1421 					{
       
  1422 					// Couldn't find it!
       
  1423 					User::RequestComplete(iRequest,KErrNotFound);
       
  1424 					}
       
  1425 				}
       
  1426 			break;
       
  1427 
       
  1428 		case KIMAP4MTMFolderFullSync:
       
  1429 			// Start a full sync of the folder
       
  1430 			iRequestedOperation=TImap4GenericProgress::ESync;
       
  1431 			iCurrentSession->iCompound->FullSyncL(*status,aSelection[0]);
       
  1432 			notComplete = ETrue;
       
  1433 			break;
       
  1434 
       
  1435 		case KIMAP4MTMWaitForBackground:
       
  1436 			// Wait for background operation to complete: is one running?
       
  1437 			if (!iBackgroundSyncInProgress)
       
  1438 				{
       
  1439 				// No, just return
       
  1440 				User::RequestComplete(iRequest,KErrNone);
       
  1441 				}
       
  1442 			else
       
  1443 				{
       
  1444 				// Otherwise, wait for completion
       
  1445 				iState=EMtmStateWaitingForBackgroundToFinish;
       
  1446 				// Activate instead of SetActive()
       
  1447 				Activate();
       
  1448 				}
       
  1449 			break;
       
  1450 
       
  1451 		case KIMAP4MTMDisconnect:
       
  1452 			// if we want to delete emails on disconnect and we've
       
  1453 			// finished the background sync			
       
  1454 			if ( iServiceSettings->DeleteEmailsWhenDisconnecting() &&
       
  1455 				 !(iBackgroundSyncInProgress || iPrimarySession->iSession->IsCancelling()) )
       
  1456 				{
       
  1457 				// Disconnecting
       
  1458 				iRequestedOperation=TImap4GenericProgress::EDelete;
       
  1459 			
       
  1460 				iPrimarySession->iFullSync->SynchroniseDeletesL(*status, iServiceId);
       
  1461 				iPrimarySession->StartL(this);
       
  1462 				}
       
  1463 			else
       
  1464 				{
       
  1465 				// Disconnecting
       
  1466 				iRequestedOperation=TImap4GenericProgress::EDisconnect;
       
  1467 			
       
  1468 				// Cancel both sessions
       
  1469 				iPrimarySession->Cancel();
       
  1470 
       
  1471 				// No sync in progress now...
       
  1472 				if (iBackgroundSyncInProgress)
       
  1473 					iBackgroundSyncInProgress=EFalse;
       
  1474 
       
  1475 				// Disconnect both sessions
       
  1476 				status=iPrimarySession->SessionStatus();
       
  1477 				iPrimarySession->iSession->DisconnectL(*status);
       
  1478 				iPrimarySession->StartL(this);
       
  1479 				}
       
  1480 
       
  1481 			// kill off the secondary session whatever
       
  1482 			iSecondarySession->Cancel();
       
  1483 			status=iSecondarySession->SessionStatus();
       
  1484 			iSecondarySession->iSession->DisconnectL(*status);
       
  1485 			iSecondarySession->StartL(this);
       
  1486 			break;
       
  1487 
       
  1488 		case KIMAP4MTMRenameFolder:
       
  1489 			{
       
  1490 			TImap4RenameFolder cmd;
       
  1491 			TPckgC<TImap4RenameFolder> package(cmd);
       
  1492 			package.Set(aParameter);
       
  1493 			if (RenameFolderL(aSelection[0], package()))
       
  1494 				notComplete = ETrue;
       
  1495 			break;
       
  1496 			}
       
  1497 
       
  1498 		case KIMAP4MTMUndeleteAll:
       
  1499 			UndeleteAllL(aSelection, aStatus);
       
  1500 			break;
       
  1501 			
       
  1502 		case KIMAP4MTMCancelOffLineOperations:
       
  1503 			iOffLineControl->CancelOffLineOperationsL(aSelection);
       
  1504 			User::RequestComplete(iRequest,KErrNone);
       
  1505 			break;
       
  1506 			
       
  1507 		default:
       
  1508 			User::RequestComplete(iRequest,KErrNotSupported);
       
  1509 			break;
       
  1510 		}
       
  1511 
       
  1512 	if (notComplete)
       
  1513 		{
       
  1514 		// Stuff to do!
       
  1515 		iCurrentSession->StartL(this);
       
  1516 		}
       
  1517 	}
       
  1518 
       
  1519 // Are we finished yet?
       
  1520 TBool CImap4ServerMtm::CommandExpected()
       
  1521 	{
       
  1522 	// ...basically, when we're disconnected we can be deleted
       
  1523 	return (!iCanBeDeletedNow || iBatchInProgress);
       
  1524 	}
       
  1525 
       
  1526 // Report progress information back to client
       
  1527 const TDesC8& CImap4ServerMtm::Progress()
       
  1528 	{
       
  1529 	TImap4CompoundProgress progress;
       
  1530 
       
  1531 	// get generic status from the current session, this writes a
       
  1532 	// complete GenericProgressState out apart from iOperation.  note
       
  1533 	// that if we do a populate whilst background syncing (for
       
  1534 	// example) then this will give details of the populate. If we are
       
  1535 	// only syncing then this will give details about the sync
       
  1536 	// operation
       
  1537 	CActiveWrapper *session = NULL;
       
  1538 	
       
  1539 	if(iState==EMtmStateSecondarySessionIdle)
       
  1540 		{
       
  1541 		session = iPrimarySession;
       
  1542 		}
       
  1543 	else
       
  1544 		{
       
  1545 		session = iCurrentSession ? iCurrentSession : iPrimarySession;
       
  1546 		}
       
  1547 
       
  1548 	progress.iGenericProgress = session->iCompound->Progress();
       
  1549 
       
  1550 	// read the sync status whatever state we are in to ensure that
       
  1551 	// the structure is not left uninitialised
       
  1552 	progress.iSyncProgress=iPrimarySession->iFullSync->Progress();
       
  1553 	  
       
  1554 	// Have we gone from non-disconnected to disconnected all of a sudden? If we have, this
       
  1555 	// means that the lower layers have detected a disconnection.
       
  1556 	// ignore this transition if the last thing we did is ask for a disconnection.
       
  1557 	if (iLastSessionState!=TImap4GenericProgress::EDisconnected &&
       
  1558 		progress.iGenericProgress.iState==TImap4GenericProgress::EDisconnected &&
       
  1559 		iRequestedOperation!=TImap4GenericProgress::EDisconnect)
       
  1560 		{
       
  1561 		// Kick ourselves so we know we're disconnected now
       
  1562 		LOG_COMMANDS((_L8("CImap4ServerMtm::Progress: Session %d suddenly disconnected"), iCurrentSession->iID));
       
  1563 		
       
  1564 		if(iCurrentSession->iID != 2)
       
  1565 			{
       
  1566 			GoneOffline();
       
  1567 			}
       
  1568 		}
       
  1569 
       
  1570 	// Save this operation to check next time
       
  1571 	iLastSessionState=progress.iGenericProgress.iState;
       
  1572 
       
  1573 	// Put error into progress buffer
       
  1574 	if( progress.iGenericProgress.iErrorCode == KErrNone )
       
  1575 		progress.iGenericProgress.iErrorCode=iProgressErrorCode;
       
  1576 
       
  1577 	// If we're copying or moving, *we* (the mtm) keep track of the
       
  1578 	// messages done: this is because these operations involve many
       
  1579 	// more operations at MTM level (ie, syncs, etc) which also fiddle
       
  1580 	// with the msgsdone total, as they would during a full sync.
       
  1581 	switch (iRequestedOperation)
       
  1582 		{
       
  1583 	case TImap4GenericProgress::EMoveWithinService:
       
  1584 	case TImap4GenericProgress::ECopyWithinService:
       
  1585 		break;
       
  1586 	case TImap4GenericProgress::EMoveToLocal:
       
  1587 	case TImap4GenericProgress::ECopyToLocal:
       
  1588 	case TImap4GenericProgress::EMoveFromLocal:
       
  1589 	case TImap4GenericProgress::ECopyFromLocal:
       
  1590 	case TImap4GenericProgress::EPopulate:
       
  1591 	case TImap4GenericProgress::EDelete:	
       
  1592 	case TImap4GenericProgress::EOffLineDelete:
       
  1593 	case TImap4GenericProgress::EOffLineUndelete:
       
  1594 	case TImap4GenericProgress::EOffLineCopyToLocal:
       
  1595 	case TImap4GenericProgress::EOffLineMoveToLocal:
       
  1596 	case TImap4GenericProgress::EOffLineCopyFromLocal:
       
  1597 	case TImap4GenericProgress::EOffLineMoveFromLocal:
       
  1598 	case TImap4GenericProgress::EOffLineCopyWithinService:
       
  1599 	case TImap4GenericProgress::EOffLineMoveWithinService:
       
  1600 	case TImap4GenericProgress::EOffLinePopulate:
       
  1601 		progress.iGenericProgress.iMsgsToDo=iProgressMsgsToDo;
       
  1602 		progress.iGenericProgress.iMsgsDone=iProgressMsgsDone;
       
  1603 		break;
       
  1604 	default:
       
  1605 		break;
       
  1606 		}
       
  1607 
       
  1608 #ifdef PRINTING
       
  1609 	// Log the error we're returning
       
  1610 	if (iProgressErrorCode!=KErrNone)
       
  1611 		{
       
  1612 		iPrimarySession->iSession->LogText(_L8("Progress errorcode=%d, laststate=%d currentstate=%d"),
       
  1613 										   iProgressErrorCode,iLastSessionState,progress.iGenericProgress.iState);
       
  1614 		}
       
  1615 #endif
       
  1616 
       
  1617 	// put in the operation we've been asked to perform
       
  1618 	progress.iGenericProgress.iOperation=iRequestedOperation;
       
  1619 
       
  1620 	// Copy the Sync iTotalSize flag into the Generic Total Size field, if the progress val is 0;
       
  1621 	progress.iGenericProgress.iTotalSize = iTotalSize;
       
  1622 
       
  1623 	// construct the progress buffer
       
  1624 	iProgressBuf=TImap4ProgressBuf(progress);
       
  1625 	return iProgressBuf;
       
  1626 	}
       
  1627 
       
  1628 void CImap4ServerMtm::DoCancel()
       
  1629 	{
       
  1630 	DBG((iPrimarySession->iSession->LogText(_L8("CImap4ServerMtm::DoCancel() when in state %d"),iState)));
       
  1631 
       
  1632 	// What are we doing?
       
  1633 	switch(iState)
       
  1634 		{
       
  1635 	case EMtmStateCopyFromLocal:
       
  1636 	case EMtmStateMoveFromLocal:
       
  1637 	case EMtmStateCopyToLocal:
       
  1638 	case EMtmStateMoveToLocal:
       
  1639 	case EMtmStateCopyWithinService:
       
  1640 	case EMtmStateMoveWithinService:
       
  1641 	case EMtmStatePopulate:
       
  1642 		// These all use the compound objects: cancel this
       
  1643 		iPrimarySession->Cancel();
       
  1644 		iSecondarySession->Cancel();
       
  1645 		break;
       
  1646 
       
  1647 	case EMtmStateMiscCommand:
       
  1648 		// What was the actual misc command?
       
  1649 		switch(iLastCommand)
       
  1650 			{
       
  1651 		case KIMAP4MTMConnect:
       
  1652 		case KIMAP4MTMConnectAndSynchronise:
       
  1653 			// Kill primary only
       
  1654 			iPrimarySession->Cancel();
       
  1655 			break;
       
  1656 
       
  1657 		default:
       
  1658 			// Cancel both sessions...
       
  1659 			iPrimarySession->Cancel();
       
  1660 			iSecondarySession->Cancel();
       
  1661 			}
       
  1662 		break;
       
  1663 
       
  1664 	case EMtmStateSecondaryConnect:
       
  1665 		// Cancel secondary session
       
  1666 		iSecondarySession->Cancel();
       
  1667 		break;
       
  1668 
       
  1669 	case EMtmStateOffLineCopyToLocal:
       
  1670 	case EMtmStateOffLineMoveToLocal:
       
  1671 		iServerEntry->Cancel();
       
  1672 		iOffLineControl->Cancel();
       
  1673 		break;
       
  1674 	case EMtmStateSecondarySessionIdle:
       
  1675 		return;
       
  1676 	
       
  1677 	case EMtmStateDelete:
       
  1678 	case EMtmStateDeleteFolder:
       
  1679 	default:
       
  1680 		// Cancel everything in sight
       
  1681 		iPrimarySession->Cancel();
       
  1682 		iSecondarySession->Cancel();
       
  1683 		break;
       
  1684 		}
       
  1685 
       
  1686 	DBG((iPrimarySession->iSession->LogText(_L8("CImap4ServerMtm::DoCancel() finished"))));
       
  1687 
       
  1688 	// Park entries
       
  1689 	iPrimarySession->iSession->Park();
       
  1690 	iSecondarySession->iSession->Park();
       
  1691 
       
  1692 	if (iRequest)
       
  1693 		User::RequestComplete(iRequest,KErrCancel);
       
  1694 	}
       
  1695 
       
  1696 void CImap4ServerMtm::DoRunL()
       
  1697 	{
       
  1698 #ifdef PRINTING
       
  1699 	CImImap4Session* logsession=(iId==2)?iSecondarySession->iSession:iPrimarySession->iSession;
       
  1700 	logsession->LogText(_L8("CImap4ServerMtm::DoRunL(id=%d, status=%d, state=%d)"),
       
  1701 						iId,iStatus.Int(),iState);
       
  1702 #endif
       
  1703 
       
  1704 	// Status for kicking off next command
       
  1705 	TRequestStatus* status=iCurrentSession->SessionStatus();
       
  1706 
       
  1707 	// What were we doing?
       
  1708 	switch(iState)
       
  1709 		{
       
  1710 	case EMtmStateMiscCommand:
       
  1711 		// A misc command has completed: do we need to do anything next?
       
  1712 		switch(iLastCommand)
       
  1713 			{
       
  1714 		case KIMAP4MTMConnect:
       
  1715 		case KIMAP4MTMConnectAndSynchronise:
       
  1716 			{
       
  1717 			// Problems?
       
  1718 			if (iCode!=KErrNone)
       
  1719 				{
       
  1720 				// Mark ourselves as offline, and unloadable
       
  1721 				GoneOffline();
       
  1722 
       
  1723 				// Tell world about the error, via progress and
       
  1724 				// Completion code
       
  1725 				iProgressErrorCode=iCode;
       
  1726 
       
  1727 				// If doing a connect and sync, the caller is completed after the connect
       
  1728 				// phase and the sync continues in the background. If we get an error during that
       
  1729 				// sync we need to ensure we don't try to complete the caller again by checking
       
  1730 				// that iRequest is not null.
       
  1731 				if (iRequest != NULL)
       
  1732 					{
       
  1733 					User::RequestComplete(iRequest,iCode);
       
  1734 					}
       
  1735 				return;
       
  1736 				}
       
  1737 
       
  1738 			// Connect was successful: update connected bit in the service entry
       
  1739 			// Ignore errors, it's not the end of the world
       
  1740 			TRAP_IGNORE(MarkOnOrOfflineL(ETrue));
       
  1741 
       
  1742 			// Mark that we need to clear new flag before next sync
       
  1743 			iClearNewFlagOnNextSync = ETrue;
       
  1744 			
       
  1745 			// Do we need to kick off sync?
       
  1746 			if (iLastCommand==KIMAP4MTMConnectAndSynchronise)
       
  1747 				{
       
  1748 				DBG((logsession->LogText(_L8("Kicking off background synchronise"))));
       
  1749 
       
  1750 				// Start full sync
       
  1751 				if (iClearNewFlagOnNextSync)
       
  1752 					{
       
  1753 					ClearNewFlagL(iServiceId);
       
  1754 					iClearNewFlagOnNextSync = EFalse;
       
  1755 					}
       
  1756 				// SJM: New folders should always be invisible as they are not subscribed
       
  1757 				iCurrentSession->iFullSync->SynchroniseL(*status,iServiceId,ETrue,
       
  1758 					!iServiceSettings->DeleteEmailsWhenDisconnecting(), ETrue);
       
  1759 				iCurrentSession->StartL(this);
       
  1760 
       
  1761 				// Carry on as normal, completing request back to client.
       
  1762 				// The synchronise will continue in the background.
       
  1763 				iBackgroundSyncInProgress=ETrue;
       
  1764 				}
       
  1765 
       
  1766 			break;
       
  1767 			}
       
  1768 
       
  1769 		case KIMAP4MTMDisconnect:
       
  1770 			// Disconnecting but marked as busy - that means we were
       
  1771 			// carrying out the pending deletes
       
  1772 			if (iRequestedOperation == TImap4GenericProgress::EDelete)
       
  1773 				{
       
  1774 				iRequestedOperation = TImap4GenericProgress::EDisconnect;
       
  1775 
       
  1776 				// Disconnect primary sessions
       
  1777 				status=iPrimarySession->SessionStatus();
       
  1778 				iPrimarySession->iSession->DisconnectL(*status);
       
  1779 				iPrimarySession->StartL(this);
       
  1780 				return;
       
  1781 				}
       
  1782 
       
  1783 			// Disconnecting session 1? (primary session). If so, then clear the
       
  1784 			// connected bit in the service entry.
       
  1785 			if (iId==1 && iServiceId && iServiceSettings)
       
  1786 				{
       
  1787 				// Do "we've gone offline" stuff
       
  1788 				GoneOffline();
       
  1789 				}
       
  1790 			break;
       
  1791 			}
       
  1792 		break;
       
  1793 
       
  1794 	case EMtmStateCopyToLocal:
       
  1795 	case EMtmStateMoveToLocal:
       
  1796 	case EMtmStatePopulate:
       
  1797 		// if no message sent then trigger null event to get to next
       
  1798 		// state
       
  1799 		SetActive();
       
  1800 		if (!iUtils->SendLogMessageL(iCode,iStatus))
       
  1801 			{
       
  1802 			TRequestStatus* status = &iStatus;
       
  1803 			User::RequestComplete(status, KErrNone);
       
  1804 			}
       
  1805 
       
  1806 		// send log message
       
  1807 		iSavedState = iState;
       
  1808 		iState = EMtmStateLogging;
       
  1809 		return;
       
  1810 
       
  1811 	case EMtmStateLogging:
       
  1812 		// done logging, restore old state
       
  1813 		iState = iSavedState;
       
  1814 		// and deliberately fall through to next case
       
  1815 
       
  1816 	case EMtmStateCopyFromLocal:
       
  1817 	case EMtmStateMoveFromLocal:
       
  1818 	case EMtmStateCopyWithinService:
       
  1819 	case EMtmStateMoveWithinService:
       
  1820 		// Note any error in the appropriate message
       
  1821 		MessageErrorL((*iSelection)[0],iCode);
       
  1822 		
       
  1823 		// Note any error in the appropriate message
       
  1824 		MessageErrorL((*iSelection)[0],iCode);
       
  1825 		
       
  1826 		// Remove completed item from selection
       
  1827 		if (iState==EMtmStateCopyWithinService || iState==EMtmStateMoveWithinService)
       
  1828 			{
       
  1829 			TInt count=iSelection->Count();
       
  1830 			iSelection->Delete(0,count);
       
  1831 			iProgressMsgsDone+=count;
       
  1832 			}
       
  1833 		else
       
  1834 			{
       
  1835 			iSelection->Delete(0,1);
       
  1836 			iProgressMsgsDone++;
       
  1837 			}
       
  1838 
       
  1839 		// One more message done
       
  1840 
       
  1841 		// Operation done. Do next one in selection
       
  1842 		if (iSelection->Count())
       
  1843 			{
       
  1844 			// Do the copy with the compound
       
  1845 			status=iCurrentSession->SessionStatus();
       
  1846 			switch(iState)
       
  1847 				{
       
  1848 			case EMtmStateCopyFromLocal:
       
  1849 				iCurrentSession->iCompound->CopyFromLocalL(*status,(*iSelection)[0],iDestination);
       
  1850 				break;
       
  1851 
       
  1852 			case EMtmStateMoveFromLocal:
       
  1853 				iCurrentSession->iCompound->MoveFromLocalL(*status,(*iSelection)[0],iDestination);
       
  1854 				break;
       
  1855 
       
  1856 			case EMtmStateCopyToLocal:
       
  1857 				iUtils->SetUpLogMessageL((*iSelection)[0]);
       
  1858 				iCurrentSession->iCompound->CopyToLocalL(*status,(*iSelection)[0],iDestination);
       
  1859 				break;
       
  1860 
       
  1861 			case EMtmStateMoveToLocal:
       
  1862 				iUtils->SetUpLogMessageL((*iSelection)[0]);
       
  1863 				iCurrentSession->iCompound->MoveToLocalL(*status,(*iSelection)[0],iDestination);
       
  1864 				break;
       
  1865 
       
  1866 			case EMtmStateCopyWithinService:
       
  1867 				// Will copy all messages in one go.
       
  1868 				break;
       
  1869 
       
  1870 			case EMtmStateMoveWithinService:
       
  1871 				// Will copy all messages in one go.
       
  1872 				break;
       
  1873 
       
  1874 			case EMtmStatePopulate:
       
  1875 				iUtils->SetUpLogMessageL((*iSelection)[0]);
       
  1876 				iCurrentSession->iCompound->PopulateL(*status,(*iSelection)[0],iPartialMailInfo);
       
  1877 				break;
       
  1878 
       
  1879 			default: // Keep gcc quiet
       
  1880 				break;
       
  1881 				}
       
  1882 
       
  1883 			iCurrentSession->StartL(this);
       
  1884 			return;
       
  1885 			}
       
  1886 		else if(iCurrentSession == iSecondarySession)
       
  1887 			{
       
  1888 			iSecondarySession->Cancel();
       
  1889 			status = iSecondarySession->SessionStatus();
       
  1890 			iSecondarySession->iSession->DisconnectL(*status);
       
  1891 			iSecondarySession->StartL(this);
       
  1892 			iState = EMtmStateSecondarySessionIdle;
       
  1893 			iSavedState = EMtmStateSecondarySessionIdle;
       
  1894 			}
       
  1895 
       
  1896 		break;		
       
  1897 	
       
  1898 	case EMtmStateDelete:
       
  1899 		{
       
  1900 		// Problems?
       
  1901 		if (iCode!=KErrNone)
       
  1902 			{
       
  1903 			// Store the error on this one
       
  1904 			MessageErrorL((*iSelection)[0],iCode);
       
  1905 
       
  1906 			// Continue through selection
       
  1907 			}
       
  1908 
       
  1909 		// Delete completed.
       
  1910  		TInt count=iSelection->Count();
       
  1911  		iSelection->Delete(0,count);
       
  1912  		iProgressMsgsDone+=count;
       
  1913 
       
  1914 		DBG((iCurrentSession->iSession->LogText(_L8("iMsgsDone now %d"),iProgressMsgsDone)));		
       
  1915  		break;
       
  1916 		}
       
  1917 	case EMtmStateDeleteFolder:
       
  1918 		// Delete completed: do the next one
       
  1919 		iSelection->Delete(0,1);
       
  1920 
       
  1921 		// One more message done
       
  1922 		iProgressMsgsDone++;
       
  1923 
       
  1924 		DBG((iCurrentSession->iSession->LogText(_L8("iMsgsDone now %d"),iProgressMsgsDone)));
       
  1925 
       
  1926 		// Anything left to do?
       
  1927 		if (!iSelection->Count())
       
  1928 			break;
       
  1929 
       
  1930 		iCurrentSession->iCompound->DeleteFolderL(*status,(*iSelection)[0]);
       
  1931 		iCurrentSession->StartL(this);
       
  1932 		return;
       
  1933 
       
  1934 	case EMtmStateOffLineDelete:
       
  1935 	case EMtmStateOffLineUndelete:
       
  1936 	case EMtmStateOffLineCopyToLocal:
       
  1937 	case EMtmStateOffLineMoveToLocal:
       
  1938 	case EMtmStateOffLineCopyFromLocal:
       
  1939 	case EMtmStateOffLineMoveFromLocal:
       
  1940 	case EMtmStateOffLineCopyWithinService:
       
  1941 	case EMtmStateOffLineMoveWithinService:
       
  1942 	case EMtmStateOffLinePopulate:
       
  1943 		{		
       
  1944 		if(iProgressMsgsDone == iProgressMsgsToDo)
       
  1945 			break;
       
  1946 		
       
  1947 		if(iOneSelection)
       
  1948 			delete iOneSelection;
       
  1949 		iOneSelection=new (ELeave) CMsvEntrySelection;
       
  1950 		iOneSelection->AppendL((*iSelection)[iProgressMsgsDone]);		
       
  1951 		
       
  1952 		CImap4OffLineControl::TImap4OpType opType=CImap4OffLineControl::EImap4OpDelete; //have to initialise to something!
       
  1953 		switch(iState)
       
  1954 			{
       
  1955 		case EMtmStateOffLineDelete:
       
  1956 			opType=CImap4OffLineControl::EImap4OpDelete;
       
  1957 			break;
       
  1958 		case EMtmStateOffLineUndelete:
       
  1959 			opType=CImap4OffLineControl::EImap4OpUndelete;
       
  1960 			break;
       
  1961 		case EMtmStateOffLineCopyToLocal:
       
  1962 			opType=CImap4OffLineControl::EImap4OpCopyToLocal;
       
  1963 			break;
       
  1964 		case EMtmStateOffLineMoveToLocal:
       
  1965 			opType=CImap4OffLineControl::EImap4OpMoveToLocal;
       
  1966 			break;
       
  1967 		case EMtmStateOffLineCopyFromLocal:
       
  1968 			opType=CImap4OffLineControl::EImap4OpCopyFromLocal;
       
  1969 			break;
       
  1970 		case EMtmStateOffLineMoveFromLocal:
       
  1971 			opType=CImap4OffLineControl::EImap4OpMoveFromLocal;
       
  1972 			break;
       
  1973 		case EMtmStateOffLineCopyWithinService:
       
  1974 			opType=CImap4OffLineControl::EImap4OpCopyWithinService;
       
  1975 			break;
       
  1976 		case EMtmStateOffLineMoveWithinService:
       
  1977 			opType=CImap4OffLineControl::EImap4OpMoveWithinService;
       
  1978 			break;
       
  1979 		case EMtmStateOffLinePopulate:
       
  1980 			opType=CImap4OffLineControl::EImap4OpPopulate;
       
  1981 			break;
       
  1982 		default:
       
  1983 			break;
       
  1984 			}
       
  1985 		
       
  1986 		if(iState == EMtmStateOffLineDelete || iState == EMtmStateOffLineUndelete)
       
  1987 			{
       
  1988 			iOffLineControl->StoreOfflineCommandL(opType, *iOneSelection, KMsvNullIndexEntryId, iStatus);
       
  1989 			}
       
  1990 		else if(iState == EMtmStateOffLinePopulate)
       
  1991 			{
       
  1992 			TPckgBuf<TImap4GetMailOptions> package(iGetMailOptions);
       
  1993 			iOffLineControl->StoreOfflineCommandL(opType, *iOneSelection, iDestination, package, iStatus);
       
  1994 			}
       
  1995 		else
       
  1996 			{	
       
  1997 			iOffLineControl->StoreOfflineCommandL(opType, *iOneSelection, iDestination, iStatus);
       
  1998 			}
       
  1999 
       
  2000 		iProgressMsgsDone++;
       
  2001 		SetActive();
       
  2002 		return;
       
  2003 		}
       
  2004 	case EMtmStateSecondaryConnect:
       
  2005 		// We've now connected the secondary session. Issue the
       
  2006 		// saved command and continue;
       
  2007 		switch(iState=iSavedState)
       
  2008 			{
       
  2009 		case EMtmStateCopyToLocal:
       
  2010 			// We've just connected, so first thing to do is to do the
       
  2011 			// folder selection. No need to check the selection, as
       
  2012 			// we know it contains at least 1 item from the originally
       
  2013 			// issued command.
       
  2014 			iUtils->SetUpLogMessageL((*iSelection)[0]);
       
  2015 			iCurrentSession->iCompound->CopyToLocalL(*status,(*iSelection)[0],iDestination);
       
  2016 			iCurrentSession->StartL(this);
       
  2017 			return;
       
  2018 		
       
  2019 		case EMtmStatePopulate:
       
  2020 			iUtils->SetUpLogMessageL((*iSelection)[0]);
       
  2021 			iCurrentSession->iCompound->PopulateL(*status,(*iSelection)[0],iPartialMailInfo);
       
  2022 			iCurrentSession->StartL(this);
       
  2023 			return;
       
  2024 		
       
  2025 		default:
       
  2026 			break;
       
  2027 			}
       
  2028 		break;
       
  2029 
       
  2030 	case EMtmStateSyncCompleted:	// FALL THROUGH
       
  2031 	default:
       
  2032 		break;
       
  2033 		}
       
  2034 
       
  2035 	// Async request completed (from wrapper): also return it in the progress
       
  2036 	DBG((logsession->LogText(_L8("ID %d completed with code %d"),iId,iCode)));
       
  2037 
       
  2038 	iProgressErrorCode=iCode;
       
  2039 
       
  2040 	// Park entry
       
  2041 	iServerEntry->SetEntry(KMsvNullIndexEntryId);
       
  2042 
       
  2043 	// Only complete if we have an iRequest: we may not (ie, 2 sessions
       
  2044 	// disconnecting at once)
       
  2045 	if (iRequest)
       
  2046 		User::RequestComplete(iRequest,KErrNone);
       
  2047 	}
       
  2048 
       
  2049 void CImap4ServerMtm::DoComplete(TInt aStatus)
       
  2050 	{
       
  2051 #ifdef PRINTING
       
  2052 	iPrimarySession->iSession->LogText(_L8("CImap4ServerMtm::DoComplete(%d)"),aStatus);
       
  2053 #endif
       
  2054 
       
  2055 	// Park entry
       
  2056 	iServerEntry->SetEntry(KMsvNullIndexEntryId);
       
  2057 	if (iRequest)
       
  2058 		User::RequestComplete(iRequest,aStatus);
       
  2059 	}
       
  2060 
       
  2061 // Save error code in a message
       
  2062 void CImap4ServerMtm::MessageErrorL(const TMsvId aMessageId, const TInt aError)
       
  2063 	{
       
  2064 	// Save error code: if we can't access this entry, then it's probably something to do
       
  2065 	// with the error we're trying to report: ignore it silently
       
  2066 	// SJM: this used to be != KerrNone - surely shome mistake
       
  2067 	if (iServerEntry->SetEntry(aMessageId)==KErrNone)
       
  2068 		{
       
  2069 		TMsvEntry entry=iServerEntry->Entry();
       
  2070 
       
  2071 		// Save unnecessary writes...
       
  2072 		if (entry.iError!=aError)
       
  2073 			{
       
  2074 			entry.iError=aError;
       
  2075 			ChangeEntryL(entry);
       
  2076 			}
       
  2077 		}
       
  2078 	}
       
  2079 
       
  2080 // Mixin - a child has completed
       
  2081 void CImap4ServerMtm::RequestCompleted(TInt aId, TInt aCode)
       
  2082 	{
       
  2083 #ifdef PRINTING
       
  2084 	CImImap4Session* logsession=(aId==2)?iSecondarySession->iSession:iPrimarySession->iSession;
       
  2085 	logsession->LogText(_L8("CImap4ServerMtm::RequestCompleted(id=%d, result=%d, state=%d)"),aId,aCode,iState);
       
  2086 #endif
       
  2087 	// Is this the background sync completeing?
       
  2088 	if (aId==1 && iBackgroundSyncInProgress)
       
  2089 		{
       
  2090 		// Not in progress any more, boyo
       
  2091 		iBackgroundSyncInProgress=EFalse;
       
  2092 
       
  2093 		// Is anyone in the forground waiting for this to happen?
       
  2094 		if (iState==EMtmStateWaitingForBackgroundToFinish)
       
  2095 			{
       
  2096 			// Yes: we need to complete ourselves by falling through
       
  2097 			// Reset state first
       
  2098 			iState=EMtmStateIdle;
       
  2099 
       
  2100 			// Any errors from the background sync aren't interesting to us
       
  2101 			aCode=KErrNone;
       
  2102 			}
       
  2103 		// Makes the secondary session request, when primary completes background sync
       
  2104 		else if (iState == EMtmStateSecondaryConnect || iState == EMtmStateCopyToLocal || iState == EMtmStatePopulate)
       
  2105 			{
       
  2106 			iProgressErrorCode=aCode;
       
  2107 			return;	
       
  2108 			}			
       
  2109 		else if( aCode == KErrNone )
       
  2110 			{
       
  2111 			// Complete with the state EMtmStateSyncCompleted.  
       
  2112 			// When this is caught in the DoRunL, it does nothing.
       
  2113 			iState = EMtmStateSyncCompleted;
       
  2114 			
       
  2115 			// NOTE - only do this if there are no errors - if there is an error 
       
  2116 			// then DoRunL must handle appropriately in the previous state.
       
  2117 			}
       
  2118 		}
       
  2119 
       
  2120 	// Are we doing a disconnect? If so, we will get completions from both sessions, and we're only
       
  2121 	// interested in the primary one, really
       
  2122 	if (iLastCommand==KIMAP4MTMDisconnect && aId!=1)
       
  2123 		{
       
  2124 		// Silently ignore
       
  2125 		return;
       
  2126 		}
       
  2127 
       
  2128 	// Is the code >0? If so, truncate it to 0 as it's IMPS-specific info
       
  2129 	if (aCode>KErrNone)
       
  2130 		aCode=KErrNone;
       
  2131 
       
  2132 	// Save stuff
       
  2133 	iCode=aCode;
       
  2134 	iId=aId;
       
  2135 
       
  2136 	// Set the current session to the one which has just completed so
       
  2137 	// that when DoRunL() is called it knows which to deal with
       
  2138 	if (aId==1)
       
  2139 		iCurrentSession=iPrimarySession;
       
  2140 	else
       
  2141 		iCurrentSession=iSecondarySession;
       
  2142 
       
  2143 	// Complete *ourselves*
       
  2144 	TRequestStatus *a=&iStatus;
       
  2145     User::RequestComplete(a,aCode);
       
  2146 	
       
  2147 	// The activation may need to be done here.
       
  2148 	// e.g. the primary session already completed and then the secondary completes.
       
  2149 	// e.g. EMtmCopyToLocal is started whilst we are online and a background 
       
  2150 	// sync is in progress.  One completes and then the other.
       
  2151     if(!IsActive())
       
  2152     	{
       
  2153     	SetActive();
       
  2154     	}    
       
  2155 	}
       
  2156 	
       
  2157 // This function allows a CActiveWrapper to set the CImap4ServerMtm active 
       
  2158 // when it starts a request, as opposed to just when one finishes. This means
       
  2159 // that Cancel()s are handled properly.
       
  2160 void CImap4ServerMtm::Activate()
       
  2161 	{
       
  2162 	// Object may already be active as there is a primary and secondary session.
       
  2163 	if(!IsActive())
       
  2164 		{
       
  2165 		iStatus = KRequestPending;
       
  2166 		SetActive();
       
  2167 		}
       
  2168 	}
       
  2169 
       
  2170 #ifdef PRINTING
       
  2171 void CImap4ServerMtm::NonCompletedFailureOnSession(TInt aId)
       
  2172 #else
       
  2173 void CImap4ServerMtm::NonCompletedFailureOnSession(TInt /*aId*/)
       
  2174 #endif
       
  2175 	{
       
  2176 #ifdef PRINTING
       
  2177 	CImImap4Session* logsession=(aId==2)?iSecondarySession->iSession:iPrimarySession->iSession;
       
  2178 	logsession->LogText(_L8("CImap4ServerMtm::NonCompletedFailureOnSession (id=%d)"), aId);
       
  2179 #endif
       
  2180 
       
  2181 	// A failure has occured on the session, but there is no outstanding asynchronous
       
  2182 	// request on it. This can happen if for instance we get a disconnect while doing
       
  2183 	// a cancel and idle operation. We need to go offline immediately.
       
  2184 	GoneOffline();
       
  2185 	}
       
  2186 
       
  2187 CImap4ServerMtm::CImap4ServerMtm(CRegisteredMtmDll& aRegisteredMtmDll, CMsvServerEntry* aEntry):
       
  2188 	CBaseServerMtm(aRegisteredMtmDll,aEntry)
       
  2189 	{
       
  2190 	__DECLARE_NAME(_S("CImap4ServerMtm"));
       
  2191 
       
  2192 	// We can be deleted: at the start, we're not connected
       
  2193 	iCanBeDeletedNow=ETrue;
       
  2194 
       
  2195 	// Add us to the scheduler
       
  2196 	CActiveScheduler::Add(this);
       
  2197 	}
       
  2198 TBool CImap4ServerMtm::PruneMessages(const CMsvEntrySelection& aSelection)
       
  2199 	{
       
  2200 	TInt index = aSelection.Count();
       
  2201 	
       
  2202 	// See if the parent of the first entry is a message.
       
  2203 	// If it is then we need to prune the entries, ie. delete them locally.
       
  2204 	if (index == 0)
       
  2205 		return EFalse;
       
  2206 
       
  2207 	TInt err = iServerEntry->SetEntry(aSelection[0]);
       
  2208 
       
  2209 	if (err == KErrNone)
       
  2210 		{
       
  2211 		err = iServerEntry->SetEntry(iServerEntry->Entry().Parent());
       
  2212 		if (KUidMsvMessageEntry != iServerEntry->Entry().iType)
       
  2213 			// The parent of the given entry was not a message, so we don't prune it.
       
  2214 			return EFalse;
       
  2215 		}
       
  2216 
       
  2217 	while ((index--) && (err==KErrNone))
       
  2218 		{
       
  2219 		// Go to the required entry
       
  2220 		err = iServerEntry->SetEntry(aSelection[index]);
       
  2221 
       
  2222 		if (KErrNone == err)
       
  2223 			{
       
  2224 			// Go to the parent entry to see if it is a message entry
       
  2225 			iServerEntry->SetEntry(iServerEntry->Entry().Parent());
       
  2226 			TMsvEmailEntry entry = iServerEntry->Entry();
       
  2227 
       
  2228 			// assert that (KUidMsvMessageEntry == entry.iType)
       
  2229 
       
  2230 			// Clear the complete flag because we are about to delete the child parts.
       
  2231 			entry.SetComplete(EFalse);
       
  2232 			entry.SetBodyTextComplete(EFalse);
       
  2233 			err = iServerEntry->ChangeEntry(entry);
       
  2234 
       
  2235 			if (KErrNone == err)
       
  2236 				{
       
  2237 				// Delete the body of the message.
       
  2238 				iServerEntry->DeleteEntry(aSelection[index]);
       
  2239 				}
       
  2240 			}
       
  2241 		}
       
  2242 
       
  2243 	User::RequestComplete(iRequest, err);
       
  2244 
       
  2245 	return ETrue;
       
  2246 	}