email/imap4mtm/imapsession/src/cimapfetchbody.cpp
changeset 80 8b14b30db193
equal deleted inserted replaced
79:2981cb3aa489 80:8b14b30db193
       
     1 // Copyright (c) 2006-2010 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 "cimapfetchbody.h"
       
    17 #include "moutputstream.h"
       
    18 #include "cimapsession.h"
       
    19 #include "cimapsessionconsts.h"
       
    20 #include "cimapsettings.h"
       
    21 #include "cimapmimeheaderfieldsparser.h"
       
    22 #include "cimapmimeheaderfields.h"
       
    23 #include "cfetchbodyinfo.h"
       
    24 #include "cimapfetchbodyresponse.h"
       
    25 #include "cimaplogger.h"
       
    26 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
    27 #include "cimapcapabilityinfo.h"
       
    28 #endif
       
    29 
       
    30 const TInt KMaxTagIdSize = 8;
       
    31 const TInt KDefaultMaxFetchSize = 20480;
       
    32 const TInt KOutstandingRequests = 2;
       
    33 const TInt KOutstandingBinaryFetchRequests = 1;
       
    34 
       
    35 _LIT8(KCommandFetch, "%S UID FETCH %d (BODY[%S]<%d.%d>)\r\n");
       
    36 _LIT8(KCommandFetchWithMime, "%S UID FETCH %d (BODY[%S]<%d.%d> BODY[%S.MIME])\r\n");
       
    37 _LIT8(KCommandFetchPeek, "%S UID FETCH %d (BODY.PEEK[%S]<%d.%d>)\r\n");
       
    38 _LIT8(KCommandFetchPeekWithMime, "%S UID FETCH %d (BODY.PEEK[%S]<%d.%d> BODY.PEEK[%S.MIME])\r\n");
       
    39 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
    40 _LIT8(KCommandFetchBinary, "%S UID FETCH %d (BINARY[%S]<%d.%d>)\r\n");
       
    41 _LIT8(KCommandFetchBinaryPeek, "%S UID FETCH %d (BINARY.PEEK[%S]<%d.%d>)\r\n");
       
    42 #endif
       
    43 _LIT8(KStartSection,"[");
       
    44 _LIT8(KEndSection,"]");
       
    45 _LIT8(KStartLiteral,"{");
       
    46 _LIT8(KEndLiteral,"}");
       
    47 _LIT8(KStartOrigin,"<");
       
    48 _LIT8(KEndOrigin,">");
       
    49  
       
    50 CImapFetchBody* CImapFetchBody::NewL(CImapFolderInfo* aSelectedFolderData, TInt aLogId, TUint aMessageUid,TBool aPeek, CFetchBodyInfo& aFetchBodyInfo, CImapFetchBodyResponse& aFetchBodyResponse, CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, CImapSession& aParent)
       
    51 	{
       
    52 	CImapFetchBody* self = new (ELeave) CImapFetchBody(aSelectedFolderData, aLogId, aMessageUid, aPeek, aFetchBodyInfo, aFetchBodyResponse, aImapSettings, aImapMailStore, aParent);
       
    53 	CleanupStack::PushL(self);
       
    54 	self->ConstructL();
       
    55 	CleanupStack::Pop(self);
       
    56 	return self;
       
    57 	}
       
    58 	
       
    59 CImapFetchBody::CImapFetchBody(CImapFolderInfo* aSelectedFolderData, TInt aLogId, TUint aMessageUid, TBool aPeek, CFetchBodyInfo& aFetchBodyInfo, CImapFetchBodyResponse& aFetchBodyResponse, CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, CImapSession& aParent)
       
    60 	: CImapCommand(aSelectedFolderData, aLogId),
       
    61 	iMessageUid(aMessageUid),
       
    62 	iPeek(aPeek),
       
    63 	iSizeToFetch(aFetchBodyInfo.SizeToFetch()),
       
    64 	iImapSettings(aImapSettings),
       
    65 	iFetchBodyInfo(aFetchBodyInfo),
       
    66 	iImapMailStore(aImapMailStore),
       
    67 	iParent(aParent),
       
    68 	iFetchBodyResponse(aFetchBodyResponse),
       
    69 	iSendFetch(ETrue)
       
    70 	{
       
    71     iPartialFetch=iFetchBodyInfo.PartialDownload();
       
    72 	}
       
    73 	
       
    74 CImapFetchBody::~CImapFetchBody()
       
    75 	{
       
    76 	// ensure that iImapMailStore will not call StoreOperationComplete() 
       
    77 	// on this object now that it is being destoyed.
       
    78 	
       
    79 	delete iHeaderFieldsParser;
       
    80 	delete iBuf;
       
    81 	iTagIds.Reset();
       
    82 	}
       
    83 
       
    84 /**
       
    85 Overrides CImapCommand::Cancel() by cancelling any outstanding mail store operation.
       
    86 */
       
    87 void CImapFetchBody::Cancel()
       
    88 	{
       
    89 	__LOG_TEXT(iLogId, "CImapFetchBody::Cancel()"); // Overrides CImapCommand::Cancel()
       
    90 	
       
    91 	iImapMailStore.CancelRequest(*this);
       
    92 	CImapCommand::Cancel();
       
    93 	}
       
    94 
       
    95 void CImapFetchBody::StoreOperationComplete(TMsvId /*aId*/,TInt aErrorCode)
       
    96 	{
       
    97 	__LOG_FORMAT((iLogId, "CImapFetchBody::StoreOperationComplete aErrorCode = %d",aErrorCode));
       
    98 	iStoreComplete = ETrue;
       
    99 	
       
   100 	// Complete early if there is an error
       
   101 	if (aErrorCode != KErrNone)
       
   102 		{
       
   103 		__LOG_TEXT(iLogId, "CImapFetchBody::StoreOperationComplete - ERROR: Completing Early");
       
   104 		iParent.FetchBodyOperationComplete(aErrorCode);
       
   105 		}
       
   106 	// Otherwise complete only if the last tagged OK has been received.
       
   107 	else if(ParseState() == ECommandComplete)
       
   108 		{
       
   109 		// Call the session to let it know we are done
       
   110 		__ASSERT_DEBUG(iRequestCount == iTotalRequests && iOutstandingRequests == 0, TImapServerPanic::ImapPanic(TImapServerPanic::EStoreOperationCompleteWithPendingRequest) );
       
   111 		iParent.FetchBodyOperationComplete(aErrorCode);
       
   112 		}
       
   113 	}
       
   114 	
       
   115 TBool CImapFetchBody::IsStoreOperationComplete()
       
   116 	{
       
   117 	return iStoreComplete;
       
   118 	}
       
   119 	
       
   120 void CImapFetchBody::ConstructL()
       
   121 	{
       
   122 	// obtain
       
   123 	iImapSettings.GetTransportBufferSizesL(iMaxFetchSize, iMaxOutstandingRequests);
       
   124 
       
   125 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)		
       
   126 	// check for BINARY capability
       
   127 	const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo();
       
   128 	TBool binaryCapExist = capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap);		
       
   129 #endif
       
   130 	
       
   131 	// if either parameter is undefined, resort to using the defaults.
       
   132 	if(iMaxFetchSize==0)
       
   133 		{
       
   134 		iMaxFetchSize=KDefaultMaxFetchSize;	
       
   135 		}
       
   136 	
       
   137 	if(iMaxOutstandingRequests==0)
       
   138 		{
       
   139 		iMaxOutstandingRequests=KOutstandingRequests;	
       
   140 		}
       
   141 
       
   142 	//calculate the number of chunks that will be needed
       
   143 	iTotalRequests=TotalRequestsRequired(iSizeToFetch);
       
   144 		
       
   145 	__LOG_FORMAT((iLogId, "CImapFetchBody::CImapFetchBody iTotalRequests = %d",iTotalRequests));
       
   146 	
       
   147 	
       
   148 	if(iFetchBodyInfo.IsText())
       
   149 		{
       
   150 		// check if chunk storage mechanism is enabled.
       
   151 		if(iImapSettings.StorePlainText())
       
   152 			{
       
   153 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
   154 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   155 				{
       
   156 				iImapMailStore.InitialiseStorePlainBodyTextL(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this,*this, ETrue);
       
   157 				}
       
   158 			else
       
   159 #endif
       
   160 				{
       
   161 				iImapMailStore.InitialiseStorePlainBodyTextL(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this,*this);
       
   162 				}			
       
   163 			}
       
   164 		else
       
   165 			{
       
   166 			if(iImapSettings.Store8BitData())
       
   167 				{
       
   168 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
   169 				if(binaryCapExist && iFetchBodyInfo.IsText())
       
   170 					{
       
   171 					iImapMailStore.InitialiseStoreBody8L(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this,ETrue);
       
   172 					}
       
   173 				else
       
   174 #endif
       
   175 					{
       
   176 					iImapMailStore.InitialiseStoreBody8L(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this);
       
   177 					}						
       
   178 				}
       
   179 			else
       
   180 				{
       
   181 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
   182 				if(binaryCapExist && iFetchBodyInfo.IsText())
       
   183 					{
       
   184 					iImapMailStore.InitialiseStoreBody16L(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this,ETrue);		
       
   185 					}
       
   186 				else			
       
   187 #endif
       
   188 					{	
       
   189 					iImapMailStore.InitialiseStoreBody16L(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this);		
       
   190 					}
       
   191 				}
       
   192 			}
       
   193 		}
       
   194 	else
       
   195 		{
       
   196 		iImapMailStore.InitialiseStoreAttachmentL(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this);	
       
   197 		}
       
   198 	}
       
   199 
       
   200 TInt CImapFetchBody::TotalRequestsRequired(TInt aSize)
       
   201 	{
       
   202 	
       
   203 	TInt chunkNumber = aSize / iMaxFetchSize;
       
   204 	
       
   205 	if( (aSize % iMaxFetchSize)>0)
       
   206 		{
       
   207 		//add a chunk for the last bit of data
       
   208 		++chunkNumber;
       
   209 		}	
       
   210 
       
   211 	return chunkNumber;	
       
   212 	}
       
   213 
       
   214 
       
   215 TInt CImapFetchBody::CalculateChunk(TInt aPos)
       
   216 	{
       
   217 	return aPos / iMaxFetchSize;
       
   218 	}
       
   219 
       
   220 /** 
       
   221 Formats and sends the IMAP UID FETCH command.
       
   222 @param aTagId Command sequence id which will be send along with the IMAP command.
       
   223 @param aStream A wrapper for the outbound stream of a connected socket, using which 
       
   224 the command will be send to the server
       
   225 */
       
   226 void CImapFetchBody::SendMessageL(TInt aTagId, MOutputStream& aStream)
       
   227 	{	
       
   228 	iOutStream=&aStream;
       
   229 	
       
   230 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)		
       
   231 	// check for BINARY capability
       
   232 	const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo();
       
   233 	TBool binaryCapExist = capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap);		
       
   234 	if(binaryCapExist && iFetchBodyInfo.IsText())
       
   235 		{
       
   236 		// if message body part is downloaded using FETCH BINARY, then there should be only one
       
   237 		// Outstanding Request
       
   238 		iOutstandingRequests = KOutstandingBinaryFetchRequests;
       
   239 		}
       
   240 	else
       
   241 #endif
       
   242 		{
       
   243 		//iOutstandingRequests is the smaller of iMaxOutstandingRequests and the total chunk count
       
   244 		iOutstandingRequests = iTotalRequests>iMaxOutstandingRequests ? iMaxOutstandingRequests : iTotalRequests;
       
   245 		}
       
   246 	// SendMessageL will increment the tag ID as the first thing it does, so we
       
   247 	// should set it to 1 lower than the fist tag we want to send.
       
   248 	iTagId = aTagId - 1;
       
   249 
       
   250 	SendMessageL();	
       
   251 	}
       
   252 	
       
   253 void CImapFetchBody::SendMessageL()
       
   254 	{
       
   255 	// Set the tag ID to use in the next message
       
   256 	++iTagId;
       
   257 
       
   258 	_LIT8(KTagFormatId, "%d");
       
   259 	TBuf8<KMaxTagIdSize>tagIdBuffer;
       
   260 	tagIdBuffer.Format(KTagFormatId,iTagId);
       
   261 	
       
   262 	iTagIds.InsertInOrder(iTagId);
       
   263 	
       
   264 	
       
   265 	//create fetch command based on settings	
       
   266 	//the offset from which we want to fetch data
       
   267 	TInt offset = iRequestCount*iMaxFetchSize;
       
   268 	
       
   269 	// calclulate the size to fetch in this request,
       
   270 	// default to max fetch size.
       
   271 	TUint sizeToFetch = iMaxFetchSize;
       
   272 	
       
   273 	if(iPartialFetch)
       
   274 	    {
       
   275         if ((iRequestCount == (iTotalRequests-1)) && (iSizeToFetch<iMaxFetchSize))
       
   276             sizeToFetch = iSizeToFetch;
       
   277 	    }
       
   278 	
       
   279 	TInt bufLength = 0;
       
   280 	bufLength += iFetchBodyInfo.RelativePath()->Length();
       
   281 	bufLength += TagLength(offset);
       
   282 	bufLength += TagLength(sizeToFetch);
       
   283 	bufLength += tagIdBuffer.Length();
       
   284 
       
   285 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   286 	// check for BINARY capability
       
   287 	// Issue binary fetch for plain/text part only
       
   288 	const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo();
       
   289 	TBool binaryCapExist = capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap);	
       
   290 #endif
       
   291 	if (iRequestCount == 0 && !iFetchBodyInfo.iEmbed)
       
   292 		{
       
   293 		bufLength += iFetchBodyInfo.RelativePath()->Length();
       
   294 		
       
   295 		if (iPeek)
       
   296 			{
       
   297 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   298 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   299 				{
       
   300 				bufLength += KCommandFetchBinaryPeek().Length();
       
   301 				}
       
   302 			else
       
   303 #endif
       
   304 				{
       
   305 				bufLength += KCommandFetchPeekWithMime().Length();	
       
   306 				}
       
   307 			}
       
   308 		else
       
   309 			{
       
   310 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   311 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   312 				{	
       
   313 				bufLength += KCommandFetchBinary().Length();
       
   314 				}
       
   315 			else
       
   316 #endif
       
   317 				{
       
   318 				bufLength += KCommandFetchWithMime().Length();
       
   319 				}			
       
   320 			}
       
   321 		}
       
   322 	else
       
   323 		{
       
   324 		if(iPeek)
       
   325 			{
       
   326 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   327 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   328 				{
       
   329 				bufLength += KCommandFetchBinaryPeek().Length();
       
   330 				}
       
   331 			else
       
   332 #endif
       
   333 				{
       
   334 				bufLength += KCommandFetchPeek().Length();	
       
   335 				}			
       
   336 			}
       
   337 		else
       
   338 			{
       
   339 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   340 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   341 				{
       
   342 				bufLength += KCommandFetchBinary().Length();							
       
   343 				}
       
   344 			else
       
   345 #endif
       
   346 				{
       
   347 				bufLength += KCommandFetch().Length();			
       
   348 				}			
       
   349 			}
       
   350 		}
       
   351 
       
   352 	//now create the command	
       
   353 	HBufC8* buffer = HBufC8::NewL(bufLength);				
       
   354 	delete iOutputBuffer;
       
   355 	iOutputBuffer=buffer;
       
   356 
       
   357 	if (iRequestCount == 0 && !iFetchBodyInfo.iEmbed)
       
   358 		{
       
   359 		if(iPeek)
       
   360 			{
       
   361 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   362 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   363 				{
       
   364 				iOutputBuffer->Des().Format(KCommandFetchBinaryPeek, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch, iFetchBodyInfo.RelativePath());				
       
   365 				}
       
   366 			else
       
   367 #endif
       
   368 				{
       
   369 				iOutputBuffer->Des().Format(KCommandFetchPeekWithMime, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch, iFetchBodyInfo.RelativePath());
       
   370 				}			
       
   371 			}
       
   372 		else
       
   373 			{
       
   374 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   375 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   376 				{
       
   377 				iOutputBuffer->Des().Format(KCommandFetchBinary, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch, iFetchBodyInfo.RelativePath());	
       
   378 				}
       
   379 			else
       
   380 #endif
       
   381 				{
       
   382 				iOutputBuffer->Des().Format(KCommandFetchWithMime, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch, iFetchBodyInfo.RelativePath());	
       
   383 				}
       
   384 			}
       
   385 		}
       
   386 	else
       
   387 		{
       
   388 		iFetchBodyInfo.iEmbed = EFalse;
       
   389 		if(iPeek)
       
   390 			{
       
   391 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   392 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   393 				{
       
   394 				iOutputBuffer->Des().Format(KCommandFetchBinaryPeek, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch);	
       
   395 				}
       
   396 			else
       
   397 #endif
       
   398 				{
       
   399 				iOutputBuffer->Des().Format(KCommandFetchPeek, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch);	
       
   400 				}			
       
   401 			}
       
   402 		else
       
   403 			{
       
   404 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   405 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   406 				{
       
   407 				iOutputBuffer->Des().Format(KCommandFetchBinary, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, iMaxFetchSize);								
       
   408 				}
       
   409 			else
       
   410 #endif
       
   411 				{
       
   412 				iOutputBuffer->Des().Format(KCommandFetch, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, iMaxFetchSize);				
       
   413 				}			
       
   414 			}
       
   415 		}
       
   416 
       
   417 	delete iBuf;
       
   418 	iBuf = NULL;
       
   419 	iReceivedMimeHeaders = EFalse;
       
   420 
       
   421 	//send the command to the server
       
   422 	iOutStream->SendDataReq(*iOutputBuffer);
       
   423 	++iRequestCount;
       
   424 	}
       
   425 
       
   426 /**
       
   427 @param aData Will contain a single line of response from the server for LOGIN command without \r\n.
       
   428 @return will be any one of this
       
   429 	1) If the next expected chunk is a literal block, ParseMessageL() will return the size of the block it expects.
       
   430 	2) If the next expected chunk is a line, ParseMessageL() will return 0, and Result() will return EImapResponseNone.
       
   431 	3) If no further data is expected (e.g. the OK or error tag has been received) then ParseMessageL() will return 0, 
       
   432 	   and Result() will return one of EImapResponseOk, EImapResponseNo or EImapResponseBad.
       
   433 */
       
   434 CImapCommand::TParseBlockResult CImapFetchBody::DoParseBlockL(const TDesC8& aData)
       
   435 	{
       
   436 		
       
   437 	CImapCommand::TParseBlockResult resultCode(ECompleteUntagged);
       
   438 
       
   439 	switch (iState)
       
   440 		{
       
   441 		case EStateDataItemLine:
       
   442 			{
       
   443 			// We are the beginning of a new response, so we can't have found any UID data items yet.
       
   444 			// So we need to reset the flag here.
       
   445 			iUidDataItemFoundInResponse = EFalse;
       
   446 			resultCode = ProcessStartL();
       
   447 			
       
   448 			ASSERT(iState == EStateDataItemLine);
       
   449 			
       
   450 			// If we get EResponseIncomplete then allow the current EStateDataItemLine state to
       
   451 			// drop through to ProcessDataItems()
       
   452 			// otherwise, EStateComplete will take us straight to the return.
       
   453 			if (resultCode != EResponseIncomplete)
       
   454 				{
       
   455 				iState = EStateComplete;
       
   456 				}
       
   457 			}
       
   458 			break;
       
   459 		case EStateBodyLiteral:
       
   460 			{
       
   461 			// Bump progress: bytesdone is *encoded* length, so we just use the encoded length
       
   462 			iFetchBodyInfo.IncrementBytesFetched(aData.Length());
       
   463 			
       
   464 			__ASSERT_DEBUG(aData.Length() == iLiteralSize, TImapServerPanic::ImapPanic(TImapServerPanic::ETParseBlockResultInvalidLiteralSize) );
       
   465 
       
   466 			ProcessBodyLiteralL(aData);
       
   467 			resultCode = EResponseIncomplete; // always expect more data after a literal
       
   468 			}
       
   469 			break;
       
   470 		case EStateMime:
       
   471 			{
       
   472 			ProcessRestOfMimeL(iUnparsedData);
       
   473 			resultCode = EResponseIncomplete;
       
   474 			}
       
   475 			break;
       
   476 		case EStateFetchNextDataItemLine:
       
   477 			{
       
   478 			// Fetch is over.  Get ready to process next data item.
       
   479 			iUnparsedData.Set(aData);
       
   480 			GetAndStoreNextPart();
       
   481 			
       
   482 			iState = EStateDataItemLine;
       
   483 			}
       
   484 			break;
       
   485 		default:
       
   486 			{
       
   487 			// unexpected state
       
   488 			ASSERT(EFalse);
       
   489 			}
       
   490 		}
       
   491 
       
   492 	// The ProcessXxxL() methods above can change the state.
       
   493 	// Now we need to check if there are data items to process...
       
   494 	if (iState == EStateDataItemLine)
       
   495 		{
       
   496 		resultCode = ProcessDataItemsL();
       
   497 		}
       
   498 	else if (iState == EStateComplete)
       
   499 		{
       
   500 		//if we still have more requests to issue send the next one now
       
   501 		
       
   502 		if(resultCode == ECompleteTagged)
       
   503 			{
       
   504 			if (iResponseCode == EImapResponseOk)
       
   505 				{
       
   506 				++iResponseCount;
       
   507 				// If we received some MIME headers, we may need to store them
       
   508 				// with the CAF framework
       
   509 				if ((iReceivedMimeHeaders) && (iFetchBodyInfo.Caf() != NULL) && (iFetchBodyInfo.Caf()->Registered()))
       
   510 					{
       
   511 					WriteMimeHeadersToCafL();
       
   512 					}
       
   513 
       
   514 				// Store the body data if we received it
       
   515 				if (iBuf != NULL)
       
   516 					{
       
   517 					TInt extraFetchRequestCount = 0;
       
   518 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)					
       
   519 					// check for BINARY capability
       
   520 					const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo();
       
   521 					TBool binaryCapExist = capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap);					
       
   522 					if(binaryCapExist && iFetchBodyInfo.IsText() && iPreviousLiteralBytesReceived < KDefaultMaxFetchSize)
       
   523 						{
       
   524 						extraFetchRequestCount = iTotalRequests - iRequestCount;
       
   525 						// iTotalRequests, iRequestCount and iResponseCount should be same at this stage
       
   526 						// iResponseCount will be same as iRequestCount
       
   527 						iTotalRequests=iRequestCount;
       
   528 						//reset iPreviousLiteralBytesReceived to zero
       
   529 						iPreviousLiteralBytesReceived=0;										
       
   530 						}
       
   531 #endif
       
   532 						
       
   533 					StoreBodyDataL(extraFetchRequestCount);										
       
   534 					
       
   535 					if (iRequestCount<iTotalRequests)
       
   536 						{
       
   537 						// if there are outstanding requests already then just add this request to the count
       
   538 						++iOutstandingRequests;
       
   539 						
       
   540 						// If iOutstandingRequests is greater than one, this means a write operation is in progress
       
   541 						// and the message will be sent when SendDataCnf() is called.
       
   542 						if (iSendFetch && (iOutstandingRequests == 1))
       
   543 							{
       
   544 							SendMessageL();
       
   545 							}
       
   546 
       
   547 						resultCode=ECompleteUntagged;
       
   548 						iResponseCode=EImapResponseNone;
       
   549 						}
       
   550 					// if there are remaining requests yet to be received then tell the session were not finished.
       
   551 					else if(iResponseCount<iTotalRequests)
       
   552 						{
       
   553 						resultCode = ECompleteUntagged;	
       
   554 						iResponseCode=EImapResponseNone;	
       
   555 						}
       
   556 					}
       
   557 				// if there is no body part to be stored but server sent a OK responsethen set 
       
   558 				// iStoreComplete to ETrue and Cancel the Request.If more than one FETCH was sent
       
   559 				// then Flush the state so that all incoming server data is discarded.
       
   560 				else
       
   561 					{
       
   562 					iStoreComplete = ETrue;
       
   563 					iImapMailStore.CancelRequest(*this);	
       
   564 					
       
   565 					// Check the tag id
       
   566 					if(iTagIds.Count())
       
   567 						{
       
   568 						EnterFlushingState();
       
   569 						resultCode = ECompleteUntagged;
       
   570 						iResponseCode = EImapResponseNone;
       
   571 						}		
       
   572 					}
       
   573 				}
       
   574 			else
       
   575 				{
       
   576 				iImapMailStore.CancelRequest(*this);
       
   577 				}
       
   578 			}
       
   579 			
       
   580 		// this response is complete, so the next data (if any) will be a data item line,
       
   581 		iState = EStateDataItemLine;
       
   582 		}
       
   583 
       
   584 	// For complete untagged responses, check whether the UID data item was received.
       
   585 	// If it was, then this was a genuine response to the UID FETCH command.
       
   586 	// If it was not received, then this was an unsolicited server event, and the data should be discarded.
       
   587 	if (resultCode == ECompleteUntagged)
       
   588 		{
       
   589 		if (iUidDataItemFoundInResponse)
       
   590 			{
       
   591 			// Genuine UID FETCH response - copy UID and FLAG info into the response object
       
   592 			iFetchBodyResponse.SetMessageFlagInfo(iMessageFlagInfo);
       
   593 			
       
   594 			// Note: iUidDataItemFoundInResponse is NOT reset here
       
   595 			// 		 Instead iUidDataItemFoundInResponse is set to EFalse just prior to calling ProcessStartL() - i.e. at the start of a new response.
       
   596 			}
       
   597 		else
       
   598 			{
       
   599 			// Record that an unsolicited FETCH was received - so that a sync will be triggered after this command.
       
   600 			__LOG_TEXT(iLogId, "CImapFetchBody::DoParseBlockL() - Found unsolicited FETCH FLAGS");
       
   601 			SetMessageFlagsChanged();
       
   602 			}
       
   603 		}
       
   604 
       
   605 	return resultCode;
       
   606 	}
       
   607 
       
   608 /**
       
   609 Returns the number of tagged responses that are currently expected.
       
   610 Because CImapFetchBody uses pipelining - with many simulataneous request running at once
       
   611 it will be expect a tagged response for each request that is still running on the server.
       
   612 @return the number of tagged responses that are currently expected.
       
   613 */
       
   614 TInt CImapFetchBody::NumberOfTaggedResponsesExpected() const
       
   615 	{
       
   616 	return iTagIds.Count();
       
   617 	}
       
   618 	
       
   619 CImapCommand::TParseBlockResult CImapFetchBody::ProcessStartL()
       
   620 	{
       
   621 	TParseBlockResult result = ENotRecognised;
       
   622 
       
   623 	TInt tagId = 0;	
       
   624 	TTagType tagged = GetTagTypeL(tagId);
       
   625 	switch(tagged)
       
   626 		{
       
   627 		case ETagged:
       
   628 			{
       
   629 			// Check the tag id
       
   630 			TInt tagPos=iTagIds.FindInOrder(tagId);
       
   631 			if(tagPos!=KErrNotFound)
       
   632 				{
       
   633 				iTagIds.Remove(tagPos);	
       
   634 				}
       
   635 			else
       
   636 				{
       
   637 				//Unexpected Tagid	
       
   638 	 			CorruptDataL();	
       
   639 				}
       
   640 	 		
       
   641  			// Fetch and check the response code
       
   642 			iResponseCode = GetResponseStateCode();
       
   643 			if (iResponseCode == EImapResponseNone)
       
   644 				{
       
   645 				// Was expecting one of OK/NO/BAD, but didn't get it.  This is a parse error.
       
   646 				CorruptDataL();
       
   647 				}
       
   648 				
       
   649 			result =ECompleteTagged;		
       
   650 			}
       
   651 			break;
       
   652 			
       
   653 		case EUntagged:
       
   654 			{
       
   655 			// Is this a FETCH response?
       
   656 			// Check for Sequence Number followed by "FETCH"
       
   657 			
       
   658 			TPtrC8 part1 = GetNextPart(); // returns KNullDesC8 if there is no part available
       
   659 			TPtrC8 part2 = GetNextPart(); // returns KNullDesC8 if there is no part available
       
   660 			
       
   661 			// Is part1 a Sequence Number?
       
   662 			TInt sequenceNumber = 0;
       
   663 			TLex8 lex(part1);
       
   664 			if (lex.Val(sequenceNumber) == KErrNone)
       
   665 				{
       
   666 				// part1 is a Sequence Number.  Now check part2 - is it "FETCH"?
       
   667 
       
   668 				if(part2.CompareF(KImapTxtFetch) == 0)
       
   669 					{
       
   670 										
       
   671 					if (GetAndStoreNextPart())
       
   672 						{
       
   673 						if (iCurrentPart[0] == '(')
       
   674 							{
       
   675 							iCurrentPart.Set(iCurrentPart.Mid(1));
       
   676 							}
       
   677 						else
       
   678 							{
       
   679 							// was expecting a bracket, got something else
       
   680 							CorruptDataL();
       
   681 							}
       
   682 						}
       
   683 					else
       
   684 						{
       
   685 						// was expecting a bracket, got nothing
       
   686 						CorruptDataL();
       
   687 						}
       
   688 
       
   689 					result = EResponseIncomplete;
       
   690 					}
       
   691 				}
       
   692 			}
       
   693 			break;
       
   694 		case EContinuation:
       
   695 		default:
       
   696 			{
       
   697 			CorruptDataL();
       
   698 			}
       
   699 			break;
       
   700 		}
       
   701 
       
   702 	// result will be ENotRecognised if tagged not found or untagged FETCH not found.
       
   703 	return result;
       
   704 	}
       
   705 
       
   706 CImapCommand::TParseBlockResult CImapFetchBody::ProcessDataItemsL()
       
   707 	{
       
   708 	CImapCommand::TParseBlockResult resultCode = EResponseIncomplete;
       
   709 	
       
   710 	TBool foundPart = ETrue;
       
   711 	while (iState == EStateDataItemLine && foundPart)
       
   712 		{
       
   713 		if (iCurrentPart.CompareF(KImapTxtUid) == 0)
       
   714 			{
       
   715 			ProcessUidL();
       
   716 			}
       
   717 		else if (iCurrentPart.CompareF(KImapTxtFlags) == 0)
       
   718 			{
       
   719 			ProcessFlagsL();
       
   720 			}
       
   721 	
       
   722 		// check if the part starts 'BODY['	
       
   723 		else if (iCurrentPart.Find(KImapTxtBody)==0)
       
   724 			{
       
   725 			//is it the body or the body.mime?
       
   726 			if(iCurrentPart.Find(KImapTxtMime) != KErrNotFound )
       
   727 				{
       
   728 				ProcessStartOfMimeL();
       
   729 				}
       
   730 			else
       
   731 				{
       
   732 				ProcessBodyL();	
       
   733 				}
       
   734 			}
       
   735 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
   736 		// check if the part starts 'BINARY['	
       
   737 		else if (iCurrentPart.Find(KImapTxtBinary)==0)
       
   738 			{
       
   739 			// no mime to process for fetch binary
       
   740 			ProcessBodyL();	
       
   741 			}
       
   742 #endif
       
   743 	
       
   744 		// Only fetch the next part if we're still searching for data items.
       
   745 		if (iState == EStateDataItemLine)
       
   746 			{
       
   747 			foundPart = GetAndStoreNextPart();
       
   748 			}
       
   749 		}
       
   750 		
       
   751 	if (!foundPart && iState == EStateDataItemLine)
       
   752 		{
       
   753 		if(iBuf && iUnexpectedFormat)
       
   754 			{
       
   755 			iState = EStateFetchNextDataItemLine;
       
   756 			iUnexpectedFormat = EFalse;
       
   757 			}
       
   758 		resultCode = ECompleteUntagged;
       
   759 		}
       
   760 	iUnexpectedFormat = EFalse;	
       
   761 	return resultCode;
       
   762 	}
       
   763 
       
   764 
       
   765 void CImapFetchBody::ProcessStartOfMimeL()
       
   766 	{
       
   767 	//look for the body section that is being returned 
       
   768 	TInt secStart=iCurrentPart.Find(KStartSection);
       
   769 	TInt secEnd=iCurrentPart.Find(KImapTxtMime);
       
   770 
       
   771 	if(secStart==KErrNotFound || secEnd==KErrNotFound)
       
   772 		{
       
   773 		CorruptDataL();
       
   774 		}
       
   775 
       
   776 	TPtrC8 section = iCurrentPart.Mid(secStart + 1, secEnd - secStart - 1);
       
   777 
       
   778 	//check the section is what we asked for
       
   779 	if(section.CompareF(*iFetchBodyInfo.RelativePath())  != 0)
       
   780 		{
       
   781 		CorruptDataL();
       
   782 		}
       
   783 
       
   784 	// Peek the next part. We don't want to consume it as we may need
       
   785 	// to pass it to the header fields parser.
       
   786 	iCurrentPart.Set(PeekNextPart());
       
   787 	if (iCurrentPart.Length() == 0)
       
   788 		{
       
   789 		CorruptDataL();
       
   790 		}
       
   791 
       
   792 	iReceivedMimeHeaders = ETrue;
       
   793 	
       
   794 	// If the last character is ')' then we're at the last data item in the list.
       
   795 	// Consume the character so that the rest of the data item can be interpreted.
       
   796 	if (iCurrentPart.Right(1).CompareF(KImapTxtCloseBracket) == 0)
       
   797 		{
       
   798 		iCurrentPart.Set(iCurrentPart.Left(iCurrentPart.Length() - 1));
       
   799 		}
       
   800 	
       
   801 	// Check if data part is NIL or "" for empty string
       
   802 	if (iCurrentPart.CompareF(KImapTxtNil) == 0 || iCurrentPart.CompareF(KImapTxtEmptyStringAsDoubleQuotePair) == 0)
       
   803 		{
       
   804 		// Consume the NIL part
       
   805 		GetAndStoreNextPart();
       
   806 
       
   807 		// Create empty MIME header fields
       
   808 		CImapMimeHeaderFields* fields = CImapMimeHeaderFields::NewL();
       
   809 		iFetchBodyResponse.SetHeaderFields(fields);
       
   810 
       
   811 		// May be more data items coming up
       
   812 		iState = EStateDataItemLine;
       
   813 		}
       
   814 	else
       
   815 		{
       
   816 		// Pass the rest of the line to the header fields parser
       
   817 		iHeaderFieldsParser = CImapMimeHeaderFieldsParser::NewL(iFetchBodyResponse, iLogId);
       
   818 		iState = EStateMime;
       
   819 		ProcessRestOfMimeL(iUnparsedData);
       
   820 		}
       
   821 	}
       
   822 
       
   823 void CImapFetchBody::ProcessRestOfMimeL(const TDesC8& aData)
       
   824 	{
       
   825 	TBool wantsMore = iHeaderFieldsParser->ProcessBlockL(aData);
       
   826 
       
   827 	if (!wantsMore)
       
   828 		{
       
   829 		delete iHeaderFieldsParser;
       
   830 		iHeaderFieldsParser = NULL;
       
   831 		iState = EStateFetchNextDataItemLine;
       
   832 		}
       
   833 	}
       
   834 
       
   835 void CImapFetchBody::ProcessBodyL()
       
   836 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
   837 	{//BODY[1]<0> or BINARY[1]<0>
       
   838 #else
       
   839 	{//BODY[1]<0>
       
   840 #endif	
       
   841 	//look for the body section that is being returned 
       
   842 	TInt secStart=iCurrentPart.Find(KStartSection);
       
   843 	TInt secEnd=iCurrentPart.Find(KEndSection);
       
   844 	
       
   845 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
   846 	const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo();
       
   847 	if(capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap) && iFetchBodyInfo.IsText())
       
   848 		{
       
   849 		if(secStart!=KImapTxtBinary().Length() - 1  || secEnd <= secStart + 1)
       
   850 			{
       
   851 			CorruptDataL();
       
   852 			}
       
   853 		}
       
   854 	else
       
   855 #endif 
       
   856 		{
       
   857 		if(secStart!=KImapTxtBody().Length() - 1  || secEnd <= secStart + 1)
       
   858 			{
       
   859 			CorruptDataL();
       
   860 			}						
       
   861 		}
       
   862 			
       
   863 	TPtrC8 section=iCurrentPart.Mid(secStart+1,secEnd-secStart-1);
       
   864 	
       
   865 	//check the section is what we asked for
       
   866 	if(section.CompareF(*iFetchBodyInfo.RelativePath())  != 0)
       
   867 		{
       
   868 		CorruptDataL();
       
   869 		}
       
   870 	
       
   871 	//get the origin octet of the form <origin>, this may not exist, if its not
       
   872 		//then the origin is at the start of the data
       
   873 	TInt originStart=iCurrentPart.Find(KStartOrigin);
       
   874 	if(originStart==KErrNotFound)
       
   875 		{
       
   876 		//the origin octet will be 0, the data will  go in the first chunk
       
   877 		iCurrentChunk=0;		
       
   878 		}
       
   879 	else
       
   880 		{
       
   881 		if(originStart != secEnd + 1)
       
   882 			{
       
   883 			CorruptDataL();
       
   884 			}
       
   885 		TInt originEnd=iCurrentPart.Find(KEndOrigin);
       
   886 		if(originEnd==KErrNotFound || originEnd != iCurrentPart.Length() - 1 )
       
   887 			{
       
   888 			CorruptDataL();	
       
   889 			}
       
   890 		if(originEnd <= originStart + 1)
       
   891 			{
       
   892 			CorruptDataL();	
       
   893 			}
       
   894 			
       
   895 		TPtrC8 originPtr=iCurrentPart.Mid(originStart+1,originEnd-originStart-1);
       
   896 		TLex8 originToInt(originPtr);
       
   897 	
       
   898 		TInt origin=0;
       
   899 		TInt err = originToInt.Val(origin);
       
   900 		if (err != KErrNone)
       
   901 			{
       
   902 			// Was expecting originPtr to be a number
       
   903 			CorruptDataL();
       
   904 			}
       
   905 		
       
   906 		//set the chunk number
       
   907 		//if the origin was blank ie. <> then this is set to 0, the start of the data 
       
   908 		iCurrentChunk = CalculateChunk(origin);
       
   909 		}
       
   910 		
       
   911 	//now look for the size of the literal
       
   912 	TBool foundPart = GetAndStoreNextPart();
       
   913 	if(!foundPart)
       
   914 		{
       
   915 		CorruptDataL();	
       
   916 		}
       
   917 		
       
   918 	TInt litStart=iCurrentPart.Find(KStartLiteral);
       
   919 	TInt litEnd=iCurrentPart.Find(KEndLiteral);
       
   920 	
       
   921 	if(litStart==KErrNotFound && litEnd==KErrNotFound)
       
   922 		{
       
   923 		// This may be the data item
       
   924 		ProcessBodyLiteralL(iCurrentPart);
       
   925 		iState = EStateDataItemLine;
       
   926 		iUnexpectedFormat = ETrue;
       
   927 		}
       
   928 	else
       
   929 		{
       
   930 		if(litStart==KErrNotFound || litEnd==KErrNotFound)
       
   931 			{
       
   932 			CorruptDataL();	
       
   933 			}
       
   934 
       
   935 		if(litEnd <= litStart + 1)
       
   936 			{
       
   937 			CorruptDataL();	
       
   938 			}
       
   939 
       
   940 		TPtrC8 litPtr=iCurrentPart.Mid(litStart+1,litEnd-litStart-1);
       
   941 		TLex8 litSizeToInt(litPtr);
       
   942 		
       
   943 		TInt err = litSizeToInt.Val(iLiteralSize);
       
   944 		if (err != KErrNone)
       
   945 			{
       
   946 			// Was expecting litPtr to be a number
       
   947 			CorruptDataL();
       
   948 			}
       
   949 		
       
   950 		if(GetAndStoreNextPart())
       
   951 			{
       
   952 			ProcessBodyLiteralL(iCurrentPart);
       
   953 			iState = EStateDataItemLine;
       
   954 			iUnexpectedFormat = ETrue;
       
   955 			}
       
   956 		else
       
   957 			{
       
   958 			//now wait for the litereral
       
   959 			iState = EStateBodyLiteral;
       
   960 			}
       
   961 		}
       
   962 	}
       
   963 	
       
   964 void CImapFetchBody::ProcessBodyLiteralL(const TDesC8& aData)
       
   965 	{
       
   966 	delete iBuf;
       
   967 	iBuf = NULL;
       
   968 	iBuf = aData.AllocL();
       
   969 	
       
   970 	//now wait for the line that always follows a literal
       
   971 	iState = EStateFetchNextDataItemLine;
       
   972 	}
       
   973 
       
   974 /**
       
   975 Move to the next part
       
   976 @return whether a part was found
       
   977 */
       
   978 TBool CImapFetchBody::GetAndStoreNextPart()
       
   979 	{
       
   980 	iCurrentPart.Set(GetNextPart());
       
   981 	return (iCurrentPart.Length() > 0) ? ETrue : EFalse;
       
   982 	}
       
   983 
       
   984 void CImapFetchBody::ProcessFlagsL()
       
   985 	{
       
   986 	iUnparsedData.Set(iMessageFlagInfo.ParseFlagsL(iUnparsedData));
       
   987 	}
       
   988 
       
   989 void CImapFetchBody::ProcessUidL()
       
   990 	{
       
   991 	if (GetAndStoreNextPart())
       
   992 		{
       
   993 		TInt err = iMessageFlagInfo.SetMessageUid(iCurrentPart);
       
   994 		if (err == KErrNone)
       
   995 			{
       
   996 			iUidDataItemFoundInResponse = ETrue;
       
   997 			}
       
   998 		else
       
   999 			{
       
  1000 			// expected iCurrentPart to be a number representing a UID.
       
  1001 			// but we did not get a number.
       
  1002 			CorruptDataL();
       
  1003 			}
       
  1004 		}
       
  1005 	}
       
  1006 
       
  1007 void CImapFetchBody::WriteMimeHeadersToCafL()
       
  1008 	{
       
  1009 	CImapMimeHeaderFields* fields = iFetchBodyResponse.HeaderFields();
       
  1010 	if (fields != NULL)
       
  1011 		{
       
  1012 		TPtrC8 name;
       
  1013 		TPtrC8 value;
       
  1014 
       
  1015 		fields->RestartGetNextField();
       
  1016 		while (fields->GetNextField(name, value))
       
  1017 			{
       
  1018 			__LOG_FORMAT((iLogId, "Add CAF metadata: %S %S", &name, &value));
       
  1019 			iFetchBodyInfo.Caf()->AddToMetaDataL(name, value);
       
  1020 			}
       
  1021 		}
       
  1022 	}
       
  1023 
       
  1024 void CImapFetchBody::StoreBodyDataL(TBool aExtraFetchRequestCount)
       
  1025 	{
       
  1026 	// We are going to pass the buffer to the mail store, so set our
       
  1027 	// buffer to NULL so that we don't try to delete it if the store
       
  1028 	// routine leaves.
       
  1029 	HBufC8* buf(iBuf);
       
  1030 	iBuf = NULL;
       
  1031 
       
  1032 	if(iFetchBodyInfo.IsText())
       
  1033 		{
       
  1034 		if(iImapSettings.StorePlainText())
       
  1035 			{
       
  1036 			iSendFetch = iImapMailStore.StorePlainBodyTextL(buf,iFetchBodyInfo.PartId(),iCurrentChunk,aExtraFetchRequestCount);
       
  1037 			}
       
  1038 		else
       
  1039 			{
       
  1040 			if(iImapSettings.Store8BitData())
       
  1041 				{
       
  1042 				iImapMailStore.StoreBodyChunk8L(buf,iFetchBodyInfo.PartId(),iCurrentChunk,aExtraFetchRequestCount);
       
  1043 				}
       
  1044 			else
       
  1045 				{
       
  1046 				iImapMailStore.StoreBodyChunk16L(buf,iFetchBodyInfo.PartId(),iCurrentChunk,aExtraFetchRequestCount);	
       
  1047 				}
       
  1048 			}
       
  1049 		}
       
  1050 	else //attachments
       
  1051 		{
       
  1052 		iImapMailStore.StoreAttachmentChunkL(buf,iFetchBodyInfo.PartId(),iCurrentChunk);
       
  1053 		}
       
  1054 	}
       
  1055 
       
  1056 /**
       
  1057 If pipelining is enabled then this method will send the next fetch request to the server after confirmation of the last request having been sent.
       
  1058 @return void
       
  1059 */ 
       
  1060 
       
  1061 
       
  1062 void CImapFetchBody::SendDataCnfL()
       
  1063 	{
       
  1064 	ASSERT(iOutstandingRequests>0);
       
  1065 	--iOutstandingRequests;
       
  1066 	//if we want more requests outstanding then send the next one now
       
  1067 	if(iOutstandingRequests>0 && iSendFetch)
       
  1068 		{
       
  1069 		SendMessageL();	
       
  1070 		}
       
  1071 	}
       
  1072 /**
       
  1073 This method will enable the FETCH command to be send to the server if it was
       
  1074 disabled by CImapMailStore due to reciept of out-of-order chunks.
       
  1075 @return void
       
  1076 */	
       
  1077 void CImapFetchBody::EnableSendFetch()
       
  1078 	{
       
  1079 	iSendFetch = ETrue;
       
  1080 	}