ipsservices/ipssosplugin/src/ipsplgsmtpservice.cpp
changeset 0 8466d47a6819
child 4 e7aa27f58ae1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ipsservices/ipssosplugin/src/ipsplgsmtpservice.cpp	Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,672 @@
+/*
+* 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 CIpsPlgSmtpService.
+*
+*/
+
+
+#include "emailtrace.h"
+#include "ipsplgheaders.h"
+
+// <cmail> const TInt KIpsSetUtilsCharAt = '@'; </cmail>
+const TInt KIpsSetUtilsCharLessThan = '<';
+const TInt KIpsSetUtilsCharMoreThan = '>';
+const TInt KIpsSetUtilsCntrCharacters = 2;
+
+// do we need smtp object instead set of static functions
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::CIpsPlgSmtpService
+// ---------------------------------------------------------------------------
+//
+CIpsPlgSmtpService::CIpsPlgSmtpService(
+    CMsvSession& aSession,
+    CIpsPlgSosBasePlugin& aPlugin ) :
+    iPlugin( aPlugin ),
+    iSession( aSession), 
+    iMsgMapper( NULL )
+    {
+    FUNC_LOG;
+    }
+  
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::~CIpsPlgSmtpService
+// ---------------------------------------------------------------------------
+//    
+CIpsPlgSmtpService::~CIpsPlgSmtpService() 
+    {
+    FUNC_LOG;
+    delete iMsgMapper;
+    }    
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::NewL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C CIpsPlgSmtpService* CIpsPlgSmtpService::NewL(
+    CMsvSession& aSession,
+    CIpsPlgSosBasePlugin& aPlugin )
+    {
+    FUNC_LOG;
+    CIpsPlgSmtpService* self = CIpsPlgSmtpService::NewLC( 
+        aSession, aPlugin  );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::NewLC
+// ---------------------------------------------------------------------------
+//
+EXPORT_C CIpsPlgSmtpService* CIpsPlgSmtpService::NewLC(
+    CMsvSession& aSession,
+    CIpsPlgSosBasePlugin& aPlugin )
+    {
+    FUNC_LOG;
+    CIpsPlgSmtpService* self = new( ELeave ) CIpsPlgSmtpService( 
+        aSession, aPlugin );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;
+    }
+    
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSmtpService::ConstructL()
+    {
+    FUNC_LOG;
+    iMsgMapper = CIpsPlgMsgMapper::NewL( iSession, iPlugin );
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::CreateDisplayStringLC
+// ---------------------------------------------------------------------------
+//
+HBufC* CIpsPlgSmtpService::CreateDisplayStringLC(
+    const TDesC& aDisplayName,
+    const TDesC& aEmailName )
+    {
+    FUNC_LOG;
+    TInt length( aDisplayName.Length() );
+    HBufC* fullName( NULL );
+    
+    length += aEmailName.Length() + KIpsSetUtilsCntrCharacters;
+    fullName = HBufC::NewLC( length );
+    fullName->Des().Append( aDisplayName );
+    
+    if ( fullName->Length() )
+        {
+        // We have display name, add angle brackets to address
+        fullName->Des().Append( KIpsSetUtilsCharLessThan );
+        fullName->Des().Append( aEmailName );
+        fullName->Des().Append( KIpsSetUtilsCharMoreThan );
+        }
+    else
+        {
+        fullName->Des().Append( aEmailName );
+        }
+    return fullName;
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::StoreMessageL
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSmtpService::StoreMessageL( 
+    TFSMailMsgId /* aMailBoxId */, CFSMailMessage& aMessage )
+    {
+    FUNC_LOG;
+
+    // Update flags i.e. Priority
+    iMsgMapper->UpdateMessageFlagsL( aMessage.GetMessageId().Id(), aMessage );
+    
+    // get message from store
+    CMsvEntry* cEntry = CMsvEntry::NewL(
+        iSession, aMessage.GetMessageId().Id(), TMsvSelectionOrdering() );
+    CleanupStack::PushL( cEntry );  // << cEntry
+    TMsvEntry tEntry = cEntry->Entry();    
+    
+    // creating store object for editing message
+    CMsvStore* store = cEntry->EditStoreL();
+    CleanupStack::PushL( store );   // << store
+    
+    // create symbian email header object
+    CImHeader* header = CImHeader::NewLC(); // << header
+    header->RestoreL( *store );
+
+    // From field, check that sender is set
+    if ( aMessage.GetSender() )
+        {
+        header->SetFromL( aMessage.GetSender()->GetEmailAddress() );
+        }
+    
+    // To Field
+    const RPointerArray<CFSMailAddress>& toArray 
+        = aMessage.GetToRecipients();
+    // Reseting recipient list, because our client calls us many times
+    // and we want to avoid duplicates
+    header->ToRecipients().Reset();
+    // build new 'to' header
+    for( TInt i = 0; i < toArray.Count(); i++ )
+        {
+        TPtrC displayName = toArray[i]->GetDisplayName();
+        TPtrC emailName = toArray[i]->GetEmailAddress();
+        HBufC* fullName = CreateDisplayStringLC( displayName, emailName );  // << fullName
+        header->ToRecipients().AppendL( *fullName ); // copy created
+        // only first receiver 
+        if( i == 0 && fullName )
+            {
+            tEntry.iDetails.Set( *fullName );
+            cEntry->ChangeL( tEntry );
+            // Load tEntry again
+            // because old instance's iDetails member gets wiped
+            // in PopAndDestroy below
+            tEntry = cEntry->Entry();
+            }
+        CleanupStack::PopAndDestroy( fullName );    // >>> fullName
+        }   
+    
+    // CC field
+    const RPointerArray<CFSMailAddress>& ccArray 
+        = aMessage.GetCCRecipients();
+    header->CcRecipients().Reset();
+    for( TInt i = 0; i < ccArray.Count(); i++ )
+        {
+        header->CcRecipients().AppendL( ccArray[i]->GetEmailAddress() ); // copy created
+        }
+    
+    // BCC field
+    const RPointerArray<CFSMailAddress>& bccArray 
+        = aMessage.GetBCCRecipients();
+    header->BccRecipients().Reset();
+    for( TInt i = 0; i < bccArray.Count(); i++ )
+        {
+        header->BccRecipients().AppendL( bccArray[i]->GetEmailAddress() ); // copy created
+        }
+    
+    // Subject, check null pointer
+    if ( &aMessage.GetSubject() )
+        {
+        header->SetSubjectL( aMessage.GetSubject() );
+        }
+        
+    // store header in cEntry's store
+    header->StoreWithoutCommitL(*store);
+    // commit header to store
+    store->CommitL();
+    
+    //change preparation state and set subject to description
+    tEntry.SetInPreparation( EFalse );
+    tEntry.iDescription.Set( aMessage.GetSubject() );
+    
+    cEntry->ChangeL( tEntry );
+    
+    // release store
+    CleanupStack::PopAndDestroy( 3, cEntry );   // >>> cEntry, header, store
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::CreateNewSmtpMessageL
+// ---------------------------------------------------------------------------
+//
+CFSMailMessage* CIpsPlgSmtpService::CreateNewSmtpMessageL( 
+    const TFSMailMsgId& aMailBoxId )
+    {
+    FUNC_LOG;
+    TMsvPartList partList( KMsvMessagePartBody );
+    
+    CIpsPlgOperationWait* wait = CIpsPlgOperationWait::NewLC( );
+    
+    TMsvEntry mboxEntry;
+    TMsvId service;
+    iSession.GetEntry( aMailBoxId.Id(), service, mboxEntry );
+    
+    // new mail creating operation. Mail is created asynchronously
+    CImEmailOperation* newMailOp = CImEmailOperation::CreateNewL(
+            wait->iStatus, 
+            iSession,
+            KMsvDraftEntryId,
+            mboxEntry.iRelatedId, 
+            partList, 
+            0, 
+            KUidMsgTypeSMTP );
+    
+    CleanupStack::PushL( newMailOp );
+
+    // wait until new mail is created
+    wait->Start();
+   
+    TMsvId msgId = GetIdFromProgressL( newMailOp->FinalProgress() );
+    
+    CleanupStack::PopAndDestroy( 2, wait );
+    
+    return CreateFSMessageAndSetFlagsL( 
+            msgId, KErrNotFound, aMailBoxId.Id() );
+    }
+    
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::CreateForwardSmtpMessageL
+// ---------------------------------------------------------------------------
+//
+CFSMailMessage* CIpsPlgSmtpService::CreateForwardSmtpMessageL( 
+    const TFSMailMsgId& aMailBoxId,
+    const TFSMailMsgId& aOriginalMessageId )
+    {
+    FUNC_LOG;
+    // 1. part of function checs that body text and all
+    // attachments are fetched
+    TMsvEntry orgMsg;
+    TMsvId service;
+    User::LeaveIfError( iSession.GetEntry( 
+            aOriginalMessageId.Id(), service, orgMsg ) );
+    
+    if ( orgMsg.Id() ==  KMsvNullIndexEntryIdValue )
+        {
+        User::Leave(KErrNotFound);
+        }
+    
+    // In case original message is in Sent folder, it's serviceId must be
+    // changed before starting forward/reply msg creation operation
+    // (after forward msg is created, this is changed back)
+    TMsvId orgServiceId( 0 );
+    if ( ( orgMsg.Parent() == KMsvSentEntryIdValue ) && 
+         ( orgMsg.iMtm == KSenduiMtmSmtpUid ) )
+        {
+        orgServiceId = orgMsg.iServiceId;
+        ChangeServiceIdL( orgMsg );
+        }
+
+    TMsvPartList partList( KMsvMessagePartBody | KMsvMessagePartAttachments );
+    
+    CIpsPlgOperationWait* wait = CIpsPlgOperationWait::NewLC( );
+    CImEmailOperation* forwMailOp = CImEmailOperation::CreateForwardL(
+            wait->iStatus, 
+            iSession,
+            orgMsg.Id(),
+            KMsvDraftEntryId, 
+            partList, 
+            0, 
+            KUidMsgTypeSMTP );
+            
+    CleanupStack::PushL( forwMailOp );
+    
+    wait->Start();
+    
+    TMsvId msgId = GetIdFromProgressL( forwMailOp->FinalProgress() );
+    
+    CleanupStack::PopAndDestroy( 2, wait );
+
+    // If original message's serviceId was changed prior to forward/reply msg
+    // creation op, changing it back to the original
+    if ( orgServiceId )
+        {
+        ChangeServiceIdL( orgMsg, orgServiceId );
+        }
+    
+    return CreateFSMessageAndSetFlagsL( msgId, orgMsg.Id(), aMailBoxId.Id() );
+    }
+    
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::CreateReplySmtpMessageL
+// ---------------------------------------------------------------------------
+//
+CFSMailMessage* CIpsPlgSmtpService::CreateReplySmtpMessageL( 
+    const TFSMailMsgId& aMailBoxId,
+    const TFSMailMsgId& aOriginalMessageId,
+    TBool aReplyToAll )
+    {
+    FUNC_LOG;
+    // find orginal message header and check that body is fetched
+    TMsvEntry orgMsg;
+    TMsvId service;
+    User::LeaveIfError( 
+        iSession.GetEntry( aOriginalMessageId.Id(), service, orgMsg ) );
+    
+    if ( orgMsg.Id() ==  KMsvNullIndexEntryIdValue )
+        {
+        User::Leave(KErrNotFound);
+        }
+    
+    // In case original message is in Sent folder, it's serviceId must be
+    // changed before starting forward/reply msg creation operation
+    // (after forward msg is created, this is changed back)
+    TMsvId orgServiceId( 0 );
+    if ( ( orgMsg.Parent() == KMsvSentEntryIdValue ) && 
+         ( orgMsg.iMtm == KSenduiMtmSmtpUid ) )
+        {
+        orgServiceId = orgMsg.iServiceId;
+        ChangeServiceIdL( orgMsg );
+        }
+    
+    // partList flags control e.g. what kind of recipient set is created
+    TMsvPartList partList = KMsvMessagePartBody | KMsvMessagePartDescription
+    | KMsvMessagePartOriginator;        
+    if( aReplyToAll )
+        {
+        partList |= KMsvMessagePartRecipient;
+        }
+    
+    // Ask Symbian messaging fw to create reply message "skeleton"
+    CIpsPlgOperationWait* wait = CIpsPlgOperationWait::NewLC( );
+    CImEmailOperation* replMailOp = CImEmailOperation::CreateReplyL(
+            wait->iStatus, 
+            iSession,
+            orgMsg.Id(),
+            KMsvDraftEntryId, 
+            partList, 
+            0, 
+            KUidMsgTypeSMTP );
+    CleanupStack::PushL( replMailOp );
+    wait->Start();
+    TMsvId msgId = GetIdFromProgressL( replMailOp->FinalProgress() );
+    CleanupStack::PopAndDestroy( 2, wait );
+    
+    // If original message's serviceId was changed prior to forward/reply msg
+    // creation op, changing it back to the original
+    if ( orgServiceId )
+        {
+        ChangeServiceIdL( orgMsg, orgServiceId );
+        }
+
+    // Start finalising new FS style message
+    CFSMailMessage* fsMsg = CreateFSMessageAndSetFlagsL( 
+            msgId, orgMsg.Id(), aMailBoxId.Id() );
+    CleanupStack::PushL( fsMsg ); // ***
+
+    // dig out new reply message's header
+    CMsvEntry* cEntry = iSession.GetEntryL( msgId );
+    CleanupStack::PushL( cEntry ); // ***
+    CMsvStore* store = cEntry->ReadStoreL();
+    CleanupStack::PushL( store ); // ***
+    if( store->IsPresentL( KUidMsgFileIMailHeader ) == EFalse )
+         {
+         User::Leave(KErrCorrupt);
+         }
+    CImHeader* header = CImHeader::NewLC(); // ***
+    header->RestoreL( *store );
+
+    // Start handling recipients
+    HBufC* emailAddr( NULL );
+    CFSMailAddress* fsAddr( NULL );
+    // copy to recipients
+    for( TInt i = 0; i < header->ToRecipients().Count(); i++ )
+        {
+        emailAddr = header->ToRecipients()[i].AllocLC(); // ***
+        fsAddr = CFSMailAddress::NewLC(); // ***
+        fsAddr->SetEmailAddress( *emailAddr ); // Copy created
+        fsMsg->AppendToRecipient( fsAddr ); // No copy
+        CleanupStack::Pop( fsAddr ); // fsAddr belong now to fsMsg
+        CleanupStack::PopAndDestroy( emailAddr ); // emailAddr not used
+        }
+    // copy cc recipients
+    // <cmail>
+    TFSMailMsgId folderId;
+    TFSMailDetails details( EFSMsgDataEnvelope );
+    CFSMailMessage* originalMessage = iPlugin.GetMessageByUidL( aMailBoxId, 
+                                       folderId, aOriginalMessageId, details );
+    CleanupStack::PushL( originalMessage );
+    RPointerArray<CFSMailAddress>& originalToRecipients = 
+                                            originalMessage->GetToRecipients();
+    TInt originalToRecipientsCount = originalToRecipients.Count(); 
+    TBool present = EFalse;
+    // </cmail>
+    for( TInt i = 0; i < header->CcRecipients().Count(); i++ )
+        {
+        emailAddr = header->CcRecipients()[i].AllocLC(); // ***
+        fsAddr = CFSMailAddress::NewLC(); // ***
+        fsAddr->SetEmailAddress( *emailAddr ); // Copy created
+        // <cmail>
+        if( aReplyToAll )
+            {
+            // check if CC recipient read from header was present in To field
+            // of original message. If so, copy it into To recipietns
+            present = EFalse;
+            for( TInt j = 0; j < originalToRecipientsCount; j++ )
+                {
+                if( emailAddr->Find( originalToRecipients[j]->GetEmailAddress())
+                                                              != KErrNotFound )
+                    {
+                    present = ETrue;
+                    break;
+                    }
+                }
+            if( present )
+                {
+                fsMsg->AppendToRecipient( fsAddr ); // No copy
+                }
+            else
+                {
+                fsMsg->AppendCCRecipient( fsAddr ); // No copy
+                }
+            }
+        else
+        {
+            fsMsg->AppendCCRecipient( fsAddr ); // No copy
+        }
+        // </cmail>
+        CleanupStack::Pop( fsAddr ); // fsAddr belong now to fsMsg
+        CleanupStack::PopAndDestroy( emailAddr ); // emailAddr not used
+        }
+    // <cmail>
+    CleanupStack::PopAndDestroy( originalMessage );
+    // </cmail>
+    // copy bcc recipients
+    for( TInt i = 0; i < header->BccRecipients().Count(); i++ )
+        {
+        emailAddr = header->BccRecipients()[i].AllocLC(); // ***
+        fsAddr = CFSMailAddress::NewLC(); // ***
+        fsAddr->SetEmailAddress( *emailAddr ); // Copy created
+        fsMsg->AppendBCCRecipient( fsAddr ); // No copy
+        CleanupStack::Pop( fsAddr ); // fsAddr belong now to fsMsg
+        CleanupStack::PopAndDestroy( emailAddr ); // emailAddr not used
+        }
+
+    CleanupStack::PopAndDestroy( 3, cEntry ); // header, store, cEntry
+    CleanupStack::Pop( fsMsg ); // fsMsg is given to client
+    return fsMsg;
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::ChangeServiceIdL
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSmtpService::ChangeServiceIdL( TMsvEntry& aEntry )
+    {
+    FUNC_LOG;
+    TMsvEntry serviceEntry;
+    TMsvId service;
+    CMsvEntry* cEntry = iSession.GetEntryL( aEntry.iServiceId );
+    CleanupStack::PushL( cEntry );
+    User::LeaveIfError( iSession.GetEntry( cEntry->EntryId(), service, serviceEntry ) );
+    if( aEntry.iServiceId != serviceEntry.iRelatedId )
+        {
+        aEntry.iServiceId = serviceEntry.iRelatedId;
+        cEntry->SetEntryL( aEntry.Id() );
+        cEntry->ChangeL( aEntry );
+        }
+    CleanupStack::PopAndDestroy( cEntry );
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::ChangeServiceIdL
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSmtpService::ChangeServiceIdL( TMsvEntry& aEntry, TMsvId aServiceId )
+    {
+    FUNC_LOG;
+    CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() );
+    CleanupStack::PushL( cEntry );
+    aEntry.iServiceId = aServiceId;
+    cEntry->ChangeL( aEntry );
+    CleanupStack::PopAndDestroy( cEntry );
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::CreateFSMessageAndSetFlagsL
+// ---------------------------------------------------------------------------
+//
+CFSMailMessage* CIpsPlgSmtpService::CreateFSMessageAndSetFlagsL(
+       TMsvId aMessageId, TMsvId aOriginalMsgId,TMsvId aMailboxId )
+    {
+    FUNC_LOG;
+
+    // Default charset
+    TUid charset;
+    charset.iUid = KCharacterSetIdentifierUtf8;
+
+    // set in preparation flag, altought 
+    // not known where this affects
+    TMsvId dummy;
+    TMsvEmailEntry newEmailMsg;
+    iSession.GetEntry( aMessageId, dummy, newEmailMsg );
+    newEmailMsg.SetInPreparation( ETrue );
+    
+    // when creating new message from scratch theres no 
+    // orginal message, so it is set to KErrNotFound
+    if ( aOriginalMsgId != KErrNotFound )
+        {
+        TMsvEntry orgMsg;
+        //get entry errors not handled
+        iSession.GetEntry( aOriginalMsgId, dummy, orgMsg );
+        const TMsvEmailEntry& orgEmailMsg(orgMsg);
+        
+        // symbian not mark same priority to reply / forward messages
+        if ( orgEmailMsg.Priority() != newEmailMsg.Priority() )
+            {
+            newEmailMsg.SetPriority( orgEmailMsg.Priority() );
+            }
+        //get charset from original message
+        charset = GetOriginalCharsetL( aOriginalMsgId );
+        }
+    
+    // set in preparation
+    CMsvEntry* cEntry = iSession.GetEntryL( aMessageId );
+    CleanupStack::PushL( cEntry );
+    cEntry->ChangeL( newEmailMsg );
+
+    //no need to set if we for some reason don't have it.
+    //system default will be used.
+    if ( KNullUidValue != charset.iUid )
+        {
+        SetCharactersetL( *cEntry, charset );
+        }
+    // delete operations we don't need anymore
+    CleanupStack::PopAndDestroy( cEntry );
+    
+    // create a Freestyle mail message object and set to it all
+    // needed data from just created symbian mail message
+    CFSMailMessage* fsMsg = CFSMailMessage::NewL(
+        TFSMailMsgId( iPlugin.PluginId(), aMessageId ) );
+    fsMsg->SetMailBoxId( TFSMailMsgId( iPlugin.PluginId(), aMailboxId ) );
+    fsMsg->SetFolderId( 
+        TFSMailMsgId( iPlugin.PluginId(), KMsvDraftEntryId ) );
+
+    //update flags
+    iMsgMapper->SetFSMessageFlagsL( newEmailMsg, *fsMsg );
+    
+    return fsMsg;
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::GetIdFromProgressL
+// inline static
+// ---------------------------------------------------------------------------
+//
+inline TMsvId CIpsPlgSmtpService::GetIdFromProgressL( const TDesC8& aProg )
+    {
+    FUNC_LOG;
+    // Taken from symbian os help example code
+    // Create and initialise a temporary TPckg object that 
+    // can hold a message Id.
+    TMsvId msgId;
+    TPckg<TMsvId> param(msgId);
+    
+    // Copy the message Id returned from the ProgressL() call into the
+    // temporary TPckg object.
+    param.Copy( aProg ); 
+
+    // Check the value of the returned message Id in the TPckg object.
+    if ( msgId == KMsvNullIndexEntryId )
+        {
+        // Email is not correctly created, so leave
+        User::Leave( KErrNotFound );
+        }
+    return msgId;
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::GetOriginalCharsetL
+// ---------------------------------------------------------------------------
+//
+TUid CIpsPlgSmtpService::GetOriginalCharsetL( TMsvId aOriginalMsgId )
+    {
+    FUNC_LOG;
+    TUid ret;
+    CMsvEntry* oEntry = iSession.GetEntryL( aOriginalMsgId );
+    CleanupStack::PushL( oEntry );
+    
+    CImEmailMessage* cMessage = CImEmailMessage::NewLC( *oEntry );
+    
+    // <cmail> Added check for body text because GetCharacterSetL will
+    // hang if there is no body text
+    CMsvStore* store = oEntry->EditStoreL();
+    CleanupStack::PushL(store);
+
+    TUint charId;
+    
+    if( store->HasBodyTextL() )
+        {
+        TBool override=EFalse;
+        cMessage->GetCharacterSetL( aOriginalMsgId, charId, override );
+        ret.iUid = charId;
+        }
+    else
+        {
+        ret.iUid = KCharacterSetIdentifierUtf8;
+        }
+    
+    CleanupStack::PopAndDestroy( 3, oEntry );//oEntry, cMessage, store
+    // </cmail>
+      
+    return ret;
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSmtpService::SetCharactersetL
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSmtpService::SetCharactersetL( CMsvEntry& aEntry, TUid aCharset )
+    {
+    FUNC_LOG;
+    //Set character set for outgoing message. We use the one 
+    //that was in the original message.     
+    CMsvStore* store = aEntry.EditStoreL();
+    CleanupStack::PushL(store);
+
+    CImHeader* header = CImHeader::NewLC();
+    header->RestoreL( *store );
+    
+    TImEmailTransformingInfo info;
+    info.SetToDefault(ESendAsMimeEmail);    
+    info.SetHeaderAndBodyCharset( aCharset.iUid );
+    info.StoreL( *store );
+    
+    header->StoreL( *store );
+    store->CommitL();
+    CleanupStack::PopAndDestroy( 2, store ); // store, header       
+    }
+// End of File
+