--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ipsservices/ipssosplugin/src/ipsplgmsgmapper.cpp Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,1574 @@
+/*
+* Copyright (c) 2007 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: This file implements class CIpsPlgMsgMapper.
+*
+*/
+
+
+
+#include "emailtrace.h"
+#include "ipsplgheaders.h"
+
+_LIT( KMimeTypeTextPlain, "text/plain" );
+_LIT( KMimeTypeTextHtml, "text/html" );
+_LIT( KMimeTypeTextRtf, "text/rtf" );
+_LIT( KSlash, "/" );
+
+_LIT( KCharSemicolon, ";" );
+_LIT( KCharEquals, "=" );
+_LIT( KCharsetTag, "CHARSET" );
+_LIT( KMessageExtension, ".eml" );
+
+// Supported multipart content types
+_LIT( KMimeTypeMultipartRelated, "multipart/related" );
+_LIT( KMimeTypeMultipartMixed, "multipart/mixed" );
+_LIT( KMimeTypeMultipartAlternative, "multipart/alternative" );
+_LIT( KMimeTypeMultipartDigest, "multipart/digest" );
+_LIT( KMimeTypeMultipartRfc822, "message/rfc822" );
+_LIT( KMimeTypeMultipartPartial, "message/partial" );
+_LIT( KMimeTypeMultipartDirectory, "text/directory" );
+_LIT( KMimeTypeMultipartExternalBody, "message/external-body" );
+_LIT( KMimeTypeMultipartParallel, "multipart/parallel" );
+
+const TInt KCharEscape = 0x5C;
+const TInt KCharNonPrintable = 0x1F;
+const TInt KCharAt = 0x40;
+const TInt KMaxContentTypeLength = 200;
+const TInt KEmbeddedMsgExtensionLength = 4;
+
+// ======== CONSTRUCTORS & DESTRUCTOR ========
+
+// ---------------------------------------------------------------------------
+// CIpsPlgMsgMapper::NewL()
+// ---------------------------------------------------------------------------
+//
+CIpsPlgMsgMapper* CIpsPlgMsgMapper::NewL(
+ CMsvSession& aSession,
+ CIpsPlgSosBasePlugin& aPlugin )
+ {
+ FUNC_LOG;
+ CIpsPlgMsgMapper* self = CIpsPlgMsgMapper::NewLC( aSession, aPlugin );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgMsgMapper::NewLC()
+// ---------------------------------------------------------------------------
+//
+CIpsPlgMsgMapper* CIpsPlgMsgMapper::NewLC(
+ CMsvSession& aSession,
+ CIpsPlgSosBasePlugin& aPlugin )
+ {
+ FUNC_LOG;
+ CIpsPlgMsgMapper* self =
+ new( ELeave ) CIpsPlgMsgMapper( aSession, aPlugin );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgMsgMapper::~CIpsPlgMsgMapper()
+// ---------------------------------------------------------------------------
+//
+CIpsPlgMsgMapper::~CIpsPlgMsgMapper()
+ {
+ FUNC_LOG;
+ }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgMsgMapper::CIpsPlgMsgMapper()
+// ---------------------------------------------------------------------------
+//
+CIpsPlgMsgMapper::CIpsPlgMsgMapper(
+ CMsvSession& aSession,
+ CIpsPlgSosBasePlugin& aPlugin )
+ : iSession( aSession ), iPlugin( aPlugin )
+ {
+ FUNC_LOG;
+ }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgMsgMapper::ConstructL()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgMsgMapper::ConstructL()
+ {
+ FUNC_LOG;
+ }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgMsgMapper::GetMailMessageL()
+// ---------------------------------------------------------------------------
+//
+CFSMailMessage* CIpsPlgMsgMapper::GetMailMessageL(
+ CMsvEntry& aEntry )
+ {
+ FUNC_LOG;
+ TFSMailMsgId msgId( iPlugin.PluginId(), aEntry.Entry().Id() );
+ CFSMailMessage* fsMsg = CFSMailMessage::NewLC( msgId );
+
+ fsMsg->SetFolderId(
+ TFSMailMsgId( iPlugin.PluginId(), aEntry.Entry().Parent() ) );
+
+ CMsvStore* store( NULL );
+
+ if ( aEntry.HasStoreL() )
+ {
+ store = aEntry.ReadStoreL();
+ CleanupStack::PushL( store );
+ }
+
+ SetEnvelopeL( &aEntry, store, *fsMsg );
+
+ // Apparently, this should be done only with
+ // EFSMsgDataStructure, but EFSMsgDataEnvelope is currently
+ // used by assuming that it reads also the content-type of
+ // the message
+ SetStructureL( &aEntry, *fsMsg );
+
+ TMsvEmailEntry tEntry( aEntry.Entry() );
+
+ SetFlags( tEntry, *fsMsg );
+
+ if ( store )
+ {
+ CleanupStack::PopAndDestroy( store );
+ }
+
+ CleanupStack::Pop( fsMsg );
+ return fsMsg;
+ }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgMsgMapper::GetMailMessageL()
+// ---------------------------------------------------------------------------
+//
+CFSMailMessage* CIpsPlgMsgMapper::GetMailMessageL(
+ const TFSMailMsgId& aMailboxId,
+ const TMsvEmailEntry& aEntry,
+ const TFSMailDetails& aDetails )
+ {
+ FUNC_LOG;
+ TFSMailMsgId msgId( iPlugin.PluginId(), aEntry.Id() );
+ CFSMailMessage* result = CFSMailMessage::NewLC( msgId );
+
+ result->SetMailBoxId( aMailboxId );
+ result->SetFolderId(
+ TFSMailMsgId( iPlugin.PluginId(), aEntry.Parent() ) );
+
+ SetFlags( aEntry, *result );
+ SetFetchStateL( aEntry, aEntry.Id(), EFalse, *result );
+
+ switch( aDetails )
+ {
+ case EFSMsgDataDate:
+ SetDateL( aEntry, *result );
+ break;
+ case EFSMsgDataSubject:
+ SetSubjectL( aEntry, *result );
+ break;
+ case EFSMsgDataSender:
+ SetSenderL( aEntry.iDetails, *result );
+ break;
+ case EFSMsgDataEnvelope:
+ case EFSMsgDataStructure:
+ {
+ CMsvStore* store( NULL );
+ CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() );
+ CleanupStack::PushL( cEntry );
+
+ if ( cEntry && cEntry->HasStoreL() )
+ {
+ store = cEntry->ReadStoreL();
+ CleanupStack::PushL( store );
+ }
+
+ SetEnvelopeL( cEntry, store, *result );
+
+ // Apparently, this should be done only with
+ // EFSMsgDataStructure, but EFSMsgDataEnvelope is currently
+ // used by assuming that it reads also the content-type of
+ // the message
+ SetStructureL( cEntry, *result );
+
+ if ( store )
+ {
+ CleanupStack::PopAndDestroy( store );
+ }
+ CleanupStack::PopAndDestroy( cEntry );
+ break;
+ }
+ case EFSMsgDataIdOnly:
+ default:
+ break;
+ }
+
+ CleanupStack::Pop( result );
+ return result;
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::GetChildPartsL(
+ const TFSMailMsgId& aMailBoxId,
+ const TFSMailMsgId& aMessageId,
+ const TFSMailMsgId& aParentId,
+ RPointerArray<CFSMailMessagePart>& aParts )
+ {
+ FUNC_LOG;
+
+ if ( aParentId.IsNullId() )
+ // the caller wants the children of the message
+ {
+ GetChildPartsOfMessageEntryL( aMailBoxId, aMessageId, aParts );
+ }
+ else
+ // the caller wants the parts of the 'real' subpart
+ {
+ GetChildPartsOfFolderEntryL( aMailBoxId, aMessageId, aParentId.Id(),
+ aParts );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+CFSMailMessagePart* CIpsPlgMsgMapper::GetMessagePartL(
+ TMsvId aEntryId,
+ const TFSMailMsgId& aMailBoxId,
+ const TFSMailMsgId& aMessageId )
+ {
+ FUNC_LOG;
+ CFSMailMessagePart* result( NULL );
+ TInt status;
+ TMsvId serviceId;
+ TMsvEmailEntry tEntry;
+
+ status = iSession.GetEntry( aEntryId, serviceId, tEntry );
+
+ if ( status == KErrNone )
+ {
+ switch ( tEntry.iType.iUid )
+ {
+ case KUidMsvFolderEntryValue:
+ {
+ result = ConvertFolderEntry2MessagePartL( tEntry,
+ aMailBoxId, aMessageId );
+ break;
+ }
+ case KUidMsvAttachmentEntryValue:
+ case KUidMsvMessageEntryValue:
+ {
+ result = ConvertAttachmentEntry2MessagePartL( tEntry,
+ aMailBoxId, aMessageId );
+ break;
+ }
+ case KUidMsvEmailTextEntryValue:
+ case KUidMsvEmailHtmlEntryValue:
+ case KUidMsvEmailExternalBodyEntryValue:
+ case KUidMsvEmailRtfEntryValue:
+ {
+ result = ConvertBodyEntry2MessagePartL( tEntry, aMailBoxId,
+ aMessageId );
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+TBool CIpsPlgMsgMapper::ChangeTEntryFlagsL(
+ TMsvEmailEntry& aEmlEntry,
+ const CFSMailMessage& aMessage )
+ {
+ FUNC_LOG;
+ TInt msgFlags = aMessage.GetFlags();
+ TBool modified ( EFalse );
+ TBool unread( aEmlEntry.Unread() );
+
+ if ( !LogicalXor( unread, msgFlags & EFSMsgFlag_Read ) )
+ {
+ aEmlEntry.SetUnread( !unread );
+ modified = ETrue;
+ }
+
+ // EFSMsgFlag_Low
+ // EFSMsgFlag_Important
+ TMsvPriority msgPriority;
+
+ if ( msgFlags & EFSMsgFlag_Important )
+ {
+ msgPriority = EMsvHighPriority;
+ }
+ else if ( msgFlags & EFSMsgFlag_Low )
+ {
+ msgPriority = EMsvLowPriority;
+ }
+ else
+ {
+ msgPriority = EMsvMediumPriority;
+ }
+
+ if ( aEmlEntry.Priority() != msgPriority )
+ {
+ aEmlEntry.SetPriority( msgPriority );
+ modified = ETrue;
+ }
+
+ // EFSMsgFlag_FollowUpComplete: no counterpart in Symbian message
+
+ // EFSMsgFlag_FollowUp: supported only with IMAP4 (see below)
+
+ // EFSMsgFlag_Attachments: It does not seem reasonable to update
+ // this flag here (but when attachments are added)
+
+ // EFSMsgFlag_Multiple: no counterpart in Symbian message
+
+ // EFSMsgFlag_CalendarMsg
+ if( ( aEmlEntry.iMtm == KSenduiMtmSmtpUid ) && ( msgFlags & EFSMsgFlag_CalendarMsg ) )
+ {
+ if( !aEmlEntry.ICalendar() )
+ {
+ aEmlEntry.SetICalendar( ETrue );
+ modified = ETrue;
+ }
+ }
+
+
+ // EFSMsgFlag_Answered: supported only with IMAP4 (see below)
+
+ // EFSMsgFlag_Forwarded: no counterpart in Symbian message in S60 3.1
+
+ // EFSMsgFlag_OnlyToMe: no counterpart in Symbian message
+
+ // EFSMsgFlag_RemoteDeleted: no counterpart in Symbian message
+
+ // EFSMsgFlag_HasMsgSender: no counterpart in Symbian message
+
+
+ //this applies to POP too. Just ignore the misleading naming
+ // moved to fix EANA-7HUD2G, pop doesn't support permanent flags
+ // EFSMsgFlag_Answered
+
+ // IMAP flags
+ if ( aEmlEntry.iMtm == KSenduiMtmImap4Uid )
+ {
+ // EFSMsgFlag_FollowUp
+ if ( LogicalXor( aEmlEntry.FlaggedIMAP4Flag(),
+ ( msgFlags & EFSMsgFlag_FollowUp ) ) )
+ {
+ aEmlEntry.SetFlaggedIMAP4Flag( !aEmlEntry.FlaggedIMAP4Flag() );
+ modified = ETrue;
+ }
+ // EFSMsgFlag_Answered
+ if ( LogicalXor( aEmlEntry.AnsweredIMAP4Flag(),
+ ( msgFlags & EFSMsgFlag_Answered ) ) )
+ {
+ aEmlEntry.SetAnsweredIMAP4Flag( !aEmlEntry.AnsweredIMAP4Flag() );
+ modified = ETrue;
+ }
+ }
+ return modified;
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::UpdateMessageFlagsL(
+ TMsvId aEntryId,
+ const CFSMailMessage& aMessage )
+ {
+ FUNC_LOG;
+ // This function updates tEntry from aMessage
+ CMsvEntry* cEntry = iSession.GetEntryL( aEntryId );
+ CleanupStack::PushL( cEntry );
+
+ TMsvEmailEntry tEntry( cEntry->Entry() );
+ TBool isModified = ChangeTEntryFlagsL( tEntry, aMessage );
+
+ if ( isModified )
+ {
+ CIpsPlgOperationWait* waiter = CIpsPlgOperationWait::NewLC();
+ CMsvOperation* ops = cEntry->ChangeL( tEntry, waiter->iStatus );
+ CleanupStack::PushL( ops );
+ waiter->Start();
+ CleanupStack::PopAndDestroy( 2, waiter );
+ }
+
+ CleanupStack::PopAndDestroy( cEntry );
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+CMsvOperation* CIpsPlgMsgMapper::UpdateMessageFlagsAsyncL(
+ TMsvId aEntryId,
+ const CFSMailMessage& aMessage,
+ TRequestStatus& aStatus )
+ {
+ FUNC_LOG;
+ // This function updates tEntry from aMessage
+ CMsvEntry* cEntry = iSession.GetEntryL( aEntryId );
+ CleanupStack::PushL( cEntry );
+ TMsvEmailEntry tEntry( cEntry->Entry() );
+
+ TBool isModified = ChangeTEntryFlagsL( tEntry, aMessage );
+ CMsvOperation* ops = NULL;
+ if ( isModified )
+ {
+ ops = cEntry->ChangeL( tEntry, aStatus );
+ }
+
+ CleanupStack::PopAndDestroy( cEntry );
+ return ops;
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::SetFSMessageFlagsL(
+ const TMsvEmailEntry& aEntry, CFSMailMessage& aMsg )
+ {
+ FUNC_LOG;
+ // this is just stupid through call, but now not need to
+ // move SetFlags to public
+ SetFlags( aEntry, aMsg );
+ }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgMsgMapper::NewChildPartL
+// The method supports currently only the multipart/alternative structure
+// construction (which is needed in the meeting request messages).
+// The creation of the multipart structure happens by changing the folder
+// type of the (SMTP) message entry itself. The folder entry is created
+// by Symbian MTM later when new parts are added below the multipart
+// structure. This causes some problems because there is no new entry
+// in this phase and so the new CFSMailMessagePart instance do not
+// ---------------------------------------------------------------------------
+CFSMailMessagePart* CIpsPlgMsgMapper::NewChildPartL(
+ const TFSMailMsgId& /* aMailBoxId */,
+ const TFSMailMsgId& aMessageId,
+ const TFSMailMsgId& /* aParentPartId */,
+ const TDesC& /*aContentType*/ )
+ {
+ FUNC_LOG;
+ CFSMailMessagePart* result( NULL );
+ result = CFSMailMessagePart::NewLC( aMessageId,
+ TFSMailMsgId( aMessageId.PluginId().iUid,
+ KMsvNullIndexEntryIdValue ) );
+ CleanupStack::Pop( result );
+ return result;
+ }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgMsgMapper::SetDateL
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgMsgMapper::SetDateL(
+ const TMsvEntry& aEntry,
+ CFSMailMessage& aMsg )
+ {
+ FUNC_LOG;
+ const TTime date = aEntry.iDate;
+ aMsg.SetDate( date );
+ }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgMsgMapper::SetSubjectL
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgMsgMapper::SetSubjectL(
+ const TMsvEntry& aEntry,
+ CFSMailMessage& aMsg )
+ {
+ FUNC_LOG;
+ aMsg.SetSubject( aEntry.iDescription );
+ }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgMsgMapper::SetSenderL
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgMsgMapper::SetSenderL(
+ TPtrC aSender,
+ CFSMailMessage& aMsg )
+ {
+ FUNC_LOG;
+ CFSMailAddress* addr = CFSMailAddress::NewLC();
+ ConvertAddressL( aSender, *addr );
+ aMsg.SetSender( addr );
+ CleanupStack::Pop( addr );
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::SetEnvelopeL(
+ const CMsvEntry* aEntry,
+ CMsvStore* aStore,
+ CFSMailMessage& aMsg )
+ {
+ FUNC_LOG;
+ CFSMailAddress* addr = NULL;
+
+ TMsvEmailEntry tEntry( aEntry->Entry() );
+
+ SetDateL( tEntry, aMsg );
+ SetSubjectL( tEntry, aMsg );
+
+ if ( aStore && aStore->IsPresentL( KUidMsgFileIMailHeader ) )
+ {
+ CImHeader* header = CImHeader::NewLC();
+ header->RestoreL( *aStore );
+
+ SetSenderL( header->From(), aMsg );
+
+ const CDesCArray& toRecs = header->ToRecipients();
+
+ for( TInt i=0; i<toRecs.Count(); i++ )
+ {
+ addr = CFSMailAddress::NewLC();
+ ConvertAddressL( toRecs[i], *addr );
+ aMsg.AppendToRecipient( addr );
+ CleanupStack::Pop( addr );
+ }
+
+ const CDesCArray& ccRecs = header->CcRecipients();
+
+ for( TInt i=0; i<ccRecs.Count(); i++ )
+ {
+ addr = CFSMailAddress::NewLC();
+ ConvertAddressL( ccRecs[i], *addr );
+ aMsg.AppendCCRecipient( addr );
+ CleanupStack::Pop( addr );
+ }
+
+ const CDesCArray& bccRecs = header->BccRecipients();
+
+ for( TInt i=0; i< bccRecs.Count(); i++ )
+ {
+ addr = CFSMailAddress::NewLC();
+ ConvertAddressL( bccRecs[i], *addr );
+ aMsg.AppendBCCRecipient( addr );
+ CleanupStack::Pop( addr );
+ }
+
+ CleanupStack::PopAndDestroy( header );
+ }
+ else
+ {
+ // if the email header stream is not available, the sender
+ // information is taken from the index entry
+ SetSenderL( aEntry->Entry().iDetails, aMsg );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::SetStructureL(
+ const CMsvEntry* aEntry,
+ CFSMailMessage& aMessage )
+ {
+ FUNC_LOG;
+ // Find out the content type by studying the child entry:
+ // If there are no children, the message contents are not fetched and
+ // thus the content type cannot be inferred. On the other hand,
+ // the message entry should never have more than one child entry
+ // (otherwise, it should be a multipart message)
+ if ( aEntry->Count() == 1 )
+ {
+ TMsvEmailEntry tEntry = (*aEntry)[0];
+ if ( tEntry.iType == KUidMsvFolderEntry )
+ {
+ aMessage.SetContentType(
+ ConvertMultipartMimeType( tEntry.MessageFolderType() ) );
+ }
+ else
+ // The case in which the content entry is directly below
+ // the message entry..
+ {
+ aMessage.SetContentType( KMimeTypeMultipartMixed );
+ }
+ }
+ else
+ {
+ // mark message structure state unknown if we don't have any
+ // child parts. This needed to ui start fetch
+ aMessage.SetMessagePartsStatus( EFSEmailStructureUnknown );
+ }
+
+ aMessage.SetContentSize( aEntry->Entry().iSize );
+ }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgMsgMapper::SetFlags
+// FS framework's flag definitions and methods are somewhat clumsy and thus
+// there is quite much code for a pretty simple function..
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::SetFlags(
+ const TMsvEmailEntry& aEntry,
+ CFSMailMessage& aMsg )
+ {
+ FUNC_LOG;
+
+ TBool forwardedMeetingRequest = EFalse;
+
+ // EFSMsgFlag_Read
+ // EFSMsgFlag_Read_Locally
+ if ( aEntry.Unread() )
+ {
+ aMsg.ResetFlag( EFSMsgFlag_Read );
+ aMsg.ResetFlag( EFSMsgFlag_Read_Locally );
+ }
+ else
+ {
+ aMsg.SetFlag( EFSMsgFlag_Read );
+ aMsg.SetFlag( EFSMsgFlag_Read_Locally );
+ }
+
+ // EFSMsgFlag_Low
+ // EFSMsgFlag_Important
+ switch ( aEntry.Priority() )
+ {
+ case EMsvHighPriority:
+ {
+ aMsg.SetFlag( EFSMsgFlag_Important );
+ aMsg.ResetFlag( EFSMsgFlag_Low );
+ break;
+ }
+ case EMsvMediumPriority:
+ {
+ aMsg.ResetFlag( EFSMsgFlag_Important );
+ aMsg.ResetFlag( EFSMsgFlag_Low );
+ break;
+ }
+ case EMsvLowPriority:
+ {
+ aMsg.ResetFlag( EFSMsgFlag_Important );
+ aMsg.SetFlag( EFSMsgFlag_Low );
+ break;
+ }
+ }
+
+ // EFSMsgFlag_FollowUpComplete: cannot be supported with Symbian messages?
+
+ // EFSMsgFlag_FollowUp: supported only with IMAP4 messages (see below)
+ aMsg.ResetFlag( EFSMsgFlag_FollowUp );
+
+// <cmail>
+ //only for incomplete POP3 messages
+ if ( aEntry.iMtm.iUid == KSenduiMtmPop3UidValue &&
+ ( !aEntry.Complete() || aEntry.PartialDownloaded () ) )
+ {
+ TRAP_IGNORE( AttaCheckForIncompleteMsgL( aEntry, aMsg ) );
+ }
+// </cmail>
+ else
+ {
+ // EFSMsgFlag_Attachments
+ if ( aEntry.Attachment() )
+ {
+ aMsg.SetFlag( EFSMsgFlag_Attachments );
+
+ if ( aEntry.ICalendar() )
+ {
+ // <cmail> implementation changed due to cs warning
+ TInt attCount = 0;
+ TRAPD ( err, attCount = GetAttachmentCountL( aEntry ) );
+ if ( err == KErrNone && attCount == 1 )
+ {
+ CMsvEntry* cEntry = NULL;
+ TRAPD ( err2, cEntry = iSession.GetEntryL( aEntry.Id() ) );
+ if ( err2 == KErrNone && cEntry->Count() == 1 )
+ {
+ TMsvEmailEntry tEntry = (*cEntry)[0];
+ TImEmailFolderType ft = tEntry.MessageFolderType();
+ if ( tEntry.iType == KUidMsvFolderEntry && ft == EFolderTypeMixed )
+ {
+ // Message with calendar object. But based on content type
+ // (multipart/mixed) we know that this is meeting request
+ // forwarded as email, so it must be seen as normal email.
+ forwardedMeetingRequest = ETrue;
+ aMsg.ResetFlag( EFSMsgFlag_CalendarMsg );
+ aMsg.SetFlag( EFSMsgFlag_Attachments );
+ }
+ else
+ {
+ // Only text/calendar part included as attachment
+ aMsg.ResetFlag( EFSMsgFlag_Attachments );
+ //Set Attachment flag for CMsvEntry (needed for sorting)
+ TRAP_IGNORE( SetAttachmentFlagL( aEntry, EFalse ) );
+ }
+ }
+ delete cEntry;
+ cEntry = NULL;
+ }
+ // </cmail>
+ }
+ }
+ else
+ {
+ aMsg.ResetFlag( EFSMsgFlag_Attachments );
+ }
+ }
+
+ // EFSMsgFlag_Multiple: currently this is not used anywhere and
+ // to evaluate the value, the CMsvStore of the message should be
+ // accessed which is relatively slow (compared to the access of
+ // the index entry)
+
+ // EFSMsgFlag_CalendarMsg
+ if ( aEntry.ICalendar() && !forwardedMeetingRequest ) // <cmail>
+ {
+ aMsg.SetFlag( EFSMsgFlag_CalendarMsg );
+ }
+ else if( !( aMsg.GetFlags() & EFSMsgFlag_CalendarMsg ) )
+ {
+ // Flag not set by mrui, we can reset it
+ aMsg.ResetFlag( EFSMsgFlag_CalendarMsg );
+ }
+
+ // EFSMsgFlag_Answered: supported only with IMAP4 messages (see below)
+ aMsg.ResetFlag( EFSMsgFlag_Answered );
+
+ // EFSMsgFlag_Forwarded: not supported in S60 3.1
+ aMsg.ResetFlag( EFSMsgFlag_Forwarded );
+
+ // EFSMsgFlag_OnlyToMe: like EFSMsgFlag_Multiple
+
+ // EFSMsgFlag_RemoteDeleted: no reasonable use in IPS
+
+ // EFSMsgFlag_HasMsgSender: currently not used anywhere. Could be
+ // probably be supported by checking the contents of TmsvEntry::iDetails
+ // but this should be tested
+
+ // Additional logic for IMAP4 messages
+ if ( aEntry.iMtm == KSenduiMtmImap4Uid )
+ {
+ if ( aEntry.FlaggedIMAP4Flag() )
+ {
+ aMsg.SetFlag( EFSMsgFlag_FollowUp );
+ }
+ // moved to fix EANA-7HUD2G, pop doesn't support permanent flags
+ if ( aEntry.AnsweredIMAP4Flag() )
+ {
+ aMsg.SetFlag( EFSMsgFlag_Answered );
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::SetFetchStateL(
+ const TMsvEmailEntry& aEntry,
+ TMsvId aMsgMainId,
+ TBool aIsAtta,
+ CFSMailMessagePart& aMessage )
+ {
+ FUNC_LOG;
+ if ( aEntry.iMtm.iUid == KSenduiMtmPop3UidValue &&
+ aEntry.Id() != aMsgMainId &&
+ !aIsAtta )
+ {
+ TInt error = KErrNone;
+ TMsvEmailEntry emlEntry;
+ TMsvId dummy;
+
+ error = iSession.GetEntry( aMsgMainId , dummy, emlEntry );
+
+ if ( error == KErrNone )
+ {
+ DoSetFetchStateL( emlEntry, aMsgMainId, aIsAtta, aMessage );
+ }
+ else
+ {
+ aMessage.SetMessagePartsStatus( EFSEmailStructureUnknown );
+ }
+ }
+ else
+ {
+ DoSetFetchStateL( aEntry, aMsgMainId, aIsAtta, aMessage );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::DoSetFetchStateL(
+ const TMsvEmailEntry& aEntry,
+ TMsvId aMsgMainId,
+ TBool aIsAtta,
+ CFSMailMessagePart& aMessage )
+ {
+ FUNC_LOG;
+ if ( aEntry.PartialDownloaded() )
+ {
+ aMessage.SetMessagePartsStatus( EFSPartial );
+ }
+ else if ( aEntry.BodyTextComplete() && !aIsAtta )
+ {
+ aMessage.SetMessagePartsStatus( EFSFull );
+ }
+ else if ( aEntry.Complete() && !aIsAtta )
+ {
+ aMessage.SetMessagePartsStatus( EFSFull );
+ }
+ else if ( aEntry.Complete() && aIsAtta )
+ {
+ CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() );
+
+ CleanupStack::PushL( cEntry );
+
+ TBool hasStore = cEntry->HasStoreL();
+
+ if ( hasStore )
+ {
+ CMsvStore* store = cEntry->EditStoreL();
+
+ CleanupStack::PushL( store );
+
+ MMsvAttachmentManager& attMgr = store->AttachmentManagerL();
+
+ if ( attMgr.AttachmentCount() )
+ {
+ aMessage.SetMessagePartsStatus( EFSFull );
+ }
+ else
+ {
+ aMessage.SetMessagePartsStatus( EFSNone );
+ }
+
+ CleanupStack::PopAndDestroy( store );
+ }
+
+ CleanupStack::PopAndDestroy( cEntry );
+ }
+ else if ( aEntry.Id() != aMsgMainId )
+ {
+ // fetch state of some message part, then we sure know
+ // structure, but its not complete nor partial so state must be
+ // none
+ aMessage.SetMessagePartsStatus( EFSNone );
+ }
+ else
+ {
+ aMessage.SetMessagePartsStatus( EFSEmailStructureUnknown );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+TPtrC CIpsPlgMsgMapper::ConvertMultipartMimeType(
+ TImEmailFolderType aFolderType ) const
+ {
+ FUNC_LOG;
+ TPtrC result;
+
+ switch ( aFolderType )
+ {
+ case EFolderTypeRelated:
+ {
+ result.Set( KMimeTypeMultipartRelated );
+ break;
+ }
+ case EFolderTypeMixed:
+ {
+ result.Set( KMimeTypeMultipartMixed );
+ break;
+ }
+ case EFolderTypeParallel:
+ {
+ result.Set( KMimeTypeMultipartParallel );
+ break;
+ }
+ case EFolderTypeAlternative:
+ {
+ result.Set( KMimeTypeMultipartAlternative );
+ break;
+ }
+ case EFolderTypeDigest:
+ {
+ result.Set( KMimeTypeMultipartDigest );
+ break;
+ }
+ case EFolderTypeRFC822:
+ {
+ result.Set( KMimeTypeMultipartRfc822 );
+ break;
+ }
+ case EFolderTypePartial:
+ {
+ result.Set( KMimeTypeMultipartPartial );
+ break;
+ }
+ case EFolderTypeDirectory:
+ {
+ result.Set( KMimeTypeMultipartDirectory );
+ break;
+ }
+ case EFolderTypeExternal:
+ {
+ result.Set( KMimeTypeMultipartExternalBody );
+ break;
+ }
+ case EFolderTypeUnknown:
+ default:
+ {
+ result.Set( KNullDesC16 );
+ break;
+ }
+ }
+
+ return result;
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+// <cmail>
+TInt CIpsPlgMsgMapper::ConvertBodyPartMimeType(
+ const TUid& aEntryType,
+ TDes& aMimeType )
+ {
+ FUNC_LOG;
+ TInt result( KErrNone );
+
+ switch ( aEntryType.iUid )
+ {
+ case KUidMsvEmailTextEntryValue:
+ {
+ aMimeType.Append( KMimeTypeTextPlain );
+ break;
+ }
+ case KUidMsvEmailHtmlEntryValue:
+ {
+ aMimeType.Append( KMimeTypeTextHtml );
+ break;
+ }
+ case KUidMsvEmailExternalBodyEntryValue:
+ {
+ // This seems a bit suspicious, but it is improbable that this case
+ // is ever used..
+ aMimeType.Append( KMimeTypeMultipartExternalBody );
+ break;
+ }
+ case KUidMsvEmailRtfEntryValue:
+ {
+ aMimeType.Append( KMimeTypeTextRtf );
+ break;
+ }
+ default:
+ {
+ result = KErrNotFound;
+ }
+ }
+ return result;
+ }
+// </cmail>
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::ConvertAddressL(
+ TPtrC aSourceAddress,
+ CFSMailAddress& aTargetAddress )
+ {
+ FUNC_LOG;
+ TInt status( KErrNone );
+ TImMessageField mailField;
+
+ aTargetAddress.SetEmailAddress(
+ mailField.GetValidInternetEmailAddressFromString( aSourceAddress ) );
+
+// <cmail>
+ // If previous validation fails because of invalid email address.
+ // e.g '@' is missing. Then address between '<' and '>' marks is used.
+ TInt start( aSourceAddress.LocateReverse('<') );
+ if ( start != KErrNotFound && start > 0)
+ {
+ TInt end( aSourceAddress.LocateReverse('>') );
+ start += 1;
+ aTargetAddress.SetEmailAddress( aSourceAddress.Mid( start, ( end - start ) ) );
+ }
+// </cmail>
+
+ TPtrC alias = mailField.GetValidAlias( aSourceAddress, status );
+ if ( status == KErrNone )
+ {
+ TPtr alias2 = alias.AllocLC()->Des(); // have to create copy because alias might change
+ for ( TInt ii = 0; ii < alias2.Length(); ii++ )
+ {
+ if ( alias2[ii] <= KCharNonPrintable )
+ {
+ alias2.Delete( ii, 1 );
+ ii--;
+ }
+ else if ( ii < ( alias2.Length() - 1 ) &&
+ alias2[ii] == KCharEscape )
+ {
+ if( alias2[ii+1] == KCharAt )
+ {
+ alias2.Delete( ii, 1 );
+ ii--;
+ }
+ }
+ }
+ aTargetAddress.SetDisplayName( alias2 ); // creates its own copy
+ CleanupStack::PopAndDestroy();
+ }
+ else
+ {
+// <cmail>
+ aTargetAddress.SetDisplayName( aTargetAddress.GetEmailAddress() );
+// </cmail>
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::SetContentTypeL(
+ CImMimeHeader& aMimeHeader,
+ CFSMailMessagePart& aMessagePart )
+ {
+ FUNC_LOG;
+ HBufC8* buffer8 = HBufC8::NewLC(
+ aMimeHeader.ContentType().Length() +
+ aMimeHeader.ContentSubType().Length() + 1 );
+ buffer8->Des().Append( aMimeHeader.ContentType() );
+ buffer8->Des().Append( KSlash );
+ buffer8->Des().Append( aMimeHeader.ContentSubType() );
+ HBufC* buffer = HBufC::NewLC( buffer8->Length() );
+ buffer->Des().Copy( buffer8->Des() );
+ aMessagePart.SetContentType( *buffer );
+ CleanupStack::PopAndDestroy( 2, buffer8 ); // buffer
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::GetChildPartsOfMessageEntryL(
+ const TFSMailMsgId& aMailBoxId,
+ const TFSMailMsgId& aMessageId,
+ RPointerArray<CFSMailMessagePart>& aParts )
+ {
+ FUNC_LOG;
+ CFSMailMessagePart* childPart( NULL );
+ CMsvEntry* cEntry = iSession.GetEntryL( aMessageId.Id() );
+ CleanupStack::PushL( cEntry );
+
+ if ( cEntry->Count() > 0 )
+ {
+ // Note: it is assumed that there is only one child which is
+ // either the body part (simple message) or the folder entry
+ // representing the main level multipart structure
+ if ( (*cEntry)[0].iType == KUidMsvFolderEntry )
+ {
+ GetChildPartsOfFolderEntryL( aMailBoxId, aMessageId,
+ (*cEntry)[0].Id(), aParts);
+ }
+ else
+ {
+ childPart = GetMessagePartL( (*cEntry)[0].Id(), aMailBoxId, aMessageId );
+ if( childPart )
+ {
+ aParts.Append( childPart );
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy( cEntry );
+ }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgMsgMapper::GetChildPartsOfFolderEntryL
+// Note: if the aParentId does not refer to a folder entry, childCount
+// will be zero and the method does not do anything.
+// It assumed that the method is called mainly for the folder entries
+// and thus CMsvEntry is constructed without checking the entry type
+// beforehand. If the assumption is not correct, the performance can be
+// optimized by checking the entry type first.
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::GetChildPartsOfFolderEntryL(
+ const TFSMailMsgId& aMailBoxId,
+ const TFSMailMsgId& aMessageId,
+ TMsvId aParentId,
+ RPointerArray<CFSMailMessagePart>& aParts )
+ {
+ FUNC_LOG;
+ CMsvEntry* cEntry = iSession.GetEntryL( aParentId );
+ CleanupStack::PushL( cEntry );
+ CFSMailMessagePart* childPart( NULL );
+ TInt childCount( cEntry->Count() );
+ TInt i;
+ TInt position;
+ TBool textBodyPartFound( EFalse );
+
+ for (i = 0; i < childCount; i++ )
+ {
+ childPart = GetMessagePartL( (*cEntry)[i].Id(), aMailBoxId, aMessageId );
+
+ // Child parts have to be ordered so that the plain text body
+ // part is first (if such exists) and the HTML body is next.
+ // The rest of the children can be in any order.
+ if ( (*cEntry)[i].iType == KUidMsvEmailTextEntry )
+ {
+ position = 0;
+ textBodyPartFound = ETrue;
+ }
+ else if ( (*cEntry)[i].iType == KUidMsvEmailHtmlEntry )
+ {
+ if ( textBodyPartFound )
+ {
+ position = 1;
+ }
+ else
+ {
+ position = 0;
+ }
+ }
+ else
+ {
+ position = i;
+ }
+
+ // Insert the new child part to the result array
+ if ( childPart )
+ {
+ aParts.Insert( childPart, position );
+ childPart = NULL;
+ }
+ }
+ CleanupStack::PopAndDestroy( cEntry );
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+CFSMailMessagePart* CIpsPlgMsgMapper::ConvertBodyEntry2MessagePartL(
+ const TMsvEmailEntry& aEntry,
+ const TFSMailMsgId& aMailBoxId,
+ const TFSMailMsgId& aMessageId )
+ {
+ FUNC_LOG;
+ CFSMailMessagePart* result( NULL );
+ TInt status;
+// <cmail>
+ HBufC* buf = HBufC::NewLC( KMaxContentTypeLength );
+ TPtr contentType = buf->Des();
+
+ status = ConvertBodyPartMimeType( aEntry.iType, contentType );
+ __ASSERT_DEBUG( ( status == KErrNone ),
+ User::Panic( KIpsPlgPanicCategory, EIpsPlgInvalidEntry ) );
+ if ( status == KErrNone )
+ {
+ result = CFSMailMessagePart::NewLC(
+ aMessageId, TFSMailMsgId( iPlugin.PluginId(), aEntry.Id() ) );
+
+ // If mimetype is 'text/html' add charset parameter
+ if ( aEntry.iType.iUid == KUidMsvEmailHtmlEntryValue )
+ {
+ GetCharsetParameterL( aEntry, contentType );
+ }
+// </cmail>
+ result->SetContentType( contentType );
+ result->SetMailBoxId( aMailBoxId );
+
+ // Size
+ result->SetContentSize( aEntry.iSize );
+
+ if ( aEntry.Complete() )
+ {
+ TMsvEmailEntry parent;
+ TMsvId dummy;
+ if ( aEntry.PartialDownloaded() )
+ {
+ CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() );
+ CleanupStack::PushL( cEntry );
+ if ( cEntry->HasStoreL() )
+ {
+ CMsvStore* store = cEntry->ReadStoreL();
+ CleanupStack::PushL( store );
+ result->SetFetchedContentSize( store->SizeL() );
+ CleanupStack::PopAndDestroy( store );
+ }
+
+ // sometimes store size is bigger than msg size
+ // even if msg is partially downloaded, then set
+ // fetched content size smaller than msg size
+ TUint fetchedSize = result->FetchedContentSize();
+ TUint contentSize = result->ContentSize();
+ if ( (contentSize > 0) && (fetchedSize > contentSize) )
+ {
+ result->SetFetchedContentSize( contentSize - 1 );
+ }
+
+ CleanupStack::PopAndDestroy( cEntry );
+ }
+ else if ( aEntry.iMtm == KSenduiMtmPop3Uid &&
+ iSession.GetEntry( aEntry.Parent(), dummy, parent )
+ == KErrNone && parent.PartialDownloaded() )
+ {
+ // we cant know remote size of pop body part, but
+ // we know it is not completely fetched at this point
+ // set content size fetchedSize+1 to make framework know that
+ // this message is not completely fetched
+
+ result->SetContentSize( aEntry.iSize+1 );
+ result->SetFetchedContentSize( aEntry.iSize );
+
+ }
+ else
+ {
+ result->SetFetchedContentSize( aEntry.iSize );
+ }
+ // This is "gludge-fix" for situation when
+ // content size is zero and message is complete
+ // mark sizes to 1 then ui not assume that something
+ // missing and not try to fetch it
+ if ( aEntry.iSize == 0 )
+ {
+ result->SetContentSize(1);
+ result->SetFetchedContentSize(1);
+ }
+ }
+ else
+ {
+ result->SetFetchedContentSize( 0 );
+ }
+
+ CleanupStack::Pop( result );
+ }
+ SetFetchStateL( aEntry, aMessageId.Id(), EFalse, *result );
+ CleanupStack::PopAndDestroy( buf );
+ return result;
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+CFSMailMessagePart* CIpsPlgMsgMapper::ConvertAttachmentEntry2MessagePartL(
+ const TMsvEmailEntry& aEntry,
+ const TFSMailMsgId& aMailBoxId,
+ const TFSMailMsgId& aMessageId )
+ {
+ FUNC_LOG;
+ CFSMailMessagePart* result( NULL );
+ HBufC* buffer;
+ CMsvEntry* cEntry;
+
+ __ASSERT_DEBUG( ( aEntry.iType == KUidMsvAttachmentEntry ||
+ aEntry.iType == KUidMsvMessageEntry ),
+ User::Panic( KIpsPlgPanicCategory, EIpsPlgInvalidEntry ) );
+
+ cEntry = iSession.GetEntryL( aEntry.Id() );
+ CleanupStack::PushL( cEntry );
+
+ if ( cEntry->HasStoreL() )
+ {
+ result = CFSMailMessagePart::NewLC( aMessageId,
+ TFSMailMsgId( iPlugin.PluginId(), aEntry.Id() ) );
+
+ CMsvStore* store = cEntry->ReadStoreL();
+ CleanupStack::PushL( store );
+
+ if ( store->IsPresentL( KUidMsgFileMimeHeader ) )
+ {
+ CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
+ mimeHeader->RestoreL( *store );
+
+ // Content-type
+ if ( aEntry.iType.iUid == KUidMsvMessageEntryValue )
+ {
+ result->SetContentType( KMimeTypeMultipartRfc822 );
+ }
+ else
+ {
+ SetContentTypeL( *mimeHeader, *result );
+ }
+
+ // Content-description
+ buffer = HBufC::NewLC(
+ mimeHeader->ContentDescription().Length ( ) );
+ buffer->Des().Copy ( mimeHeader->ContentDescription ( ) );
+ result->SetContentDescription ( *buffer );
+ CleanupStack::PopAndDestroy ( buffer );
+ buffer = NULL;
+
+ // Content-disposition
+ buffer = HBufC::NewLC(
+ mimeHeader->ContentDisposition().Length ( ) );
+ buffer->Des().Copy( mimeHeader->ContentDisposition() );
+ result->SetContentDisposition( *buffer );
+ CleanupStack::PopAndDestroy( buffer );
+ buffer = NULL;
+
+ // Content-type parameters
+
+ CDesC8Array& sourceArray( mimeHeader->ContentTypeParams() );
+ CDesCArray& targetArray( result->ContentTypeParameters() );
+ for ( TInt i=0; i<sourceArray.Count(); i++ )
+ {
+ buffer = HBufC::NewLC( sourceArray[i].Length() );
+ buffer->Des().Copy( sourceArray[i] );
+ targetArray.AppendL( buffer->Des() );
+ CleanupStack::PopAndDestroy( buffer );
+ buffer = NULL;
+ i++;
+ }
+
+ // Content ID
+ buffer = HBufC::NewLC(
+ mimeHeader->ContentID().Length ( ) );
+ buffer->Des().Copy( mimeHeader->ContentID() );
+ result->SetContentIDL( *buffer );
+ CleanupStack::PopAndDestroy( buffer );
+ buffer = NULL;
+
+ // Content-class: not supported by Symbian (non-standard field)
+
+ CleanupStack::PopAndDestroy( mimeHeader );
+ }
+ // Name
+ if ( aEntry.iType.iUid == KUidMsvMessageEntryValue )
+ {
+ HBufC* att = HBufC::NewLC( aEntry.iDescription.Length() + KEmbeddedMsgExtensionLength );
+ att->Des().Copy( aEntry.iDescription );
+ att->Des().Append( KMessageExtension );
+ result->SetAttachmentNameL( att->Des() );
+ CleanupStack::PopAndDestroy( att );
+ }
+ else
+ {
+ result->SetAttachmentNameL( aEntry.iDetails );
+ }
+
+ // Size
+ result->SetContentSize( aEntry.iSize );
+
+ if ( aEntry.Complete() )
+ {
+ result->SetFetchedContentSize( aEntry.iSize );
+ }
+ else
+ {
+ result->SetFetchedContentSize( 0 );
+ }
+ result->SetMailBoxId( aMailBoxId );
+ CleanupStack::PopAndDestroy(store);
+ CleanupStack::Pop( result );
+ }
+ SetFetchStateL( aEntry, aMessageId.Id(), ETrue, *result );
+ CleanupStack::PopAndDestroy( cEntry );
+
+ return result;
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+CFSMailMessagePart* CIpsPlgMsgMapper::ConvertFolderEntry2MessagePartL(
+ const TMsvEmailEntry& aEntry,
+ const TFSMailMsgId& aMailBoxId,
+ const TFSMailMsgId& aMessageId )
+ {
+ FUNC_LOG;
+ CFSMailMessagePart* result( NULL );
+
+ __ASSERT_DEBUG( ( aEntry.iType == KUidMsvFolderEntry ),
+ User::Panic( KIpsPlgPanicCategory, EIpsPlgInvalidEntry ) );
+
+ TPtrC mimeType = ConvertMultipartMimeType( aEntry.MessageFolderType() );
+
+ if ( mimeType.Length() > 0 )
+ {
+ result = CFSMailMessagePart::NewLC(
+ aMessageId, TFSMailMsgId( iPlugin.PluginId(), aEntry.Id() ) );
+
+ result->SetContentType( mimeType );
+ result->SetMailBoxId( aMailBoxId );
+
+ CleanupStack::Pop( result );
+ }
+
+ return result;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+//
+// ---------------------------------------------------------------------------
+// <cmail> implemented to get rid of cs warning
+TInt CIpsPlgMsgMapper::GetAttachmentCountL(
+ const TMsvEmailEntry& aEntry )
+ {
+ FUNC_LOG;
+ TInt result( KErrNone );
+
+ CMsvEntry *cEntry = iSession.GetEntryL( aEntry.Id() );
+ CleanupStack::PushL( cEntry );
+ CImEmailMessage* message = CImEmailMessage::NewLC( *cEntry );
+
+ message->GetAttachmentsListL( cEntry->Entry().Id( ),
+ CImEmailMessage::EAllAttachments, CImEmailMessage::EThisMessageOnly );
+
+ result = message->Selection().Count();
+
+ CleanupStack::PopAndDestroy( 2, cEntry ); // message, cEntry
+
+ return result;
+ }
+// </cmail>
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::AttaCheckForIncompleteMsgL(
+ const TMsvEmailEntry& aEntry,
+ CFSMailMessage& aMsg )
+ {
+ aMsg.ResetFlag( EFSMsgFlag_Attachments );
+
+ TImEmailFolderType ft = aEntry.MessageFolderType();
+
+ if ( ft == EFolderTypeUnknown )
+ {
+ CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() );
+ CleanupStack::PushL( cEntry );
+
+ if ( cEntry->HasStoreL() )
+ {
+ CMsvStore* store = cEntry->ReadStoreL();
+ CleanupStack::PushL( store );
+
+ if ( store->IsPresentL( KUidMsgFileMimeHeader ) )
+ {
+ CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
+ mimeHeader->RestoreL( *store );
+
+ HBufC8* buffer8 = HBufC8::NewLC(
+ mimeHeader->ContentType().Length() +
+ mimeHeader->ContentSubType().Length() + 1 );
+
+ buffer8->Des().Append( mimeHeader->ContentType() );
+ buffer8->Des().Append( KSlash );
+ buffer8->Des().Append( mimeHeader->ContentSubType() );
+
+ HBufC* buffer = HBufC::NewLC( buffer8->Length() );
+ buffer->Des().Copy( buffer8->Des() );
+
+ if ( buffer->CompareF( KMimeTypeMultipartMixed ) == 0 ||
+ buffer->CompareF( KMimeTypeMultipartRelated ) == 0 )
+ {
+ aMsg.SetFlag( EFSMsgFlag_Attachments );
+ if ( !aEntry.Attachment() )
+ {
+ SetAttachmentFlagL( aEntry, ETrue );
+ }
+ }
+
+ CleanupStack::PopAndDestroy( 3, mimeHeader );
+ }
+
+ CleanupStack::PopAndDestroy( store );
+ }
+ CleanupStack::PopAndDestroy( cEntry );
+ }
+ else if ( ft == EFolderTypeMixed || ft == EFolderTypeRelated )
+ {
+ aMsg.SetFlag( EFSMsgFlag_Attachments );
+ if ( !aEntry.Attachment() )
+ {
+ SetAttachmentFlagL( aEntry, ETrue );
+ }
+ }
+
+ if ( !aMsg.IsFlagSet( EFSMsgFlag_Attachments ) && aEntry.Attachment() )
+ {
+ SetAttachmentFlagL( aEntry, EFalse );
+ }
+ }
+// </cmail>
+
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+// <cmail>
+void CIpsPlgMsgMapper::SetAttachmentFlagL( const TMsvEmailEntry& aEntry,
+ TBool aHasAttachment )
+ {
+ FUNC_LOG;
+ CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() );
+ CleanupStack::PushL( cEntry );
+ // Only text/calendar part included as attachment
+ TMsvEmailEntry entryToBeChanged( aEntry );
+ entryToBeChanged.SetAttachment( aHasAttachment );
+ CIpsPlgOperationWait* waiter = CIpsPlgOperationWait::NewLC();
+ CMsvOperation* ops = cEntry->ChangeL( entryToBeChanged, waiter->iStatus );
+ CleanupStack::PushL( ops );
+ waiter->Start();
+ CleanupStack::PopAndDestroy( 3, cEntry );
+ }
+// </cmail>
+
+// <cmail>
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+void CIpsPlgMsgMapper::GetCharsetParameterL(
+ const TMsvEmailEntry& aEntry, TDes& aContentType )
+ {
+ FUNC_LOG;
+
+ CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() );
+ CleanupStack::PushL( cEntry );
+ if ( cEntry->HasStoreL() )
+ {
+ CMsvStore* store = cEntry->ReadStoreL();
+ CleanupStack::PushL( store );
+ if ( store->IsPresentL( KUidMsgFileMimeHeader ) )
+ {
+ CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
+ mimeHeader->RestoreL( *store );
+
+ TInt count = mimeHeader->ContentTypeParams().MdcaCount();
+ INFO_1("# of CT params: %d", count);
+ for ( TInt i = 0; i < count; i++ )
+ {
+ TPtrC8 key8 = mimeHeader->ContentTypeParams().MdcaPoint( i );
+ INFO_1("%S", &key8);
+ TPtr16 keyUppercase16 = HBufC::NewLC( key8.Length() )->Des();
+ keyUppercase16.Copy( key8 );
+ keyUppercase16.UpperCase();
+ if ( keyUppercase16.Compare( KCharsetTag ) == 0 &&
+ count >= i+1 ) // prevent possible indexing over array limits
+ {
+ // Starting to append text to the current content-type header..
+ // First, add ';'
+ aContentType.Append( KCharSemicolon );
+
+ // Then, 'CHARSET'
+ aContentType.Append( keyUppercase16 );
+
+ // '='
+ aContentType.Append( KCharEquals );
+
+ // Finally, the actual charset value (e.g. 'utf-8' or similar)
+ TPtrC8 value8 = mimeHeader->ContentTypeParams().MdcaPoint( i+1 );
+ TPtr16 value16 = HBufC::NewLC( value8.Length() )->Des();
+ value16.Copy( value8 );
+ aContentType.Append( value16 );
+ CleanupStack::PopAndDestroy(); // value16
+ }
+ CleanupStack::PopAndDestroy(); // keyUppercase16
+ } // for loop
+ CleanupStack::PopAndDestroy( mimeHeader );
+ }
+ CleanupStack::PopAndDestroy( store );
+ }
+ CleanupStack::PopAndDestroy( cEntry );
+ }
+// </cmail>