diff -r e8c1ea2c6496 -r 8758140453c0 email/email/smtp/src/ImCltCvRecv.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/email/email/smtp/src/ImCltCvRecv.cpp Thu Jan 21 12:53:44 2010 +0000 @@ -0,0 +1,1444 @@ +// 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 the License "Symbian Foundation License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + + + +/** + @file +*/ + +#include +#include + +#include +#include +#include +#include "ImCltCvRecv.h" + +#ifdef __WINS__ +#include +#include +#endif + +#ifndef __WINS__ +#include +#endif +#include +#include +#include + +#ifndef _MSG_NO_LOGGING +#define __IMUT_LOGGING +_LIT(KLogFilePath, "c:\\logs\\mailtext\\in.txt"); +_LIT8(KNewLogHeader, "\r\n------ New Receive Session ------\r\n"); +_LIT8(KFound, "found: "); +_LIT8(KPartLine, "unknown or part line"); +_LIT8(KEndOFHeader, "End of header"); +_LIT8(KSkippingData, "Skipping data"); + +_LIT8(KFoundMIMEBoundary, "MIME boundary"); +_LIT8(KRemoveBoundary, "Remove boundary"); +_LIT8(KRemovedBoundary, "Removed boundary"); +_LIT8(KSectionHeader, "Section header"); +_LIT8(KWritingToFile, "writing attachment"); +_LIT8(KWroteToFile, "wrote attachment"); +_LIT8(KFailedToWriteToFile, "Failed to write to attachment file"); +_LIT8(KFoundUUEStartBoundary, "UUE start boundary"); +_LIT8(KFoundUUEEndBoundary, "UUE end boundary"); +_LIT8(KReset, "Resetting CImRecvConvert"); +_LIT8(KReseted, "Resetting CImRecvConvert"); +_LIT8(KLastToken, "That was the last token"); +_LIT8(KResetForNewEntry, "Reset for a New Entry"); +_LIT8(KResetedForNewEntry, "Reseted for a New Entry"); +_LIT8(KCreatingEntry, "Creating Entry"); +_LIT8(KCreatedEntry, "Created Entry"); +_LIT8(KUpdatingEntry, "Updating Entry"); +_LIT8(KUpdatedEntry, "Updated Entry"); +_LIT8(KMoveToParentEntry, "Moved to parent entry"); +_LIT8(KMovedToParentEntry, "End of Moved to parent entry"); + +_LIT8(KIgnoringStreams, "Discarding streams"); +_LIT8(KStartMessageComplete, "Start Message Complete"); +_LIT8(KMessageComplete, "Message Complete"); +_LIT8(KHeaderComplete, "Message Header complete"); +_LIT8(KReturnReceiptTo, "return-receipt-To is set"); +_LIT8(KStartStoringEntryStream, "Starting Storing Entry Stream"); +_LIT8(KStoringEntryStream, "Storing Entry Stream"); +_LIT8(KDoneStoringEntryStream, "Done Storing Entry Stream"); + +#endif // _MSG_NO_LOGGING + +// uncomment the line below if logging is to be enabled + +#if defined(__IMUT_LOGGING) +#define RECVLOG(text) (iImcvLog?iImcvLog->AppendComment(text):void(0)); +#define RECVLOG_OUT(text) (iImcvLog?iImcvLog->AppendOut(text):void(0)); +#define LOGGING(string1, string2) (Logging(string1, string2)); +#else +#define RECVLOG(text) (void(0)); +#define RECVLOG_OUT(text) (void(0)); +#define LOGGING(string1, string2) (void(0)); +#endif + + +const TInt KBodyTextChunkSizeBytes = 512; + + +/** +NewLC() +Static factory constructor. Uses two phase construction +and pushes the newly created object into the Cleanup stack. + +@param anFs +@param aClientEntry +@param aMsgType +@param aEmailServiceId +@return +*/ + CImCltRecvConvert* CImCltRecvConvert::NewLC(RFs& anFs,CMsvEntry* aClientEntry,TUid aMsgType,TMsvId aEmailServiceId) + { + CImCltRecvConvert* self = new (ELeave) CImCltRecvConvert(anFs,aClientEntry,aMsgType,aEmailServiceId); + CleanupStack::PushL(self); + self->ConstructL(anFs); + return self; + } + + +/** +NewL() +Static factory constructor. Uses two phase construction. + +@param anFs +@param aClientEntry +@param aMsgType +@param aEmailServiceId +@return +*/ + CImCltRecvConvert* CImCltRecvConvert::NewL(RFs& anFs,CMsvEntry* aClientEntry,TUid aMsgType,TMsvId aEmailServiceId) + { + CImCltRecvConvert* self = CImCltRecvConvert::NewLC(anFs,aClientEntry,aMsgType,aEmailServiceId); + CleanupStack::Pop(); + return self; + } + + +/** +ConstructL() + +@param anFs +*/ +void CImCltRecvConvert::ConstructL(RFs& anFs) + { + iFsSession = &anFs; + + RResourceFile resFile; + OpenResourceFileL(resFile, anFs); // NB leaves if file not found + + // make sure the resource file will be closed if anything goes wrong + // CloseResourceFile is declared in IMUTDLL.H and defined in IMUTDLL.CPP + TCleanupItem close( CloseResourceFile, &resFile ); + CleanupStack::PushL( close ); + + // Read iStore8BitData flag. + HBufC8* buf = resFile.AllocReadLC(STORE_8BIT_BODY_TEXT); + TResourceReader reader; + reader.SetBuffer(buf); + iStore8BitData = reader.ReadInt8(); + CleanupStack::PopAndDestroy(buf); + + buf = resFile.AllocReadLC(REMOVED_ATTACHMENT_TAG); + reader.SetBuffer(buf); + iRemovedAttachmentTag = reader.ReadTPtrC().AllocL(); + CleanupStack::PopAndDestroy(buf); + + buf = resFile.AllocReadLC(DEFAULT_ATTACHMENT_NAME); + reader.SetBuffer(buf); + iDefaultAttachmentName = reader.ReadTPtrC().AllocL(); + CleanupStack::PopAndDestroy(buf); + buf = resFile.AllocReadLC(PARTIAL_DOWNLOAD_FOOTER_MESSAGE); + reader.SetBuffer(buf); + iPartialEmailFooter = (reader.ReadTPtrC()).AllocL(); + CleanupStack::PopAndDestroy(buf); + buf = NULL; + CleanupStack::PopAndDestroy(&resFile); + + // create CImHeader object to store Rfc822 header info... + iOutputHeader = CImHeader::NewLC(); + CleanupStack::Pop(); + + if (iStore8BitData) + { + //Create body text storage helper. + iBodyText = CMsvBodyText::NewL(); + } + else + { + // create CRichText object to store body... + iParaLayer = CParaFormatLayer::NewL(); + iCharLayer = CCharFormatLayer::NewL(); + iOutputBody = CRichText::NewL(iParaLayer, iCharLayer); + } + + // Create Rfc822 filter object... + iRfc822Token = CLocalRfc822Token::NewLC(); + CleanupStack::Pop(); + iRfc822Token->SetImRecvConvert(this); + + // Create converter objects... + iCharacterConverter = CCnvCharacterSetConverter::NewL(); + iCharConv = CImConvertCharconv::NewL(*iCharacterConverter, anFs); + iHeaderConverter = CImConvertHeader::NewL(*iCharConv); + + + // Create MIME filter object... + iMimeParser = CLocalMimeParser::NewL(*this); + + + // logfile stuff + iImcvLog=NULL; + +#ifdef __IMUT_LOGGING + TRAP_IGNORE(iImcvLog=CImLog::NewL(KLogFilePath, EAppend)); +#endif + + iRootEntryId = EntryId(); + + iNotFinishedRfc822Header = ETrue; + + iEmailEntry = new (ELeave) TMsvEmailEntry; + iReceivingHeadersOnly=EFalse; + + iParent = new (ELeave) CArrayFixFlat(3); + + iFirstBoundaryReached=EFalse; + + ResetL(); + + RECVLOG( KNewLogHeader ) + } + + +/** +CImCltRecvConvert() + +@param anFs +@param aClientEntry +@param aMsgType +@param aEmailServiceId +*/ + +CImCltRecvConvert::CImCltRecvConvert(RFs& anFs,CMsvEntry* aClientEntry,TUid aMsgType,TMsvId aEmailServiceId) + : CLocalImRecvConvert(anFs,iNullServerEntry,aMsgType,aEmailServiceId), + iClientEntry(aClientEntry) + { + __DECLARE_NAME(_S("CImCltRecvConvert")); + } + + +/** +~CImCltRecvConvert() +Destructor +*/ +CImCltRecvConvert::~CImCltRecvConvert() + { + } + + +/** +ResetForHeadersL() +*/ + void CImCltRecvConvert::ResetForHeadersL() + { + // This function is used in preference to ResetL() when the owner + // only wishes to create email entries in the remote mailbox - + // they do not wish to create any stores associated with the message + // entry + ResetL(); + iReceivingHeadersOnly = ETrue; + } + + +/** +ResetL() +*/ + void CImCltRecvConvert::ResetL() + { + RECVLOG(KReset) + + iBodyId=KMsvNullIndexEntryId; + iSizeOfAttachmentsRemoved=0; + iClientEntry->SetEntryL(iRootEntryId); + + iReceivingHeadersOnly=EFalse; + iMessageEntryCalled=EFalse; + iLeaveError=KErrNone; + iCurrentMultipartFolderEntryId=0; + + TParentDetails parent; + parent.iAttachment=parent.iMHTML=EFalse; + parent.iSize=0; + iParent->InsertL(0,parent); + + if(iEmailEntry) + { + delete iEmailEntry; + iEmailEntry=NULL; + } + iEmailEntry = new (ELeave) TMsvEmailEntry; + + // "iSavingAttachments" commands this code to store attachments in files. + // Currently this is always set to ETrue as we intend to save all attachments + // However, if the user wishes to discard (ie do not save) any + // attachments in incoming email messages - then this member variable + // may be set to EFalse by the inline accessor function "SaveAllAttachments(TBool)" + iSavingAttachments=ETrue; + iAttachmentFileState=EFileIsClosed; + + // iLeaveError contains the error value of any functions that leaves (ie CRichText::InsertL) + // or any returned error value that generates a leave from within CImRecvConvert (ie RFile::Create) + + iGlobalIndent=0; + iLongestLine=50; + + iImPriority=EMsvMediumPriority; + if(NULL!=iImcvUtils) + { + delete iImcvUtils; + iImcvUtils=NULL; + } + iImcvUtils=CImcvUtils::NewL(); + + // reset internal date + iTimeDate.HomeTime(); + + iMimeParser->Reset(); + + iNewEntry=EFalse; //EFalse if the entry was moved to. ETrue if the entry was just created + iTopMessagePart=KMsvRootIndexEntryId; + ResetForNewEntryL(iDefaultEntryType); + iMIMEPart_822Header = EFalse; + iPartialEmail=EFalse; + + RECVLOG(KReseted) + } + + +/** +ParseNextFieldL() + +@param aSourceLine +@return +*/ + TInt CImCltRecvConvert::ParseNextFieldL(const TDesC8& aSourceLine) + { + __ASSERT_DEBUG(iRootEntryId!=KMsvRootIndexEntryId, gPanic(KPanicServiceIdNotValid)); + RECVLOG_OUT(aSourceLine); + + if ((iLeaveError == KErrNone) && (iClientEntry->Entry().Id() == KMsvRootIndexEntryId)) + { + iClientEntry->SetEntryL(iSavedEntryId); + } + + if(iLeaveError==KErrNone) + { + TRAP(iLeaveError, ParseNextLineL(aSourceLine)); + } + + if (iLeaveError==KErrNone) + iSavedEntryId = iClientEntry->Entry().Id(); + TUid type = iClientEntry->Entry().iType; + if( type != KUidMsvMessageEntry && + type != KUidMsvEmailTextEntry && + type != KUidMsvEmailHtmlEntry && + type != KUidMsvAttachmentEntry) + { + iClientEntry->SetEntryL(KMsvRootIndexEntryId); + } + + + return iLeaveError; + } + + +/** +ParseNextLineL() + +@param aSourceLine +*/ +void CImCltRecvConvert::ParseNextLineL(const TDesC8& aSourceLine) + { + iParsedMimeBoundaryLast=0; + if(!iFinishedHeader) + { + // start by getting the next token from the header + iRfc822Token->ParseNextLineL(aSourceLine); + + switch(iRfc822Token->iHeaderPart) + { + case CLocalRfc822Token::EUnknown: + case CLocalRfc822Token::ENotFinished: + RECVLOG(KPartLine) + break; + case CLocalRfc822Token::EFrom: + iOutputHeader->SetFromL(*iRfc822Token->OutputLine()); + LOGGING(KFound,KImcvFromPrompt); + break; + case CLocalRfc822Token::EReplyTo: + iOutputHeader->SetReplyToL(*iRfc822Token->OutputLine()); + LOGGING(KFound,KImcvReplyToPrompt); + break; + case CLocalRfc822Token::ETo: + ParseRecipientListL(iOutputHeader->ToRecipients()); + LOGGING(KFound,KImcvToPrompt); + break; + case CLocalRfc822Token::ECc: + ParseRecipientListL(iOutputHeader->CcRecipients()); + LOGGING(KFound,KImcvCcPrompt); + break; + case CLocalRfc822Token::EBcc: + ParseRecipientListL(iOutputHeader->BccRecipients()); + LOGGING(KFound,KImcvBccPrompt); + break; + case CLocalRfc822Token::ESubject: + iOutputHeader->SetSubjectL(*iRfc822Token->OutputLine()); + LOGGING(KFound,KImcvSubjectPrompt); + break; + case CLocalRfc822Token::EDate: + iRfc822Date.ParseDateField(*iRfc822Token->OutputLine() , iTimeDate); + if (iEmailEntry->Id() != iTopMessagePart) + { + iEmailEntry->iDate = iTimeDate; + } + LOGGING(KFound,KImcvDatePrompt); + break; + case CLocalRfc822Token::EMessageId: + iOutputHeader->SetImMsgIdL(*iRfc822Token->OutputLine()); + LOGGING(KFound,KImcvMessageIdPrompt); + break; + case CLocalRfc822Token::EPriority: + iImPriority=iImcvUtils->EvaluatePriorityText(*iRfc822Token->OutputLine()); + LOGGING(KFound,KImcvPriorityPrompt); + break; + case CLocalRfc822Token::EReturnReceiptTo: + iOutputHeader->SetReceiptAddressL(*iRfc822Token->OutputLine()); + LOGGING(KFound,KReturnReceiptTo); + break; + case CLocalRfc822Token::EEndOfHeader: + // the next line goes in the body part + iFinishedHeader = ETrue; + RECVLOG(KEndOFHeader) + break; + default: + RECVLOG(KEndOFHeader) + break; + } + + + if(iRfc822Token->iHeaderPart != CLocalRfc822Token::ENotFinished) + { + // Now that we've used the data, we also need to clear the output line from the tokeniser.... + iRfc822Token->OutputLine()->Des() = KNullDesC8; + + // whatever part we just read, we may also have read the empty line that separates + // the header from the body + if((iFinishedHeader = iRfc822Token->LastToken()) != EFalse) //iFinishedHeader set to 1 on CRLF- + { + RECVLOG(KLastToken); + iNotFinishedRfc822Header = EFalse; + + iHeaderConverter->SetMessageType(iMimeParser->MessageIsMime()); + iHeaderConverter->DecodeAllHeaderFieldsL(*iOutputHeader); + + if (iMimeParser->MessageIsMime()) + { + EndOfHeaderMIMEProcessingL(); + } + else + { + EndOfHeaderProcessingL(); + } + + if (iStore8BitData) + { + iBodyText->SetDefaultCharacterSet(iCharConv->SystemDefaultCharset()); + if ( iMimeParser->MessageIsMime() && iMimeParser->ContentType()==EMimeText ) + { + iBodyText->SetCharacterSet(iMimeParser->CurrentCharsetL()); + } + else + { + iBodyText->SetCharacterSet(0); + } + } + else + { + // Get charset for decoding. + if ( iMimeParser->MessageIsMime() && iMimeParser->ContentType()==EMimeText ) + { + iCharConv->PrepareToConvertToFromOurCharsetL(iMimeParser->CurrentCharsetL()); + } + else + { + iCharConv->PrepareToConvertToFromOurCharsetL(iCharConv->SystemDefaultCharset()); + } + } + } + } + } + else if (iReceivingHeadersOnly==EFalse) + { + //Set to EFalse when a single line is to be skipped (ie boundary line) + iCommitLine=ETrue; + + // read one line of the message body if I am processing a whole email message + if(iMimeParser->MessageIsMime()) + { + ParseMimeLineL(aSourceLine); + } + else + { + ParseBodyLineL(aSourceLine); + } + + if((iCommitLine)&&(!iSkipData)) + { + DecodeAndStoreLineL(aSourceLine); + } + } + } + + +/** +MessageEntryDetailsL() + +@return +*/ + TMsvEmailEntry CImCltRecvConvert::MessageEntryDetailsL() + { + + iMessageEntryCalled=ETrue; + CloseAttachmentFileL(); + + // A message requiring manual termination and not part way through a MIME part header + if( iTopMessagePart==EntryId() && iFinishedHeader) + { + StoreEntryStreamsL(KStore822Header|KStoreMIMEHeader); + } + else + { + iClientEntry->SetEntryL(iTopMessagePart); + if(iEmailEntry) + { + delete iEmailEntry; + iEmailEntry=NULL; + } + + iEmailEntry = new (ELeave) TMsvEmailEntry(iClientEntry->Entry()); + } + + return *iEmailEntry; + } + + +/** +MessageCompleteL() + +@param aEmailEntry +*/ + void CImCltRecvConvert::MessageCompleteL(TMsvEmailEntry aEmailEntry) + { + if (iClientEntry->Entry().Id() == KMsvRootIndexEntryId) + { + iClientEntry->SetEntryL(iSavedEntryId); + } + + __ASSERT_DEBUG(iMessageEntryCalled, gPanic(KPanicMessageEntryNotCalled)); + __ASSERT_DEBUG(aEmailEntry.Id()==iTopMessagePart, gPanic(KPanicMessageEntryIdHasChanged)); + + // Called ResetL() to reset object instead of ResetForHeadersL() + __ASSERT_DEBUG(iReceivingHeadersOnly, gPanic(KPanicIncorrectResetState)); + + if(iEmailEntry) + { + if (iEmailEntry->Id()) + { + if(iLeaveError==KErrNone) + { + // a remote email header cannot have any attachments or be marked as complete... + aEmailEntry.SetAttachment(EFalse); + aEmailEntry.SetMHTMLEmail(EFalse); + aEmailEntry.SetComplete(EFalse); + iClientEntry->SetEntryL(aEmailEntry.Id()); + RECVLOG(KHeaderComplete) + } + else + { + if (!iPopulateMessage) + { + TMsvId currentId = EntryId(); + iClientEntry->SetEntryL(iClientEntry->Entry().Parent()); + iClientEntry->DeleteL(currentId); + } + User::Leave(iLeaveError); + } + } + } + + iSavedEntryId = iClientEntry->Entry().Id(); + iClientEntry->SetEntryL(KMsvRootIndexEntryId); + } + + +/** +MessageCompleteL() + +@return +*/ + TMsvId CImCltRecvConvert::MessageCompleteL() + { + RECVLOG(KStartMessageComplete) + if (iClientEntry->Entry().Id() == KMsvRootIndexEntryId) + { + iClientEntry->SetEntryL(iSavedEntryId); + } + if (iParsedMimeBoundaryLast==EFalse && iAttachmentFileState==EFileIsOpen && iPartialEmail!=EFalse) + { + iAttachmentFileState=EFileTopIncomplete; + } + + CloseAttachmentFileL(); + + if(!iEmailEntry->Id()) + { + return 0; + } + + if(iLeaveError!=KErrNone) + { + User::Leave(iLeaveError); + } + + if (EntryId()!=iTopMessagePart) + { + iEmailEntry->SetComplete(ETrue); + StoreEntryStreamsL(KStoreBodyText); + MoveToParentEntryL(); + + if( iTopMessagePart==EntryId() && iFinishedHeader) + { + iEmailEntry->SetVisible(ETrue); + iEmailEntry->SetInPreparation(EFalse); + iEmailEntry->SetBodyTextComplete(ETrue); + iEmailEntry->SetComplete(ETrue); + iEmailEntry->SetSendingState(KMsvSendStateWaiting); + // Main message. + StoreMessageEntryDetailsL(); + return iEmailEntry->Id(); + } + else if(iEmailEntry->iType == KUidMsvMessageEntry) + { + StoreMessageEntryDetailsL(); + MoveToParentEntryL(); + StoreMessageEntryDetailsL(); + } + } + + iClientEntry->SetEntryL(iTopMessagePart); + if(NULL!=iEmailEntry) + { + delete iEmailEntry; + iEmailEntry=NULL; + } + iEmailEntry = new (ELeave) TMsvEmailEntry(iClientEntry->Entry()); + iEmailEntry->SetVisible(ETrue); + iEmailEntry->SetInPreparation(EFalse); + iEmailEntry->SetComplete(ETrue); + iEmailEntry->SetBodyTextComplete(ETrue); + + iEmailEntry->SetSendingState(KMsvSendStateWaiting); + + + iEmailEntry->SetAttachment(iParent->At(0).iAttachment); + iEmailEntry->SetMHTMLEmail(iParent->At(0).iMHTML); + + if(iEmailEntry->MHTMLEmail() == EFalse && iEmailEntry->Attachment() == EFalse && iRelatedAttachments !=EFalse) + { + iEmailEntry->SetAttachment(ETrue); + } + iRelatedAttachments=EFalse; + + iEmailEntry->iSize=iParent->At(0).iSize; + iEmailEntry->SetMessageFolderType(iParent->At(0).iFolder); + + iClientEntry->ChangeL(*iEmailEntry); + + iSavedEntryId = iClientEntry->Entry().Id(); + iClientEntry->SetEntryL(KMsvRootIndexEntryId); + RECVLOG(KMessageComplete) + return iEmailEntry->Id(); + } + + + /** +ParseMimeLineL() + +@param aSourceLine +*/ +void CImCltRecvConvert::ParseMimeLineL(const TDesC8& aSourceLine) + { + iTopPartialDownloadCounter+=aSourceLine.Length(); // increment the number of bytes of the attachment downloaded so far + if(!iMimeParser->IsBoundary(aSourceLine)) + { + if(!iPrepared) // first line of the body + { + if (iMIMEPart_822Header) + { + // missing 822 part header. Revert to default. + EndOfHeaderMIMEProcessingL(); + iMIMEPart_822Header=EFalse; + } + + PrepareDecoder(); + } + + if (CheckUUEStartL(aSourceLine)) + { + iAlgorithm=EUUDecode; + iCommitLine=EFalse; + } + } + else + { + iParsedMimeBoundaryLast=ETrue; + // found a MIME boundary so store the current parts data and update its entry. + + RECVLOG(KFoundMIMEBoundary) + iCommitLine=EFalse; //Dont store this line as its a boundary. + + if(!iFirstBoundaryReached && iEntryType==EFolderEntry) + { + iFirstBoundaryReached=ETrue; + if (!iCurrentMultipartFolderEntryId) + iCurrentMultipartFolderEntryId = EntryId(); + MoveToParentEntryL(); + ResetForNewEntryL(iDefaultEntryType); + return; // First boundary encountered. + } + + CloseAttachmentFileL(); + if(iNewEntry) + { + iEmailEntry->SetComplete(ETrue); + iEmailEntry->SetBodyTextComplete(ETrue); + StoreEntryStreamsL(KStoreMIMEHeader | KStoreBodyText); + if (iBodyId==KMsvNullIndexEntryId) + { + iBodyId=iEmailEntry->Id(); + } + } + + iSkipData = EFalse; + + // check whether we just found the terminating boundary... + if(iMimeParser->IsTerminatingBoundary()) + { + RECVLOG(KRemoveBoundary); + iMimeParser->RemoveBoundary(); + RECVLOG(KRemovedBoundary); + iMIMEPart_822Header = EFalse; + + if (EntryId()!=iTopMessagePart) + { + if(iEmailPart==KParentPart) + { + // rfc822 message which is not not multipart. + iEmailPart=KNoPart; + MoveToParentEntryL(); + + // Embedded message + iEmailEntry->SetComplete(ETrue); + iEmailEntry->SetBodyTextComplete(ETrue); + StoreMessageEntryDetailsL(); + } + else if (iEmailEntry->iType==KUidMsvMessageEntry) + { + // Moving up from a multi embedded rfc822 message. + iEmailEntry->SetComplete(ETrue); + iEmailEntry->SetBodyTextComplete(ETrue); + StoreMessageEntryDetailsL(); + } + } + + MoveToParentEntryL(); + iEntryDataSize = iEmailEntry->iSize; + + if(iClientEntry->Entry().iType == KUidMsvFolderEntry) + { + iCurrentMultipartFolderEntryId = EntryId(); + } + else if (EntryId()!=iTopMessagePart) + { + if(iEmailEntry->iType == KUidMsvMessageEntry) + { + iEmailEntry->SetComplete(ETrue); + iEmailEntry->SetBodyTextComplete(ETrue); + StoreMessageEntryDetailsL(); + } + MoveToParentEntryL(); + iEntryDataSize += iEmailEntry->iSize; + } + + if(!iNewEntry) + ResetForNonMimeEntryL(); + + RECVLOG(KSkippingData) + iSkipData = ETrue; + iDefaultEntryType=ETextEntry; + } + else // if regular boundary + { + RECVLOG(KSectionHeader) + if(iEmailPart==KParentPart && EntryId()!=iTopMessagePart) + { + // rfc822 message which is not not multipart. + iEmailPart=KNoPart; + MoveToParentEntryL(); + // Embedded message + iEmailEntry->SetComplete(ETrue); + iEmailEntry->SetBodyTextComplete(ETrue); + StoreMessageEntryDetailsL(); + } + + if (!iCurrentMultipartFolderEntryId && iEmailPart==KNoPart) + MoveToParentEntryL(); + + ResetForNewEntryL(iDefaultEntryType); + } + } + } + + +/** +EndOfHeaderProcessingL() +*/ +void CImCltRecvConvert::EndOfHeaderProcessingL() + { + CreateEntryL(); + StoreEntryStreamsL(KStore822Header); + iEntryDataSize = 0; + } + + +/** +ParseBodyLineL() + +@param aSourceLine +*/ +void CImCltRecvConvert::ParseBodyLineL(const TDesC8& aSourceLine) + { + TInt len=aSourceLine.Length(); + iTopPartialDownloadCounter+=len; // added for TOP. increment the number of bytes of the attachment downloaded so far + + if (iBodyId==KMsvNullIndexEntryId) + { + iBodyId=iEmailEntry->Id(); + } + + TMsvId id=0; + // first check whether this line is a UUEncode start boundary + if(CheckUUEStartL(aSourceLine)) + { + RECVLOG(KFoundUUEStartBoundary) + TFileName tempStore = iAttachmentName; + id = EntryId(); + if (!iNewNonMIMEBodyPart || id!=iTopMessagePart) // main message entry + { + iEmailEntry->SetComplete(ETrue); + iEmailEntry->SetBodyTextComplete(ETrue); + StoreEntryStreamsL(KStoreBodyText); + } + MoveToParentEntryL(); + if ( !CreateNonMIMEFolderEntryL(id)) + { + ResetForNonMimeEntryL(); + } + + iEntryType = EAttachmentEntry; + CreateEntryL(); + SetAttachmentName(tempStore); + + iCurrentPartIsRichText = EFalse; + iAlgorithm=EUUDecode; + iCommitLine=EFalse; + if(!iSavingAttachments) + { + RECVLOG(KSkippingData) + iSkipData=ETrue; + } + iNewNonMIMEBodyPart=EFalse; + } + else if(aSourceLine.CompareF(KImcvUueEnd)==0) // Checks for the UUEncode end boundary + { + RECVLOG(KFoundUUEEndBoundary) + CloseAttachmentFileL(); + StoreEntryDataL(); + MoveToParentEntryL(); + iSkipData = EFalse; + iCommitLine=EFalse; + iNewNonMIMEBodyPart=ETrue; + } + else if (iNewNonMIMEBodyPart && !( len==2 && aSourceLine[0]==KImcvCR && aSourceLine[1]==KImcvLF )) + { + id = EntryId(); + if (!iNewNonMIMEBodyPart || id!=iTopMessagePart) + { + iEmailEntry->SetComplete(ETrue); + iEmailEntry->SetBodyTextComplete(ETrue); + StoreEntryStreamsL(KStoreBodyText); + } + MoveToParentEntryL(); + if ( !CreateNonMIMEFolderEntryL(id)) + ResetForNonMimeEntryL(); + iAlgorithm=ENoAlgorithm; + iEntryType = ETextEntry; + CreateEntryL(); + iNewNonMIMEBodyPart=EFalse; + } + } + + +/** +CreateNonMIMEFolderEntryL() + +@param aCurrentId +@return +*/ +TBool CImCltRecvConvert::CreateNonMIMEFolderEntryL(TMsvId aCurrentId) + { + if ( aCurrentId==iTopMessagePart || iCurrentMultipartFolderEntryId ) + return EFalse; + + iClientEntry->SetEntryL(iTopMessagePart); + iEmailPart = KMultiPart; + iEntryType = EFolderEntry; + CreateEntryL(); + + TMsvId destId = EntryId(); + iClientEntry->SetEntryL(iTopMessagePart); + iClientEntry->MoveL(aCurrentId, destId); + iClientEntry->SetEntryL(aCurrentId); + iClientEntry->SetEntryL(iClientEntry->Entry().Parent()); + + iEmailEntry->SetMessageFolderType(iMimeParser->MessageFolderType()); + + RECVLOG(KResetForNewEntry) + + iMimeParser->ResetForNewEntry(); + + if (iStore8BitData) + { + //Create a buffer to hold the body text as it is down loaded. + delete iBodyBuf; + iBodyBuf = NULL; + iBodyBuf = CBufFlat::NewL(KBodyTextChunkSizeBytes); + } + else + { + iOutputBody->Reset(); + } + + ResetForNonMimeEntryL(); + RECVLOG(KResetedForNewEntry) + return ETrue; + } + + +/** +CreateAttachmentL() + +@return +*/ +TBool CImCltRecvConvert::CreateAttachmentL() + { + // added to support TOP command. Reset the download counter each time we have a new + // attachment + iTopPartialDownloadCounter = 0; + + // Need to check that the complete filename: iAttachmentFullPath & iAttachmentName + // does not exceed 256 characters. Greater than this and it cannot be saved as a file. + + TBool addExtension = ETrue; + if(iAttachmentName.Length() == 0) //i.e. problem with Attachment name + { + // No filename present. Generate one. + if(iMimeParser->ContentDescription().Length()!=0) + { + // Use ContentDescription() as default name + // - as this is more informative than the default + + TLex sourceLineLex = iMimeParser->ContentDescription(); + ExtractFilename(sourceLineLex, iAttachmentName); + } + else + { + iAttachmentName = *iDefaultAttachmentName; + } + + } + else + { + // Filename present. Check it is valid. + ReplaceInvalidCharacters(iAttachmentName); + if (iAttachmentName.Locate(KImcvFullStop)!=KErrNotFound) + { + addExtension=EFalse; + } + + } + if (addExtension) + { + AddFileExtension(); + } + CMsvStore* store = iClientEntry->EditStoreL(); + CleanupStack::PushL(store); + CMsvAttachment* attachment = CMsvAttachment::NewL(CMsvAttachment::EMsvFile); + CleanupStack::PushL(attachment); + attachment->SetAttachmentNameL(iAttachmentName); + + RFile file; + store->AttachmentManagerExtensionsL().CreateAttachmentL(iAttachmentName,file,attachment); + CleanupStack::Pop(attachment); + + iAttachmentFile.SetFileHandle(file,TImAttachmentFile::EImFileWrite); + store->CommitL(); + CleanupStack::PopAndDestroy(store); // store + + if(KErrNone!=iLeaveError) + { + iAttachmentFileState=EFileFailedToOpen; + CloseAttachmentFileL(); + return EFalse; + } + + iAttachmentFileState=EFileIsOpen; + return ETrue; + } + + +/** +WriteToAttachmentL() + +@param text +*/ +void CImCltRecvConvert::WriteToAttachmentL(const TDesC8& text) + { + if ( (iAttachmentFileState==EFileIsClosed || iAttachmentFileState==EFileNotOpen) + && CreateAttachmentL() && iEntryType!=EHtmlEntry) + iEmailEntry->SetAttachment(ETrue); + + if(iAttachmentFileState!=EFileIsOpen || !text.Length()) + { + RECVLOG(KSkippingData) + iSkipData = ETrue; + } + + // write decoded data into a file if there is any data there to write. + + RECVLOG(KWritingToFile) + + // Convert text before writing to attachment. + + // Store as Binary files.. + iLeaveError=iAttachmentFile.WriteFile(text); + + if(KErrNone==iLeaveError) + { + iEntryDataSize += text.Length(); + } + + else + { + // the file write failed (eg.there is no space left), set new file state and skip + RECVLOG(KFailedToWriteToFile) + iAttachmentFileState=EFileIsIncomplete; + CloseAttachmentFileL(); + } + RECVLOG(KWroteToFile) + } + + +/** +StoreEntryStreamsL() +*/ +void CImCltRecvConvert::StoreEntryStreamsL() + { + StoreEntryStreamsL(KStoreBodyText | KStore822Header | KStoreMIMEHeader); + } + + + +/** +StoreEntryStreamsL() + +@param aSettings +*/ +void CImCltRecvConvert::StoreEntryStreamsL(TInt aSettings) + { + RECVLOG(KStartStoringEntryStream); + if (iReceivingHeadersOnly==EFalse) + { + CMsvStore* entryStore = NULL; + TBool commitStore = EFalse; + + TRAPD(error, entryStore = iClientEntry->EditStoreL()); + if(error==KErrNone) // if store does not exist then the entry is the wrong type + { + CleanupStack::PushL(entryStore); + + if (aSettings & KStore822Header) + { + Store822HeaderL(*entryStore, commitStore); + } + + if (aSettings & KStoreMIMEHeader) + { + StoreMIMEHeaderL(*entryStore, commitStore); + } + + if (aSettings & KStoreBodyText) + { + StoreBodyTextL(*entryStore, commitStore); + } + // only commit to the store if I wrote something into it + if (commitStore) + { + RECVLOG(KStoringEntryStream); + entryStore->CommitL(); + } + + StoreEntryDataL(); + CleanupStack::PopAndDestroy(); //entryStore + } + + } + RECVLOG(KDoneStoringEntryStream); + } + + +/** +StoreEntryDataL() + +@return +*/ +TBool CImCltRecvConvert::StoreEntryDataL() + { + // NB function should only be called if a whole email is being processed + TBool commit=EFalse; + RECVLOG(KUpdatingEntry) + + if (iEmailEntry->iType==KUidMsvMessageEntry) + { + iParent->At(0).iSize += iEntryDataSize; + } + else + { + iEmailEntry->iSize += iEntryDataSize; + if (iEntryType==EAttachmentEntry || iEntryType==EHtmlEntry) + { + iEmailEntry->iDetails.Set(iAttachmentName); + } + } + iClientEntry->ChangeL(*iEmailEntry); + + RECVLOG(KUpdatedEntry) + return commit; // if I wrote data into the store, tell owner + } + + +/** +MoveToParentEntryL() +*/ +void CImCltRecvConvert::MoveToParentEntryL() + { + // This function changes the context to the current entry's parent entry. + RECVLOG(KMoveToParentEntry) + + // Change context to the parent entry + if (EntryId()==iTopMessagePart) + { + return; // Already there. + } + + iClientEntry->SetEntryL(iClientEntry->Entry().Parent()); + + iNewEntry = EFalse; + + // only read and write to store if this is a real email message; headers stored in + // the remote mailbox do not require any store information. + if (iReceivingHeadersOnly) + { + RECVLOG(KIgnoringStreams) + return; + } + + TBool allowAttachmentFlag=ETrue; + if(iClientEntry->Entry().iType == KUidMsvFolderEntry) + { + // Current entry is a folder entry signifying a MIME multipart. + // Change context to the parent entry + TMsvEmailEntry entry = (TMsvEmailEntry) iClientEntry->Entry(); + iCurrentMultipartFolderEntryId = EntryId(); + allowAttachmentFlag = !(entry.MessageFolderType()==EFolderTypeRelated || + entry.MessageFolderType()==EFolderTypeAlternative); + + + if (EntryId()!=iTopMessagePart) + { + iClientEntry->SetEntryL(iClientEntry->Entry().Parent()); + } + } + + TBool childIsAttachment = (iEmailEntry->Attachment() || iEmailEntry->iType == KUidMsvMessageEntry) ? ETrue:EFalse; + TBool childIsMHTML=EFalse; + // Dont want the flag propogated 'up' past a message entry. + if(iEmailEntry->iType != KUidMsvMessageEntry) + { + childIsMHTML = iEmailEntry->MHTMLEmail() ? ETrue:EFalse; + } + //Make the parent entry the current entry + if(iEmailEntry) + { + delete iEmailEntry; + iEmailEntry=NULL; + } + iEmailEntry = new (ELeave) TMsvEmailEntry(iClientEntry->Entry()); + + if (!iParent->Count()) + { + TParentDetails parentDetails; + iParent->InsertL(0,parentDetails); + } + + if (! iParent->At(0).iAttachment) + { + iParent->At(0).iAttachment=(childIsAttachment && allowAttachmentFlag)? ETrue:EFalse; + + // if we aren't allowing attachments because of the folder type + // remember there where attachments and check at the end whether + // it was an MHTML message or not. + if(childIsAttachment && !allowAttachmentFlag) + { + iRelatedAttachments=ETrue; + } + } + if (!iParent->At(0).iMHTML) + { + iParent->At(0).iMHTML = childIsMHTML ? ETrue:EFalse; + } + iParent->At(0).iSize += iEntryDataSize; + + iOutputHeader->Reset(); + iEmptyHeaderSize=iOutputHeader->DataSize(); + iMimeParser->ResetForNewEntry(); + + iEntryDataSize=0; + + RECVLOG(KMovedToParentEntry) + } + + +/** +CreateEntryL() +Creates a new entry. +*/ +void CImCltRecvConvert::CreateEntryL() + { + RECVLOG(KCreatingEntry); + if(NULL!=iEmailEntry) + { + delete iEmailEntry; + iEmailEntry=NULL; + } + + if (iCurrentMultipartFolderEntryId) + { + iClientEntry->SetEntryL(iCurrentMultipartFolderEntryId); + iCurrentMultipartFolderEntryId=0; + } + + iEmailEntry = new (ELeave) TMsvEmailEntry; + + TValidEntryType previousEntryType = iEntryType; + if ((iTopMessagePart==KMsvRootIndexEntryId) || iMIMEPart_822Header) + { + // At the main header, want to create a message entry. + // The stored iEntryType will indicate ( from header info) the next entry to be created. + // Save temporarily. + // Also applies to the special case where a message contains ony 1 embedded message. + + previousEntryType=iEntryType; + iEntryType=EMessageEntry; + } + + if ((iPopulateMessage) && (iTopMessagePart==KMsvRootIndexEntryId)) + // If this is the root of a message that is being populated then do not create it. + { + iClientEntry->SetEntryL(iRootEntryId); + *iEmailEntry = iClientEntry->Entry(); + iTopMessagePart=iRootEntryId; + + // Delete all the children of the message entry. This is needed because if the + // message has been purged, the entries will still exist. When the message is populated, + // new entries are created. If the original entries are not removed, then duplicate + // entries will exist. + CMsvEntrySelection* children = iClientEntry->ChildrenL(); + CleanupStack::PushL(children); + if (children->Count()) + { + TMsvLocalOperationProgress prog; + iClientEntry->DeleteL(*children,prog); + } + CleanupStack::PopAndDestroy(children); + } + else + { + iEmailEntry->iMtm=iNewMsgType; + iEmailEntry->iServiceId = iEmailServiceId; + iEmailEntry->SetComplete(EFalse); + iEmailEntry->iSize = 0; + iEmailEntry->SetVisible(ETrue); + iEmailEntry->SetInPreparation(EFalse); + iEmailEntry->SetReceipt(EFalse); + + iEmailEntry->SetVCard(iMimeParser->VCard()); + iEmailEntry->SetVCalendar(iMimeParser->VCalendar()); + iEmailEntry->SetMessageFolderType(iMimeParser->MessageFolderType()); + iEmailEntry->SetPriority(iImPriority); + iEmailEntry->SetNew(EFalse); + + if(iOutputHeader->ReceiptAddress().Length()>0) + { + iEmailEntry->SetReceipt(ETrue); + } + + iEmailEntry->iDate=iTimeDate; + switch(iEntryType) + { + case EMessageEntry: + if(iTopMessagePart==KMsvRootIndexEntryId) + { + iEmailEntry->SetUnread(ETrue); + iEmailEntry->SetNew(ETrue); + iEmailEntry->SetVisible(EFalse); + iEmailEntry->SetInPreparation(ETrue); + iEmailEntry->SetSendingState(KMsvSendStateNotApplicable); + } + else + { + TParentDetails parentDetails; + parentDetails.iMHTML=EFalse; + parentDetails.iAttachment=EFalse; + parentDetails.iSize=0; + iParent->InsertL(0,parentDetails); + } + iEmailEntry->iType=KUidMsvMessageEntry; + iEmailEntry->iDetails.Set(iOutputHeader->From()); + iEmailEntry->iDescription.Set(iOutputHeader->Subject()); + break; + case EFolderEntry: + iEmailEntry->iType=KUidMsvFolderEntry; + if (iMimeParser->MessageFolderType()==EFolderTypeUnknown) + { + // Get folder type of parent (the message) + TMsvEmailEntry entry=iClientEntry->Entry(); + iEmailEntry->SetMessageFolderType(entry.MessageFolderType()); + } + break; + case EAttachmentEntry: + iEmailEntry->iType=KUidMsvAttachmentEntry; + iEmailEntry->iDetails.Set(iAttachmentName); + iEmailEntry->iDescription.Set(iMimeParser->ContentDescription()); + break; + case ETextEntry: + if ( iMimeParser->ContentDisposition()!=KImcvAttachment) + iEmailEntry->iType=KUidMsvEmailTextEntry; + else + { + iEmailEntry->iType=KUidMsvAttachmentEntry; + iEmailEntry->iDetails.Set(iAttachmentName); + iEmailEntry->iDescription.Set(iMimeParser->ContentDescription()); + } + break; + case EHtmlEntry: + iEmailEntry->iType=KUidMsvEmailHtmlEntry; + // If disposition not set or is inline.. + if ( iMimeParser->ContentDisposition()==KImcvAttachment) + iEmailEntry->iType=KUidMsvAttachmentEntry; + else + iEmailEntry->SetMHTMLEmail(ETrue); + iEmailEntry->iDetails.Set(iAttachmentName); + iEmailEntry->iDescription.Set(iMimeParser->ContentDescription()); + break; + default: + iEmailEntry->iType=KUidMsvAttachmentEntry; + iEmailEntry->iDetails.Set(iAttachmentName); + iEmailEntry->iDescription.Set(iMimeParser->ContentDescription()); + } + + iClientEntry->CreateL(*iEmailEntry); + iEmailEntry->iServiceId = iEmailServiceId; + iClientEntry->SetEntryL(iEmailEntry->Id()); + if(iTopMessagePart==KMsvRootIndexEntryId) + { + iTopMessagePart=iEmailEntry->Id(); + } + } + + iEntryType=previousEntryType; + iNewEntry = ETrue; + RECVLOG(KCreatedEntry); + } + + +/** +StoreMessageEntryDetailsL() +Stores the details of a message entry. +*/ +void CImCltRecvConvert::StoreMessageEntryDetailsL() + { + iEmailEntry->SetAttachment(iParent->At(0).iAttachment); + iEmailEntry->SetMHTMLEmail(iParent->At(0).iMHTML); + + if(iEmailEntry->MHTMLEmail() == EFalse && iEmailEntry->Attachment() == EFalse && iRelatedAttachments !=EFalse) + { + iEmailEntry->SetAttachment(ETrue); + } + iRelatedAttachments=EFalse; + + iEmailEntry->iSize=iParent->At(0).iSize; + iEmailEntry->SetMessageFolderType(iParent->At(0).iFolder); + StoreEntryDataL(); + + if (iParent->Count()>1) + { + iParent->At(1).iSize+=iEmailEntry->iSize; + iParent->Delete(0); + } + else + { + iParent->At(0).iAttachment=iParent->At(0).iMHTML=EFalse; + iParent->At(0).iSize=0; + } + }