email/imap4mtm/imapprotocolcontroller/src/cimapcompoundbase.cpp
changeset 31 ebfee66fde93
parent 0 72b543305e3a
equal deleted inserted replaced
30:6a20128ce557 31:ebfee66fde93
       
     1 // Copyright (c) 2006-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 // cimapcompoundbase.cpp
       
    15 //
       
    16 
       
    17 #include "cimapcompoundbase.h"
       
    18 #include "cimapsession.h"
       
    19 #include "cimapsettings.h"
       
    20 #include "cimapsessionconsts.h"
       
    21 #include "cimaplogger.h"
       
    22 #include "imappaniccodes.h"
       
    23 
       
    24 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  
       
    25 #include "timrfc822datefield.h"				
       
    26 #endif
       
    27 
       
    28 CImapCompoundBase::CImapCompoundBase( CImapSyncManager& aSyncManager,
       
    29 					   				  CMsvServerEntry& aServerEntry,
       
    30 					   				  CImapSettings& aImapSettings) :
       
    31 	CMsgActive(EPriorityStandard ),
       
    32 	iSyncManager(aSyncManager),
       
    33 	iServerEntry(aServerEntry),
       
    34 	iImapSettings(aImapSettings),
       
    35 	iStopForMigrate(EFalse),
       
    36 	iCancelForMigrate(EFalse),
       
    37 	iProgressState(TImap4GenericProgress::EIdle),
       
    38 	iSyncProgressState(TImap4SyncProgress::EIdle)
       
    39 	{
       
    40 
       
    41 	}
       
    42 
       
    43 CImapCompoundBase::~CImapCompoundBase( )
       
    44 	{
       
    45 	}
       
    46 
       
    47 #ifdef __IMAP_LOGGING
       
    48 void CImapCompoundBase::DoComplete(TInt& aErr)
       
    49 #else
       
    50 void CImapCompoundBase::DoComplete(TInt& /*aErr*/)
       
    51 #endif //_IMAP_LOGGING
       
    52 	{
       
    53 	__LOG_FORMAT((iSession->LogId(), "CImapCompoundBase::DoComplete(aErr = %d) CurrentStep = %d", aErr, iCurrentStep));
       
    54 	}
       
    55 
       
    56 /**
       
    57 Called when asynchronous service requests complete.
       
    58 Handles errors returned by aSynchronous services. 
       
    59 
       
    60 The state machine for derived compound commands is managed by 
       
    61 the pure-virtual DoRunLoopL() which is called by DoRunL(). 
       
    62 
       
    63 This form of DoRunL also allows synchronous steps to be performed 
       
    64 sequentially.
       
    65 */
       
    66 void CImapCompoundBase::DoRunL()
       
    67 	{
       
    68 	// Handle any server errors
       
    69 	if (iStatus.Int()!=KErrNone)
       
    70 		{
       
    71 		if (TInt err=ProcessSessionError() != KErrNone)
       
    72 			{
       
    73 			Complete(err);
       
    74 			return;
       
    75 			}
       
    76 		}
       
    77 
       
    78 	// Operation state machine handled by DoRunLoopL()
       
    79 	while (!IsActive() && !DoRunLoopL())
       
    80 		{
       
    81 		// do nothing in the body of this
       
    82 		}
       
    83 	}
       
    84 
       
    85 
       
    86 /**
       
    87 Base class method for handling errors returned by the session.
       
    88 Called on completion of an asynchronous request on the IMAP session,
       
    89 ie at the start of the DoRunL() method. If this method returns
       
    90 a value other than KErrNone, the compound operation should complete
       
    91 with the return value as the error code.
       
    92 
       
    93 This will catch any positive error codes returned by the imap
       
    94 session These indicate either NO/BAD server responses or a more
       
    95 serious error has occurred, for example a disconnect, or corrupt
       
    96 data received from the remote server.
       
    97 
       
    98 NO/BAD server responses are handled by the derived compound
       
    99 operation classes (these are non-fatal errors, an attempt is
       
   100 made to continue the requested operation)
       
   101 
       
   102 Other errors are more serious - these are passed up to the
       
   103 Protocol Controller to deal with.
       
   104 
       
   105 @return KErrNone if the error has been handled,
       
   106         otherwise the positive error code as returned by
       
   107         the IMAP session.
       
   108 */
       
   109 TInt CImapCompoundBase::ProcessSessionError()
       
   110 	{
       
   111 	TInt errCode = iStatus.Int();
       
   112 	if (errCode==KErrImapNo || errCode==KErrImapBad)
       
   113 		{
       
   114 		return ProcessNegativeServerResponse();
       
   115 		}
       
   116 	else
       
   117 		{
       
   118 		return errCode;
       
   119 		}
       
   120 	}
       
   121 
       
   122 /**
       
   123 Checks the input selection for entries of specified types.
       
   124 In this context, "Messages" means complete messages, not RFC888
       
   125 parts of another message. "parts" means attachment or text bodies.
       
   126 
       
   127 @param aSelection    - original list of message entry ids
       
   128 @param aLocalCopy    - filtered copy of message entry ids.
       
   129 @param aMessages     - accept entries of type KUidMsvMessageEntry
       
   130 @param aParts        - accept entries of type KUidMsvEmailTextEntry,
       
   131 											  KUidMsvAttachmentEntry, 
       
   132 											  KUidMsvMessageEntry
       
   133 											  KUidMsvEmailHtmlEntry
       
   134   	  	                                      KUidMsvEmailExternalBodyEntry
       
   135   	  	                                      KUidMsvEmailRtfEntry
       
   136 @param aFolders		 - accept entries of type KUidMsvFolderEntry
       
   137 @param aIsInService	 - only accept entries under the IMAP service entry
       
   138 
       
   139 @return KErrNotSupported if no valid entries,
       
   140         KErrNone otherwise
       
   141 */
       
   142 TInt CImapCompoundBase::CheckSelectionL(const CMsvEntrySelection& aSelection,
       
   143 									    CMsvEntrySelection* aLocalCopy,
       
   144 									    const TBool aMessages,
       
   145 									    const TBool aParts,
       
   146 									    const TBool aFolders,
       
   147 									    const TBool aIsInService)
       
   148 	{
       
   149 	// reset the local copy
       
   150 	aLocalCopy->Reset();
       
   151 	
       
   152 	// get the service ID
       
   153 	TMsvId serviceId = iImapSettings.ServiceId();
       
   154 
       
   155 	// Check all entries are messages
       
   156 	for(TInt a=0;a<aSelection.Count();a++)
       
   157 		{
       
   158 		// Does entry exist?
       
   159 		TBool addIt = EFalse;
       
   160 
       
   161 		if (iServerEntry.SetEntry(aSelection[a])==KErrNone)
       
   162 			{
       
   163 			TUid type = iServerEntry.Entry().iType;
       
   164 			if ((aMessages && type==KUidMsvMessageEntry) ||
       
   165 				(aParts && (type==KUidMsvEmailTextEntry || type==KUidMsvAttachmentEntry || type==KUidMsvMessageEntry || type==KUidMsvEmailHtmlEntry || type==KUidMsvEmailExternalBodyEntry || type==KUidMsvEmailRtfEntry)) ||
       
   166 				(aFolders && type==KUidMsvFolderEntry))
       
   167 				{
       
   168 				TBool inEnclosingMessage=EFalse;
       
   169 
       
   170 				// Do we need to check if it's in the local service or
       
   171 				// if it is a complete message
       
   172 				if (aIsInService || (!aParts && type==KUidMsvMessageEntry))
       
   173 					{
       
   174 					// Work up the tree until we get to the service or the root
       
   175 					do
       
   176 						{
       
   177 						SetEntryL(iServerEntry.Entry().Parent());
       
   178 						if (iServerEntry.Entry().iType==KUidMsvMessageEntry)
       
   179 							{
       
   180 							inEnclosingMessage=ETrue;
       
   181 							}
       
   182 						}
       
   183 					while(iServerEntry.Entry().iType!=KUidMsvServiceEntry &&
       
   184 						  iServerEntry.Entry().Id()!=KMsvRootIndexEntryId);		
       
   185 	
       
   186 					// Are we at the service that this MTM referrs to?
       
   187 					// if offline iServiceId==0 so allow all
       
   188 					if (!aIsInService || serviceId==0 || iServerEntry.Entry().Id()==serviceId)
       
   189 						{
       
   190 						// it's OK if it is not a message type (in
       
   191 						// which case it has already been checked and
       
   192 						// passed) or it is not within an enclosing message
       
   193 						if (type!=KUidMsvMessageEntry || !inEnclosingMessage || aParts)
       
   194 							{
       
   195 							addIt = ETrue;
       
   196 							}
       
   197 						}
       
   198 					}
       
   199 				else
       
   200 					{
       
   201 					// Add to local copy
       
   202 					addIt = ETrue;
       
   203 					}
       
   204 				}
       
   205 			}
       
   206 
       
   207 		if (addIt)
       
   208 			{
       
   209 			aLocalCopy->AppendL(aSelection[a]);
       
   210 			}
       
   211 #ifdef _DEBUG
       
   212 		// UI shouldn't really be giving us bogus items so panic
       
   213 		else
       
   214 			{
       
   215 			TImapServerPanic::ImapPanic(TImapServerPanic::EInvalidMsvTypeToCommand); 
       
   216 			}
       
   217 #endif
       
   218 		}
       
   219 
       
   220 	// Anything to do?
       
   221 	if (!aLocalCopy->Count())
       
   222 		{
       
   223 		// Nothing valid to work with
       
   224 		return(KErrNotSupported);
       
   225 		}
       
   226 	else
       
   227 		{
       
   228 		// All OK, the selection isn't empty
       
   229 		return(KErrNone);
       
   230 		}
       
   231 	}
       
   232 
       
   233 /**
       
   234 Sums the total size of messages to be copied or moved
       
   235 
       
   236 @param aSelection - selection of messages to be processed
       
   237 @return TInt      - the total size of the messages in the selection
       
   238 */
       
   239 TInt CImapCompoundBase::CalculateDownloadSizeL(const CMsvEntrySelection& aSelection)
       
   240 	{
       
   241 	TInt totalSize = 0;
       
   242 
       
   243 	// Do a quick tally on the size of messages which are to be copied / moved.
       
   244 	TInt count=aSelection.Count();
       
   245 	while (count--)
       
   246 		{
       
   247 		SetEntryL(aSelection.At(count));
       
   248 		// Only add the size up if the message is not complete.
       
   249 		if(!iServerEntry.Entry().Complete())
       
   250 			{
       
   251 			totalSize += iServerEntry.Entry().iSize;
       
   252 			}
       
   253 		}
       
   254 	return totalSize;
       
   255 	}
       
   256 
       
   257 /**
       
   258 Find the folder that contains specified message
       
   259 
       
   260 @param aMessage - selection of messages to be processed
       
   261 @return TMsvId  - the parent folder of aMessage, or the service ID.
       
   262 */
       
   263 TMsvId CImapCompoundBase::FindFolderL(const TMsvId aMessage)
       
   264 	{
       
   265 	__LOG_FORMAT((iSession->LogId(), "CImapCompoundBase::FindFolderL(%d)", aMessage));
       
   266 
       
   267 	// Find folder that encloses this message (has Mailbox flag set), or service,
       
   268 	// whichever we find first
       
   269 	SetEntryL(aMessage);
       
   270 	TMsvEmailEntry entry;
       
   271 	do
       
   272 		{
       
   273 		// Change context to parent of current entry
       
   274 		SetEntryL(iServerEntry.Entry().Parent());
       
   275 		entry=iServerEntry.Entry();
       
   276 
       
   277 		__LOG_FORMAT((iSession->LogId(), "  At %x, type=%x, mailbox=%d", entry.Id(),entry.iType,entry.Mailbox()));
       
   278 		
       
   279 		// A folder & a mailbox, or a service?
       
   280 		if (entry.iType==KUidMsvFolderEntry && entry.Mailbox())
       
   281 			{
       
   282 			// This'll do!
       
   283 			return(entry.Id());
       
   284 			}
       
   285 		}
       
   286 	while(iServerEntry.Entry().iType!=KUidMsvServiceEntry && entry.Id()!=KMsvRootIndexEntryId);
       
   287 
       
   288 	__LOG_TEXT(iSession->LogId(), "  FindFolderL() Failed");
       
   289 
       
   290 	return(NULL);
       
   291 	}
       
   292 
       
   293 // Do setentry, leave if there is an error
       
   294 void CImapCompoundBase::SetEntryL(const TMsvId aId)
       
   295 	{
       
   296 	User::LeaveIfError(iServerEntry.SetEntry(aId));
       
   297 	}
       
   298 
       
   299 /**
       
   300 Self completes to allow RunL to be called.
       
   301 */	
       
   302 void CImapCompoundBase::CompleteSelf()
       
   303 	{
       
   304 	SetActive();
       
   305 	TRequestStatus* status = &iStatus;
       
   306 	User::RequestComplete(status, KErrNone);
       
   307 	}
       
   308 
       
   309 
       
   310 void CImapCompoundBase::SetCurrentStep()
       
   311 	{
       
   312 	iCurrentStep = iNextStep;
       
   313 	}
       
   314 
       
   315 /**
       
   316 Save error code in a message
       
   317 
       
   318 @param aMessgeId
       
   319 @param aError
       
   320 */
       
   321 void CImapCompoundBase::MessageErrorL(const TMsvId aMessageId, const TInt aError)
       
   322 	{
       
   323 	// Save error code: if we can't access this entry, then it's probably something to do
       
   324 	// with the error we're trying to report: ignore it silently
       
   325 	if (iServerEntry.SetEntry(aMessageId)==KErrNone)
       
   326 		{
       
   327 		TMsvEntry entry=iServerEntry.Entry();
       
   328 
       
   329 		// Save unnecessary writes...
       
   330 		if (entry.iError!=aError)
       
   331 			{
       
   332 			entry.iError=aError;
       
   333 			User::LeaveIfError(iServerEntry.ChangeEntry(entry));
       
   334 			}
       
   335 		}
       
   336 	}
       
   337 
       
   338 /**
       
   339 Cancels outstanding service request, and recovers the compound operation
       
   340 object to a state in which the operation may be restarted following migration
       
   341 to a new carrier.
       
   342 The operation will be restarted by a call to ResumeOperationL().
       
   343 
       
   344 Derived classes must implement a DoCancel that sets iNextStep to the step
       
   345 that should be performed following the migration, when ReumeOperationL is called;
       
   346 */
       
   347 void CImapCompoundBase::CancelForMigrate()
       
   348 	{
       
   349 	__LOG_TEXT(iSession->LogId(), "CImapCompoundBase::CancelForMigrate()");
       
   350 	iCancelForMigrate = ETrue;
       
   351 	Cancel();
       
   352 	iCancelForMigrate = EFalse;
       
   353 	// Mark Operation as suspended.
       
   354 	iCurrentStep = ESuspendedForMigrate;
       
   355 	}
       
   356 
       
   357 /**
       
   358 Indicates that the compound operation should complete as soon as it is possible
       
   359 for the operation to be re-started without requiring a significant amount of
       
   360 repeated communication.
       
   361 The operation will be restarted by a call to ResumeOperationL()
       
   362 */
       
   363 void CImapCompoundBase::StopForMigrate()
       
   364 	{
       
   365 	__LOG_TEXT(iSession->LogId(), "CImapCompoundBase::StopForMigrate()");
       
   366 	iStopForMigrate = ETrue;
       
   367 	}
       
   368 	
       
   369 /**
       
   370 Returns ETrue if the compound operation has been suspended (stopped/cancelled).
       
   371 This would occur in the case of a bearer migration.
       
   372 */
       
   373 TBool CImapCompoundBase::Suspended()
       
   374 	{
       
   375 	if (iCurrentStep == ESuspendedForMigrate)
       
   376 		{
       
   377 		return ETrue;
       
   378 		}
       
   379 	return EFalse;
       
   380 	}
       
   381