diff -r 6a20128ce557 -r ebfee66fde93 email/imap4mtm/imapsession/src/cimapfetchbody.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/email/imap4mtm/imapsession/src/cimapfetchbody.cpp Fri Jun 04 10:25:39 2010 +0100 @@ -0,0 +1,1072 @@ +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "cimapfetchbody.h" +#include "moutputstream.h" +#include "cimapsession.h" +#include "cimapsessionconsts.h" +#include "cimapsettings.h" +#include "cimapmimeheaderfieldsparser.h" +#include "cimapmimeheaderfields.h" +#include "cfetchbodyinfo.h" +#include "cimapfetchbodyresponse.h" +#include "cimaplogger.h" +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) +#include "cimapcapabilityinfo.h" +#endif + +const TInt KMaxTagIdSize = 8; +const TInt KDefaultMaxFetchSize = 20480; +const TInt KOutstandingRequests = 2; +const TInt KOutstandingBinaryFetchRequests = 1; + +_LIT8(KCommandFetch, "%S UID FETCH %d (BODY[%S]<%d.%d>)\r\n"); +_LIT8(KCommandFetchWithMime, "%S UID FETCH %d (BODY[%S]<%d.%d> BODY[%S.MIME])\r\n"); +_LIT8(KCommandFetchPeek, "%S UID FETCH %d (BODY.PEEK[%S]<%d.%d>)\r\n"); +_LIT8(KCommandFetchPeekWithMime, "%S UID FETCH %d (BODY.PEEK[%S]<%d.%d> BODY.PEEK[%S.MIME])\r\n"); +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) +_LIT8(KCommandFetchBinary, "%S UID FETCH %d (BINARY[%S]<%d.%d>)\r\n"); +_LIT8(KCommandFetchBinaryPeek, "%S UID FETCH %d (BINARY.PEEK[%S]<%d.%d>)\r\n"); +#endif +_LIT8(KStartSection,"["); +_LIT8(KEndSection,"]"); +_LIT8(KStartLiteral,"{"); +_LIT8(KEndLiteral,"}"); +_LIT8(KStartOrigin,"<"); +_LIT8(KEndOrigin,">"); + +CImapFetchBody* CImapFetchBody::NewL(CImapFolderInfo* aSelectedFolderData, TInt aLogId, TUint aMessageUid,TBool aPeek, CFetchBodyInfo& aFetchBodyInfo, CImapFetchBodyResponse& aFetchBodyResponse, CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, CImapSession& aParent) + { + CImapFetchBody* self = new (ELeave) CImapFetchBody(aSelectedFolderData, aLogId, aMessageUid, aPeek, aFetchBodyInfo, aFetchBodyResponse, aImapSettings, aImapMailStore, aParent); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CImapFetchBody::CImapFetchBody(CImapFolderInfo* aSelectedFolderData, TInt aLogId, TUint aMessageUid, TBool aPeek, CFetchBodyInfo& aFetchBodyInfo, CImapFetchBodyResponse& aFetchBodyResponse, CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, CImapSession& aParent) + : CImapCommand(aSelectedFolderData, aLogId), + iMessageUid(aMessageUid), + iPeek(aPeek), + iSizeToFetch(aFetchBodyInfo.SizeToFetch()), + iImapSettings(aImapSettings), + iFetchBodyInfo(aFetchBodyInfo), + iImapMailStore(aImapMailStore), + iParent(aParent), + iFetchBodyResponse(aFetchBodyResponse), + iSendFetch(ETrue) + { + } + +CImapFetchBody::~CImapFetchBody() + { + // ensure that iImapMailStore will not call StoreOperationComplete() + // on this object now that it is being destoyed. + + delete iHeaderFieldsParser; + delete iBuf; + iTagIds.Reset(); + } + +/** +Overrides CImapCommand::Cancel() by cancelling any outstanding mail store operation. +*/ +void CImapFetchBody::Cancel() + { + __LOG_TEXT(iLogId, "CImapFetchBody::Cancel()"); // Overrides CImapCommand::Cancel() + + iImapMailStore.CancelRequest(*this); + CImapCommand::Cancel(); + } + +void CImapFetchBody::StoreOperationComplete(TMsvId /*aId*/,TInt aErrorCode) + { + __LOG_FORMAT((iLogId, "CImapFetchBody::StoreOperationComplete aErrorCode = %d",aErrorCode)); + iStoreComplete = ETrue; + + // Complete early if there is an error + if (aErrorCode != KErrNone) + { + __LOG_TEXT(iLogId, "CImapFetchBody::StoreOperationComplete - ERROR: Completing Early"); + iParent.FetchBodyOperationComplete(aErrorCode); + } + // Otherwise complete only if the last tagged OK has been received. + else if(ParseState() == ECommandComplete) + { + // Call the session to let it know we are done + __ASSERT_DEBUG(iRequestCount == iTotalRequests && iOutstandingRequests == 0, TImapServerPanic::ImapPanic(TImapServerPanic::EStoreOperationCompleteWithPendingRequest) ); + iParent.FetchBodyOperationComplete(aErrorCode); + } + } + +TBool CImapFetchBody::IsStoreOperationComplete() + { + return iStoreComplete; + } + +void CImapFetchBody::ConstructL() + { + // obtain + iImapSettings.GetTransportBufferSizesL(iMaxFetchSize, iMaxOutstandingRequests); + +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + // check for BINARY capability + const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo(); + TBool binaryCapExist = capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap); +#endif + + // if either parameter is undefined, resort to using the defaults. + if(iMaxFetchSize==0) + { + iMaxFetchSize=KDefaultMaxFetchSize; + } + + if(iMaxOutstandingRequests==0) + { + iMaxOutstandingRequests=KOutstandingRequests; + } + + //calculate the number of chunks that will be needed + iTotalRequests=TotalRequestsRequired(iSizeToFetch); + + __LOG_FORMAT((iLogId, "CImapFetchBody::CImapFetchBody iTotalRequests = %d",iTotalRequests)); + + + if(iFetchBodyInfo.IsText()) + { + // check if chunk storage mechanism is enabled. + if(iImapSettings.StorePlainText()) + { +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + if(binaryCapExist && iFetchBodyInfo.IsText()) + { + iImapMailStore.InitialiseStorePlainBodyTextL(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this,*this, ETrue); + } + else +#endif + { + iImapMailStore.InitialiseStorePlainBodyTextL(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this,*this); + } + } + else + { + if(iImapSettings.Store8BitData()) + { +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + if(binaryCapExist && iFetchBodyInfo.IsText()) + { + iImapMailStore.InitialiseStoreBody8L(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this,ETrue); + } + else +#endif + { + iImapMailStore.InitialiseStoreBody8L(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this); + } + } + else + { +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + if(binaryCapExist && iFetchBodyInfo.IsText()) + { + iImapMailStore.InitialiseStoreBody16L(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this,ETrue); + } + else +#endif + { + iImapMailStore.InitialiseStoreBody16L(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this); + } + } + } + } + else + { + iImapMailStore.InitialiseStoreAttachmentL(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this); + } + } + +TInt CImapFetchBody::TotalRequestsRequired(TInt aSize) + { + + TInt chunkNumber = aSize / iMaxFetchSize; + + if( (aSize % iMaxFetchSize)>0) + { + //add a chunk for the last bit of data + ++chunkNumber; + } + + return chunkNumber; + } + + +TInt CImapFetchBody::CalculateChunk(TInt aPos) + { + return aPos / iMaxFetchSize; + } + +/** +Formats and sends the IMAP UID FETCH command. +@param aTagId Command sequence id which will be send along with the IMAP command. +@param aStream A wrapper for the outbound stream of a connected socket, using which +the command will be send to the server +*/ +void CImapFetchBody::SendMessageL(TInt aTagId, MOutputStream& aStream) + { + iOutStream=&aStream; + +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + // check for BINARY capability + const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo(); + TBool binaryCapExist = capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap); + if(binaryCapExist && iFetchBodyInfo.IsText()) + { + // if message body part is downloaded using FETCH BINARY, then there should be only one + // Outstanding Request + iOutstandingRequests = KOutstandingBinaryFetchRequests; + } + else +#endif + { + //iOutstandingRequests is the smaller of iMaxOutstandingRequests and the total chunk count + iOutstandingRequests = iTotalRequests>iMaxOutstandingRequests ? iMaxOutstandingRequests : iTotalRequests; + } + // SendMessageL will increment the tag ID as the first thing it does, so we + // should set it to 1 lower than the fist tag we want to send. + iTagId = aTagId - 1; + + SendMessageL(); + } + +void CImapFetchBody::SendMessageL() + { + // Set the tag ID to use in the next message + ++iTagId; + + _LIT8(KTagFormatId, "%d"); + TBuf8tagIdBuffer; + tagIdBuffer.Format(KTagFormatId,iTagId); + + iTagIds.InsertInOrder(iTagId); + + + //create fetch command based on settings + //the offset from which we want to fetch data + TInt offset = iRequestCount*iMaxFetchSize; + + // calclulate the size to fetch in this request, + // default to max fetch size. + TUint sizeToFetch = iMaxFetchSize; + + TInt bufLength = 0; + bufLength += iFetchBodyInfo.RelativePath()->Length(); + bufLength += TagLength(offset); + bufLength += TagLength(sizeToFetch); + bufLength += tagIdBuffer.Length(); + +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + // check for BINARY capability + // Issue binary fetch for plain/text part only + const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo(); + TBool binaryCapExist = capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap); +#endif + if (iRequestCount == 0) + { + bufLength += iFetchBodyInfo.RelativePath()->Length(); + + if (iPeek) + { +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + if(binaryCapExist && iFetchBodyInfo.IsText()) + { + bufLength += KCommandFetchBinaryPeek().Length(); + } + else +#endif + { + bufLength += KCommandFetchPeekWithMime().Length(); + } + } + else + { +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + if(binaryCapExist && iFetchBodyInfo.IsText()) + { + bufLength += KCommandFetchBinary().Length(); + } + else +#endif + { + bufLength += KCommandFetchWithMime().Length(); + } + } + } + else + { + if(iPeek) + { +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + if(binaryCapExist && iFetchBodyInfo.IsText()) + { + bufLength += KCommandFetchBinaryPeek().Length(); + } + else +#endif + { + bufLength += KCommandFetchPeek().Length(); + } + } + else + { +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + if(binaryCapExist && iFetchBodyInfo.IsText()) + { + bufLength += KCommandFetchBinary().Length(); + } + else +#endif + { + bufLength += KCommandFetch().Length(); + } + } + } + + //now create the command + HBufC8* buffer = HBufC8::NewL(bufLength); + delete iOutputBuffer; + iOutputBuffer=buffer; + + if (iRequestCount == 0) + { + if(iPeek) + { +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + if(binaryCapExist && iFetchBodyInfo.IsText()) + { + iOutputBuffer->Des().Format(KCommandFetchBinaryPeek, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch, iFetchBodyInfo.RelativePath()); + } + else +#endif + { + iOutputBuffer->Des().Format(KCommandFetchPeekWithMime, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch, iFetchBodyInfo.RelativePath()); + } + } + else + { +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + if(binaryCapExist && iFetchBodyInfo.IsText()) + { + iOutputBuffer->Des().Format(KCommandFetchBinary, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch, iFetchBodyInfo.RelativePath()); + } + else +#endif + { + iOutputBuffer->Des().Format(KCommandFetchWithMime, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch, iFetchBodyInfo.RelativePath()); + } + } + } + else + { + if(iPeek) + { +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + if(binaryCapExist && iFetchBodyInfo.IsText()) + { + iOutputBuffer->Des().Format(KCommandFetchBinaryPeek, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch); + } + else +#endif + { + iOutputBuffer->Des().Format(KCommandFetchPeek, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch); + } + } + else + { +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + if(binaryCapExist && iFetchBodyInfo.IsText()) + { + iOutputBuffer->Des().Format(KCommandFetchBinary, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, iMaxFetchSize); + } + else +#endif + { + iOutputBuffer->Des().Format(KCommandFetch, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, iMaxFetchSize); + } + } + } + + delete iBuf; + iBuf = NULL; + iReceivedMimeHeaders = EFalse; + + //send the command to the server + iOutStream->SendDataReq(*iOutputBuffer); + ++iRequestCount; + } + +/** +@param aData Will contain a single line of response from the server for LOGIN command without \r\n. +@return will be any one of this + 1) If the next expected chunk is a literal block, ParseMessageL() will return the size of the block it expects. + 2) If the next expected chunk is a line, ParseMessageL() will return 0, and Result() will return EImapResponseNone. + 3) If no further data is expected (e.g. the OK or error tag has been received) then ParseMessageL() will return 0, + and Result() will return one of EImapResponseOk, EImapResponseNo or EImapResponseBad. +*/ +CImapCommand::TParseBlockResult CImapFetchBody::DoParseBlockL(const TDesC8& aData) + { + + CImapCommand::TParseBlockResult resultCode(ECompleteUntagged); + + switch (iState) + { + case EStateDataItemLine: + { + // We are the beginning of a new response, so we can't have found any UID data items yet. + // So we need to reset the flag here. + iUidDataItemFoundInResponse = EFalse; + resultCode = ProcessStartL(); + + ASSERT(iState == EStateDataItemLine); + + // If we get EResponseIncomplete then allow the current EStateDataItemLine state to + // drop through to ProcessDataItems() + // otherwise, EStateComplete will take us straight to the return. + if (resultCode != EResponseIncomplete) + { + iState = EStateComplete; + } + } + break; + case EStateBodyLiteral: + { + // Bump progress: bytesdone is *encoded* length, so we just use the encoded length + iFetchBodyInfo.IncrementBytesFetched(aData.Length()); + + __ASSERT_DEBUG(aData.Length() == iLiteralSize, TImapServerPanic::ImapPanic(TImapServerPanic::ETParseBlockResultInvalidLiteralSize) ); + + ProcessBodyLiteralL(aData); + resultCode = EResponseIncomplete; // always expect more data after a literal + } + break; + case EStateMime: + { + ProcessRestOfMimeL(iUnparsedData); + resultCode = EResponseIncomplete; + } + break; + case EStateFetchNextDataItemLine: + { + // Fetch is over. Get ready to process next data item. + iUnparsedData.Set(aData); + GetAndStoreNextPart(); + + iState = EStateDataItemLine; + } + break; + default: + { + // unexpected state + ASSERT(EFalse); + } + } + + // The ProcessXxxL() methods above can change the state. + // Now we need to check if there are data items to process... + if (iState == EStateDataItemLine) + { + resultCode = ProcessDataItemsL(); + } + else if (iState == EStateComplete) + { + //if we still have more requests to issue send the next one now + + if(resultCode == ECompleteTagged) + { + if (iResponseCode == EImapResponseOk) + { + ++iResponseCount; + // If we received some MIME headers, we may need to store them + // with the CAF framework + if ((iReceivedMimeHeaders) && (iFetchBodyInfo.Caf() != NULL) && (iFetchBodyInfo.Caf()->Registered())) + { + WriteMimeHeadersToCafL(); + } + + // Store the body data if we received it + if (iBuf != NULL) + { + TInt extraFetchRequestCount = 0; +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + // check for BINARY capability + const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo(); + TBool binaryCapExist = capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap); + if(binaryCapExist && iFetchBodyInfo.IsText() && iPreviousLiteralBytesReceived < KDefaultMaxFetchSize) + { + extraFetchRequestCount = iTotalRequests - iRequestCount; + // iTotalRequests, iRequestCount and iResponseCount should be same at this stage + // iResponseCount will be same as iRequestCount + iTotalRequests=iRequestCount; + //reset iPreviousLiteralBytesReceived to zero + iPreviousLiteralBytesReceived=0; + } +#endif + + StoreBodyDataL(extraFetchRequestCount); + + if (iRequestCountProcessBlockL(aData); + + if (!wantsMore) + { + delete iHeaderFieldsParser; + iHeaderFieldsParser = NULL; + iState = EStateFetchNextDataItemLine; + } + } + +void CImapFetchBody::ProcessBodyL() +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + {//BODY[1]<0> or BINARY[1]<0> +#else + {//BODY[1]<0> +#endif + //look for the body section that is being returned + TInt secStart=iCurrentPart.Find(KStartSection); + TInt secEnd=iCurrentPart.Find(KEndSection); + +#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT) + const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo(); + if(capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap) && iFetchBodyInfo.IsText()) + { + if(secStart!=KImapTxtBinary().Length() - 1 || secEnd <= secStart + 1) + { + CorruptDataL(); + } + } + else +#endif + { + if(secStart!=KImapTxtBody().Length() - 1 || secEnd <= secStart + 1) + { + CorruptDataL(); + } + } + + TPtrC8 section=iCurrentPart.Mid(secStart+1,secEnd-secStart-1); + + //check the section is what we asked for + if(section.CompareF(*iFetchBodyInfo.RelativePath()) != 0) + { + CorruptDataL(); + } + + //get the origin octet of the form , this may not exist, if its not + //then the origin is at the start of the data + TInt originStart=iCurrentPart.Find(KStartOrigin); + if(originStart==KErrNotFound) + { + //the origin octet will be 0, the data will go in the first chunk + iCurrentChunk=0; + } + else + { + if(originStart != secEnd + 1) + { + CorruptDataL(); + } + TInt originEnd=iCurrentPart.Find(KEndOrigin); + if(originEnd==KErrNotFound || originEnd != iCurrentPart.Length() - 1 ) + { + CorruptDataL(); + } + if(originEnd <= originStart + 1) + { + CorruptDataL(); + } + + TPtrC8 originPtr=iCurrentPart.Mid(originStart+1,originEnd-originStart-1); + TLex8 originToInt(originPtr); + + TInt origin=0; + TInt err = originToInt.Val(origin); + if (err != KErrNone) + { + // Was expecting originPtr to be a number + CorruptDataL(); + } + + //set the chunk number + //if the origin was blank ie. <> then this is set to 0, the start of the data + iCurrentChunk = CalculateChunk(origin); + } + + //now look for the size of the literal + TBool foundPart = GetAndStoreNextPart(); + if(!foundPart) + { + CorruptDataL(); + } + + TInt litStart=iCurrentPart.Find(KStartLiteral); + TInt litEnd=iCurrentPart.Find(KEndLiteral); + + if(litStart==KErrNotFound && litEnd==KErrNotFound) + { + // This may be the data item + ProcessBodyLiteralL(iCurrentPart); + iState = EStateDataItemLine; + iUnexpectedFormat = ETrue; + } + else + { + if(litStart==KErrNotFound || litEnd==KErrNotFound) + { + CorruptDataL(); + } + + if(litEnd <= litStart + 1) + { + CorruptDataL(); + } + + TPtrC8 litPtr=iCurrentPart.Mid(litStart+1,litEnd-litStart-1); + TLex8 litSizeToInt(litPtr); + + TInt err = litSizeToInt.Val(iLiteralSize); + if (err != KErrNone) + { + // Was expecting litPtr to be a number + CorruptDataL(); + } + + if(GetAndStoreNextPart()) + { + ProcessBodyLiteralL(iCurrentPart); + iState = EStateDataItemLine; + iUnexpectedFormat = ETrue; + } + else + { + //now wait for the litereral + iState = EStateBodyLiteral; + } + } + } + +void CImapFetchBody::ProcessBodyLiteralL(const TDesC8& aData) + { + delete iBuf; + iBuf = NULL; + iBuf = aData.AllocL(); + + //now wait for the line that always follows a literal + iState = EStateFetchNextDataItemLine; + } + +/** +Move to the next part +@return whether a part was found +*/ +TBool CImapFetchBody::GetAndStoreNextPart() + { + iCurrentPart.Set(GetNextPart()); + return (iCurrentPart.Length() > 0) ? ETrue : EFalse; + } + +void CImapFetchBody::ProcessFlagsL() + { + iUnparsedData.Set(iMessageFlagInfo.ParseFlagsL(iUnparsedData)); + } + +void CImapFetchBody::ProcessUidL() + { + if (GetAndStoreNextPart()) + { + TInt err = iMessageFlagInfo.SetMessageUid(iCurrentPart); + if (err == KErrNone) + { + iUidDataItemFoundInResponse = ETrue; + } + else + { + // expected iCurrentPart to be a number representing a UID. + // but we did not get a number. + CorruptDataL(); + } + } + } + +void CImapFetchBody::WriteMimeHeadersToCafL() + { + CImapMimeHeaderFields* fields = iFetchBodyResponse.HeaderFields(); + if (fields != NULL) + { + TPtrC8 name; + TPtrC8 value; + + fields->RestartGetNextField(); + while (fields->GetNextField(name, value)) + { + __LOG_FORMAT((iLogId, "Add CAF metadata: %S %S", &name, &value)); + iFetchBodyInfo.Caf()->AddToMetaDataL(name, value); + } + } + } + +void CImapFetchBody::StoreBodyDataL(TBool aExtraFetchRequestCount) + { + // We are going to pass the buffer to the mail store, so set our + // buffer to NULL so that we don't try to delete it if the store + // routine leaves. + HBufC8* buf(iBuf); + iBuf = NULL; + + if(iFetchBodyInfo.IsText()) + { + if(iImapSettings.StorePlainText()) + { + iSendFetch = iImapMailStore.StorePlainBodyTextL(buf,iFetchBodyInfo.PartId(),iCurrentChunk,aExtraFetchRequestCount); + } + else + { + if(iImapSettings.Store8BitData()) + { + iImapMailStore.StoreBodyChunk8L(buf,iFetchBodyInfo.PartId(),iCurrentChunk,aExtraFetchRequestCount); + } + else + { + iImapMailStore.StoreBodyChunk16L(buf,iFetchBodyInfo.PartId(),iCurrentChunk,aExtraFetchRequestCount); + } + } + } + else //attachments + { + iImapMailStore.StoreAttachmentChunkL(buf,iFetchBodyInfo.PartId(),iCurrentChunk); + } + } + +/** +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. +@return void +*/ + + +void CImapFetchBody::SendDataCnfL() + { + ASSERT(iOutstandingRequests>0); + --iOutstandingRequests; + //if we want more requests outstanding then send the next one now + if(iOutstandingRequests>0 && iSendFetch) + { + SendMessageL(); + } + } +/** +This method will enable the FETCH command to be send to the server if it was +disabled by CImapMailStore due to reciept of out-of-order chunks. +@return void +*/ +void CImapFetchBody::EnableSendFetch() + { + iSendFetch = ETrue; + }