emailservices/emailstore/base_plugin/src/BasePlugin.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 14 Apr 2010 15:42:15 +0300
branchRCL_3
changeset 17 8592a65ad3fb
parent 8 e1b6206813b4
child 24 b5fbb9b25d57
permissions -rw-r--r--
Revision: 201013 Kit: 201015

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Email interface implementation.
*
*/


//MsgStore.
//<cmail>
#include "msgstore.h"
#include "msgstoreaccount.h"
#include "msgstoremailbox.h"
#include "msgstoremessage.h"
#include "msgstorefolder.h"
#include "msgstorepropertycontainer.h"
#include "msgstorepropertykeys.h"
#include "msgstoresortcriteria.h"
#include "msgstoresortresultiterator.h"
//Freestyle.
#include "cfsmailcommon.h"
#include "cfsmailmessage.h"
#include "cmrcalendarinfo.h" 
//</cmail>
//Base plugin.
#include "baseplugin.h"
#include "basepluginpanic.h"
#include "baseplugincommonutils.h"
#include "mailiterator.h"
#include "baseplugindelayedopsprivate.h"
// Other
#include <e32base.h>
#include <utf.h>
#include <calsession.h>

//<cmail>
#include "FreestyleEmailUiConstants.h"
//</cmail>

//size of the read buffer when reading body content from the quoted
//message when replying/forwarding.
const TInt KQuotedReadBufferSize = 1024*64;


/**
 *
 */
CBasePlugin* CBasePlugin::NewLC()
    {
    CBasePlugin* api = new (ELeave) CBasePlugin();
    CleanupStack::PushL( api );
    api->ConstructL();
    return api;
    } 

/**
 *
 */
CBasePlugin* CBasePlugin::NewL()
   {
   CBasePlugin* api =  CBasePlugin::NewLC();
   CleanupStack:: Pop(api);
   return api;
   }


/**
 *
 */
EXPORT_C void CBasePlugin::ConstructL()
    {
    __LOG_CONSTRUCT( "baseplugin", "CBasePlugin" )

    __LOG_ENTER( "ConstructL" )
    iMsgStore = CMsgStore::NewL( EFalse );
    
    iDelayedOpsManager = CDelayedOpsManager::NewL( *this );

    __LOG_EXIT
    }


/**
 *
 */
EXPORT_C CBasePlugin::CBasePlugin()
: iMailboxes( RMap<TInt, CMailboxInfo>::CompareInt )
   {
   }


/**
 *
 */
EXPORT_C CBasePlugin::~CBasePlugin()
    {
    //needs to be first thing to do as it might force execution of operations
    //that depend on the plugin's current state.
    delete iDelayedOpsManager;
    
    iMailboxes.ResetAndDestroy();
    iMailboxes.Close();

    if ( iObservers.Count() > 0 )
        {
        TRAP_IGNORE( iMsgStore->RemoveObserverL( this ) );
        }
    iObservers.Close();

    delete iMsgStore;

    iReqs.ResetAndDestroy();
    iReqs.Close();
    
    ResetCache();

    __LOG_DESTRUCT
    }
    

#pragma mark --- "MFSMAILPLUGIN - MAILBOX RELATED" ---


/**
 * Note that as the msgstore performs the delete immediately the observer will get
 * called from within this method.
 */
EXPORT_C void CBasePlugin::DeleteMailBoxByUidL(
    const TFSMailMsgId& aMailBoxId,
    MFSMailRequestObserver& aOperationObserver,
	const TInt aRequestId )
    {
    __LOG_ENTER( "DeleteMailBoxByUidL" )

    RPointerArray< CMsgStoreAccount > accounts;
    iMsgStore->AccountsL( accounts );
    CleanupResetAndDestroyClosePushL( accounts );

    TFSProgress progress = { TFSProgress::EFSStatus_RequestCancelled, 0, 0, 0 };
    progress.iError = KErrNotFound;

    TInt count = accounts.Count();
    for( TInt i = 0; i < count; i++ )
        {
        CMsgStoreMailBox* msbox = iMsgStore->OpenAccountL( *accounts[i] );
        CleanupStack::PushL( msbox );
      
        if( aMailBoxId.Id() == msbox->Id() )
            {
            __LOG_WRITE_INFO( "Found, about to start the delete.." )

            //remove from the cache.
            if ( KErrNotFound != iMailboxes.Find( msbox->Id() ) )
                {
                iMailboxes.RemoveL( msbox->Id() );
                }
            
            iMsgStore->DeleteAccountL( *accounts[i] );
            CleanupStack::PopAndDestroy( msbox );
            
            progress.iError = KErrNone;
            progress.iProgressStatus = TFSProgress::EFSStatus_RequestComplete;
            
            __LOG_WRITE_INFO( "Delete complete." )
            break;
            }
      
        CleanupStack::PopAndDestroy( msbox );
        }

    CleanupStack::PopAndDestroy( &accounts );

    aOperationObserver.RequestResponseL( progress, aRequestId );
    __LOG_EXIT
    }


/**
 *
 */
EXPORT_C void CBasePlugin::ListMailBoxesL( RArray<TFSMailMsgId>& aMailboxes )
    {
    __LOG_ENTER( "ListMailBoxesL" )
    
    RPointerArray< CMsgStoreAccount > accounts;
    iMsgStore->AccountsL( accounts );
    CleanupResetAndDestroyClosePushL( accounts );

    TFSMailMsgId fsid;
    fsid.SetPluginId( TUid::Uid( GetPluginId() ) );
    
    __LOG_WRITE_FORMAT1_INFO( "Plugin id: 0x%X,", GetPluginId() )
    
    TInt count = accounts.Count();
    for ( TInt i = 0; i < count; i++ )
        {
        __LOG_WRITE_FORMAT1_INFO( "Owner id: 0x%X,", accounts[i]->Owner() )
        
        if ( accounts[i]->Owner() == GetPluginId() )
            {
            CMsgStoreMailBox* msbox = iMsgStore->OpenAccountL( *accounts[i] );
            CleanupStack::PushL( msbox );

            fsid.SetId( msbox->Id() );
            aMailboxes.AppendL( fsid );
        
            __LOG_WRITE_FORMAT1_INFO( "Found mailbox with id of 0x%X,", msbox->Id() )
            __LOG_WRITE_FORMAT1_INFO( "and account name of %S.", &accounts[i]->Name() )

            CleanupStack::PopAndDestroy( msbox );
            }
        }

    CleanupStack::PopAndDestroy( &accounts );
    __LOG_EXIT
    }


/**
 *
 * @param aMailBoxId if not found leaves with KErrNotFound.
 */
EXPORT_C CFSMailBox* CBasePlugin::GetMailBoxByUidL( const TFSMailMsgId& aMailBox )
    {
    __LOG_ENTER( "GetMailBoxByUidL" )

    CMailboxInfo& mailBox = GetMailboxInfoL( aMailBox.Id() );
    
    CFSMailBox* result = CFSMailBox::NewL( aMailBox );
    CleanupStack::PushL( result ); 

    CFSMailAddress* ownMailBox = CFSMailAddress::NewLC();
    ownMailBox->SetEmailAddress( *mailBox.iMailBoxName );
    
    if ( !( mailBox.iMailBoxDisplayName->Length() ) )
        {
        ownMailBox->SetDisplayName( KNullDesC );
        result->SetName( *mailBox.iMailBoxName );
        }
    else
        {
        ownMailBox->SetDisplayName( *(mailBox.iMailBoxDisplayName) );
        result->SetName( *(mailBox.iMailBoxDisplayName) );
        }
        
    result->SetOwnMailAddressL( ownMailBox );
    
    CleanupStack::Pop( ownMailBox );

    MMRInfoProcessor* infoProcessor = CBaseMrInfoProcessor::NewL( *this );
    result->SetMRInfoProcessorL( infoProcessor );
    
    //JOJA-83VJ4L Plugins need to set the correct Calendar Database ID for MRUI to work
    //get the calendar file name from the derived class
    const TDesC& calFileName = CalendarFileName();
    if ( calFileName != KNullDesC )
        {
        //the derived class does use its own calendar file, check if that file exists
        //the file may not exist because cal sync was disabled, or the file was deleted from the calendar UI
        CCalSession* calSession = CCalSession::NewL();
        CleanupStack::PushL( calSession );
        
        TRAPD( error, calSession->OpenL( calFileName ) );
        if ( error == KErrNone )
            {
            //calendar file exists, get its file id, and set it to cMail Celendar Info via the extention
            TCalFileId fileId = KNullFileId; 
            calSession->FileIdL( fileId );
            
            //get the extention api for the MR info, set the cal db id, and release the extention
            CEmailExtension* extension = NULL;
            TRAP( error, extension = result->ExtensionL( KMailboxExtMrCalInfo ) );
            if ( error == KErrNone )
                {
                CMRCalendarInfo* calInfo = reinterpret_cast<CMRCalendarInfo*>( extension );
                calInfo->SetCalendarDatabaseIdL( fileId ); // cannot actually leave
                result->ReleaseExtension( calInfo );
                }
            }
        
        CleanupStack::PopAndDestroy( calSession );
        }
    
    CleanupStack::Pop( result );
    
    __LOG_EXIT
    return result;
    }


#pragma mark --- "MFSMAILPLUGIN - FOLDER RELATED" ---

/**
 *
 * @param aMailBoxId if not found leaves with KErrNotFound.
 */
EXPORT_C TFSMailMsgId CBasePlugin::GetStandardFolderIdL(
    const TFSMailMsgId& aMailBoxId,
    const TFSFolderType aFolderType )
    
    {
    __LOG_ENTER( "GetStandardFolderIdL" )
    
    CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );
    
    TFSMailMsgId result;
    result.SetPluginId( TUid::Uid( GetPluginId() ) );
    
    if( EFSInbox <= aFolderType && aFolderType <= EFSDeleted )
        {
        result.SetId( mailBox.iRootFolders.iFolders[ aFolderType ] );
        }

    __LOG_EXIT
    return result;
    }


/**
 * Note that the unseen count is not set by the plugin as this information is not
 * readily available.
 *
 * @param aMailBoxId if not found leaves with KErrNotFound.
 */
EXPORT_C CFSMailFolder* CBasePlugin::GetFolderByUidL(
    const TFSMailMsgId& aMailBoxId,
    const TFSMailMsgId& aFolderId )

    {
    __LOG_ENTER( "GetFolderByUidL" )
    
    CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );

    TUint totalCount, unreadCount;
    mailBox().MessageCountsL( aFolderId.Id(), totalCount, unreadCount );

    //prepare the fsfw folder.
    CFSMailFolder* result = CFSMailFolder::NewLC( aFolderId );

    result->SetMailBoxId( aMailBoxId );
    result->SetMessageCount( totalCount );
    result->SetUnreadCount( unreadCount );

    //get the folder name from the msgstore folder object.
    __LOG_WRITE_INFO( "About to get the folder's name." )
    CMsgStoreFolder* msgStoreFolder = mailBox().FolderL( aFolderId.Id() );
    CleanupStack::PushL( msgStoreFolder );

    TUint idx;
    if ( msgStoreFolder->FindProperty( KMsgStorePropertyFolderDisplayName, idx ) )
        {
        const TDesC& name = msgStoreFolder->PropertyValueDesL( idx );
        result->SetFolderName( const_cast<TDesC&>( name ) );
        }
    else
        {
        //the root folders will get names from the UI. the base plugin should not
        //deal with any localization.
        result->SetFolderName( KNullDesC() );
        }

    TFSFolderType folderType = EFSOther;
    TUint i = 0;
    if ( msgStoreFolder->FindProperty( KMsgStorePropertyFolderType, i ) )
        {
        __LOG_WRITE_INFO( "Getting the folder's type." )
        folderType = (TFSFolderType)( msgStoreFolder->PropertyValueUint32L( i ) );
        result->SetFolderType( folderType );
        }

    TFSMailMsgId parentId( GetPluginId(), msgStoreFolder->ParentId() );
    result->SetParentFolderId( parentId );
    CleanupStack::PopAndDestroy( msgStoreFolder );

    RPointerArray<CMsgStoreFolder> folders;
    CleanupResetAndDestroyClosePushL( folders );
    
    mailBox().FoldersL( aFolderId.Id(), folders );
    result->SetSubFolderCount( folders.Count() );
    
    BlockCopyMoveFromFoldersL( aFolderId, folderType, *result );

    CleanupStack::PopAndDestroy( &folders );
    CleanupStack::Pop( result );

    __LOG_EXIT
    return result;
    } //GetFolderByUidL.


/**
 * @param aFolderId parent folder id.
 * @param aMailBoxId if not found leaves with KErrNotFound.
 * @return if the folder already exists returns the existing one.
 */
EXPORT_C CFSMailFolder* CBasePlugin::CreateFolderL(
    const TFSMailMsgId& aMailBoxId,
    const TFSMailMsgId& aParentFolderId,
    const TDesC& aFolderName,
    const TBool aSync )

    {
    __LOG_ENTER( "CreateFolderL" )
    
    CMailboxInfo& mailboxInfo = GetMailboxInfoL( aMailBoxId.Id() );

    CMsgStorePropertyContainer* props = CMsgStorePropertyContainer::NewL();
    CleanupStack::PushL( props );

    props->AddPropertyL( KMsgStorePropertyName, aFolderName );
    props->AddPropertyL( KMsgStorePropertyFolderType, EMsgStoreOther );

    TMsgStoreId parent = aParentFolderId.Id();
    TMsgStoreId folderId =
        mailboxInfo().CreateFolderL( parent, *props, aSync );
    CleanupStack::PopAndDestroy( props );

    //return the FS folder.
    TFSMailMsgId fid( GetPluginId(), folderId );

    CFSMailFolder* result = CFSMailFolder::NewLC( fid );

    result->SetParentFolderId( aParentFolderId );
    result->SetFolderName( aFolderName );

    result->SetMailBoxId( aMailBoxId );
    result->SetMessageCount( 0 );
    result->SetUnreadCount( 0 );

    BlockCopyMoveFromFoldersL( fid, EFSOther, *result );
    
    CleanupStack::Pop( result );
    __LOG_EXIT
    return result;
    }


/**
 *
 * @param aMailBoxId if not found leaves with KErrNotFound.
 */
EXPORT_C void CBasePlugin::DeleteFolderByUidL(
    const TFSMailMsgId& aMailBoxId,
    const TFSMailMsgId& aFolder )
    
    {
    __LOG_ENTER( "DeleteFolderByUidL" )

    CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );
    mailBox().DeleteFolderL( aFolder.Id() );
    
    __LOG_EXIT
    }

/**
 *
 */
EXPORT_C void CBasePlugin::ListFoldersL(
    const TFSMailMsgId& aMailBoxId,
    const TFSMailMsgId& aFolderId,
    RPointerArray<CFSMailFolder>& aFolderList )
    
    {
    __LOG_ENTER( "ListFoldersL, aFolderId" )
    
    TMsgStoreId folderId;
    if ( 0 == aFolderId.Id() )
    	{
    	folderId = aMailBoxId.Id();
    	}
    else
    	{
    	folderId = aFolderId.Id();
    	}
    
	DoListFoldersL( aMailBoxId, folderId, EFalse, aFolderList );
    __LOG_EXIT 
    }

/**
 *
 */
EXPORT_C void CBasePlugin::ListFoldersL(
    const TFSMailMsgId& aMailBoxId,
    RPointerArray<CFSMailFolder>& aFolderList )
    
    {
    __LOG_ENTER( "ListFoldersL" )
    DoListFoldersL( aMailBoxId, KMsgStoreInvalidId, ETrue, aFolderList );
    __LOG_EXIT
    }


#pragma mark --- "MFSMAILPLUGIN - MESSAGE RELATED" ---


/**
 *
 * @param aMailBoxId if not found leaves with KErrNotFound.
 */
EXPORT_C MFSMailIterator* CBasePlugin::ListMessagesL(
    const TFSMailMsgId& aMailBoxId,
    const TFSMailMsgId& aFolderId,
    const TFSMailDetails aDetails,
    const RArray<TFSMailSortCriteria>& aSorting )
   
    {
    __LOG_ENTER( "ListMessagesL" )
    
    CMailboxInfo& mailbox = GetMailboxInfoL( aMailBoxId.Id() );
    
    RMsgStoreSortCriteria criteria;
    CleanupClosePushL( criteria );
 
    criteria.iFolderId = aFolderId.Id();
    if( aSorting.Count() > 0 )
        {
        criteria.iSortBy = static_cast<TMsgStoreSortByField>( aSorting[0].iField - 1);
        criteria.iSortOrder = static_cast<TMsgStoreSortOrder>( aSorting[0].iOrder );
        criteria.iSecondarySortOrder = EMsgStoreSortDescending;
        }
    else
        {
        __LOG_WRITE_INFO( "No sorting criteria supplied, falling back to the default." )
        criteria.iSortBy = EMsgStoreSortByReceivedDate;
        criteria.iSortOrder = EMsgStoreSortDescending;
        }
    
    //determine the details to request from the msgstore.
    if ( EFSMsgDataStructure & aDetails || EFSMsgDataEnvelope & aDetails
        || EFSMsgDataSubject & aDetails )
        {
        criteria.AddResultPropertyL( KMsgStorePropertySubject );
        }

    if ( EFSMsgDataStructure & aDetails || EFSMsgDataEnvelope & aDetails
        || EFSMsgDataDate & aDetails )
        {
        criteria.AddResultPropertyL( KMsgStorePropertyReceivedAt );
        criteria.AddResultPropertyL( KMsgStorePropertySent );
        }

    if ( EFSMsgDataStructure & aDetails || EFSMsgDataEnvelope & aDetails
        || EFSMsgDataSender & aDetails )
        {
        criteria.AddResultPropertyL( KMsgStorePropertyFrom );
        }
    
    if ( EFSMsgDataStructure & aDetails || EFSMsgDataEnvelope & aDetails
        || EFSMsgDataIdOnly & aDetails )
        {
        /**@ no result properties added means the msgstore leaves with -6; ask
        about it because EFSMsgDataIdOnly means id-only.*/
        criteria.AddResultPropertyL( KMsgStorePropertyTo );
        }

    if ( EFSMsgDataStructure & aDetails || EFSMsgDataEnvelope & aDetails )
        {
        criteria.AddResultPropertyL( KMsgStorePropertyFlags );
        criteria.AddResultPropertyL( KMsgStorePropertySize );
        criteria.AddResultPropertyL( KMsgStorePropertyCc );
        criteria.AddResultPropertyL( KMsgStorePropertyBcc );
        }

    CMsgStoreSortResultIterator* msIter = mailbox().SortL( criteria );
    CleanupStack::PopAndDestroy( &criteria );

    CleanupStack::PushL( msIter );
    HMailIterator* result = new (ELeave) HMailIterator( *this, msIter, aMailBoxId );
    CleanupStack::Pop( msIter );
    
    __LOG_EXIT
    return result;
    }

/**
 *
 * @param aMailBoxId if not found leaves with KErrNotFound.
 */
EXPORT_C CFSMailMessage* CBasePlugin::GetMessageByUidL(
    const TFSMailMsgId& aMailBoxId,
    const TFSMailMsgId& /*aFolderId*/,
    const TFSMailMsgId& aMessageId,
    const TFSMailDetails aDetails )
    
    {
    __LOG_ENTER( "GetMessageByUidL" )
    
    CMsgStoreMessage* message = GetCachedMsgL( aMailBoxId.Id(), aMessageId.Id() );

    CFSMailMessage* result = CFSMailMessage::NewLC( aMessageId );
    TranslateMsgStorePropsL( aMailBoxId, *message, *result, aDetails );
    result->SetMailBoxId( aMailBoxId );
    CleanupStack::Pop( result );

    __LOG_EXIT
    return result;
    }


/**
 *
 * @param aMailBoxId if not found leaves with KErrNotFound.
 */
EXPORT_C void CBasePlugin::DeleteMessagesByUidL(
    const TFSMailMsgId& aMailBoxId,
    const TFSMailMsgId& aFolderId,
    const RArray<TFSMailMsgId>& aMessages )
    
    {
    __LOG_ENTER( "DeleteMessagesByUidL" )

    CDelayedDeleteMessagesOp* delayedOp = CDelayedDeleteMessagesOp::NewLC(
        aMailBoxId.Id(), aFolderId.Id(), aMessages );
    iDelayedOpsManager->EnqueueOpL( delayedOp );
    CleanupStack::Pop( delayedOp );

    __LOG_EXIT
    }


/**
 * Drafts folder assumed.
 *
 * @param aMailBoxId if not found leaves with KErrNotFound.
 */
EXPORT_C CFSMailMessage* CBasePlugin::CreateMessageToSendL(
    const TFSMailMsgId& aMailBox )
    
    {
    __LOG_ENTER( "CreateMessageToSendL" )
    
    CMailboxInfo& mailboxInfo = GetMailboxInfoL( aMailBox.Id() );

    CMsgStorePropertyContainer* props = CMsgStorePropertyContainer::NewL();
    CleanupStack::PushL( props );
    props->AddOrUpdatePropertyL( KMsgStorePropertyContentType, KFSMailContentTypeMultipartMixed );

    // Set reply-to address, if it exists
    HBufC* replyToAddressString = GetReplyToAddressL( aMailBox );
    
    if ( NULL != replyToAddressString )
        {
        CleanupStack::PushL( replyToAddressString );
        
        if ( replyToAddressString->Length() > 0 )
            {
            RMsgStoreAddress replyToAddress;
            CleanupClosePushL( replyToAddress );
            
            replyToAddress.iEmailAddress.Create( *replyToAddressString );
            replyToAddress.iDisplayName.Create( KNullDesC );
            
            props->AddOrUpdatePropertyL( KMsgStorePropertyReplyTo, replyToAddress );
            
            CleanupStack::PopAndDestroy( &replyToAddress );
            }        
        CleanupStack::PopAndDestroy( replyToAddressString );
        }
    
    CMsgStoreMessage* message = mailboxInfo().CreateMessageL(
        mailboxInfo.iRootFolders.iFolders[EFSDraftsFolder], *props );

    CleanupStack::PopAndDestroy( props );
    CleanupStack::PushL( message );
    
    //create the body part.
    props = CMsgStorePropertyContainer::NewL();
    CleanupStack::PushL( props );
    
    props->AddOrUpdatePropertyL(
        KMsgStorePropertyContentType, KFSMailContentTypeMultipartAlternative );
    CMsgStoreMessagePart* bodyPart = message->AddChildPartL( *props );
    
    CleanupStack::PopAndDestroy( props );
    CleanupStack::PushL( bodyPart );
    
    //create the plain text part.
    props = CMsgStorePropertyContainer::NewL();
    CleanupStack::PushL( props );

    props->AddPropertyL(
        KMsgStorePropertyContentType, KFSMailContentTypeTextPlain );

    _LIT(KMessageBodyCharset, "UTF-8");
    props->AddPropertyL( KMsgStorePropertyCharset, KMessageBodyCharset );

    _LIT(KMessageBodyDisposition, "inline");
    props->AddPropertyL(
        KMsgStorePropertyContentDisposition, KMessageBodyDisposition );

    HBufC* signature = GetSignatureL( aMailBox );
    if ( signature )
        {
        CleanupStack::PushL( signature );       

        props->AddPropertyL(
            KMsgStorePropertySize, static_cast<TUint32>( signature->Length() ) );
        props->AddPropertyL(
            KMsgStorePropertyRetrievedSize,
            static_cast<TUint32>( signature->Length() ) );
        }
    
    CMsgStoreMessagePart* textPlain = bodyPart->AddChildPartL( *props );
    if ( signature )
        {
        CleanupStack::Pop( signature );
        }
    CleanupStack::PopAndDestroy( props );           
    if ( signature )
        {
        CleanupStack::PushL( signature );
        }
    CleanupStack::PushL( textPlain );
    
    //add signature, if it exists
	if ( NULL != signature && signature->Length() )
        {
        TPtrC8 ptr8(
            reinterpret_cast<const TUint8*>( signature->Ptr() ),
            signature->Size() );
        
        textPlain->ReplaceContentL( ptr8 );
		}

	CleanupStack::PopAndDestroy( textPlain );
    if ( signature )
        {
        CleanupStack::PopAndDestroy( signature );
        }
    CleanupStack::PopAndDestroy( bodyPart );
	
	//done.
    message->CommitL();
    
    TFSMailMsgId folderId( GetPluginId(), message->ParentId() );
    TFSMailMsgId msgId( GetPluginId(), message->Id() );
    CleanupStack::PopAndDestroy( message );

    CFSMailMessage* result = CFSMailMessage::NewL( msgId );    
    
    result->SetMailBoxId( aMailBox );
    result->SetFolderId( folderId );
    result->SetContentType( KFSMailContentTypeMultipartMixed );
    
    __LOG_EXIT
    return result;
    }


/**
 *
 */
EXPORT_C CFSMailMessage* CBasePlugin::CreateForwardMessageL(
    const TFSMailMsgId& aMailBox,
    const TFSMailMsgId& aOriginal,
    const TDesC& aHeaderDescriptor )
    {
    return CreateForwardReplyMessageL( aMailBox, aOriginal, EFalse, aHeaderDescriptor, ETrue );
    }


/**
 * Relying on the UI for the subject and recipients.
 */
EXPORT_C CFSMailMessage* CBasePlugin::CreateReplyMessageL(
    const TFSMailMsgId& aMailBoxId,
    const TFSMailMsgId& aOriginalMessageId,
    const TBool aReplyToAll,
    const TDesC& aHeaderDescriptor )
    {
    return CreateForwardReplyMessageL( aMailBoxId, aOriginalMessageId, aReplyToAll, aHeaderDescriptor, EFalse );
    }


/**
 *
 */
EXPORT_C CFSMailMessage* CBasePlugin::CreateMrReplyMessageL(
    const TFSMailMsgId& aMailBoxId,
    MMRInfoObject& /*aMeetingRequest*/,
    const TFSMailMsgId& aOriginalMessageId )
    {
    return CreateReplyMessageL( aMailBoxId, aOriginalMessageId, EFalse, KNullDesC );
    }


/**
 *
 * @param aMailBoxId if not found leaves with KErrNotFound.
 */
EXPORT_C void CBasePlugin::StoreMessageL(
    const TFSMailMsgId& aMailBoxId,
    CFSMailMessage& aMessage )
    
    {
    __LOG_ENTER( "StoreMessageL" )
    
    CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );

    CMsgStoreMessage* message = mailBox().FetchMessageL(
        aMessage.GetMessageId().Id(), KMsgStoreInvalidId );
    CleanupStack::PushL( message );

    //determine whether the message is in the inbox folder or some of its
    //children; the translation is different for inbox and all the other folders.
    TBool inInbox = EFalse;
    TMsgStoreId parentId = message->ParentId();
    while ( KMsgStoreInvalidId != parentId
    	&& EMsgStoreFolderContainer == mailBox().ContainerTypeById( parentId ) )
    	{
    	if ( parentId == mailBox.iRootFolders.iFolders[EFSInbox] )
    		{
    		inInbox = ETrue;
    		break;
    		}
    	else
    		{
    		CMsgStoreFolder* parent = mailBox().FolderL( parentId );
    		parentId = parent->ParentId();
    		delete parent;
    		}
    	}
    
    TranslateEmailFwMessageL( aMessage, *message, inInbox );
    message->StorePropertiesL();
    
    CleanupStack::PopAndDestroy( message );
    
    ResetCache();
    __LOG_EXIT
    }


/**
 * Async operation, starts fetching.
 * @param aRequestId
 */
EXPORT_C void CBasePlugin::FetchMessagesL(
    const TFSMailMsgId& /*aMailBox*/,
    const TFSMailMsgId& /*aFolder*/,
    const RArray<TFSMailMsgId>& /*aMessageIds*/,
    TFSMailDetails /*aDetails*/,
    MFSMailRequestObserver& /*aObserver*/,
    TInt /*aRequestId*/ )

    {
    /**@ is this really necessary for the base plugin ?*/
    }


/**
 *
 */
EXPORT_C void CBasePlugin::GetMessagesL(
    const TFSMailMsgId& /*aMailBoxId*/,
    const TFSMailMsgId& /*aParentFolderId*/,
    const RArray<TFSMailMsgId>& /*aMessageIds*/,
    RPointerArray<CFSMailMessage>& /*aMessageList*/,
    const TFSMailDetails /*aDetails*/ )
    
    {
    /**@ is this really necessary for the base plugin ?*/
    }


/**
 * CFSMailPlugin::SendMessageL
 */
EXPORT_C void CBasePlugin::SendMessageL( CFSMailMessage& aMessage )    
    {
    __LOG_ENTER( "SendMessageL1" )

    TMsgStoreId mailBoxId = aMessage.GetMailBoxId().Id();
    TMsgStoreId msgId = aMessage.GetMessageId().Id();
    
    CMsgStoreMessage* message = GetCachedMsgL( mailBoxId, msgId );
    __LOG_WRITE8_FORMAT1_INFO( "Fetched message : 0x%X.", msgId )

    TranslateEmailFwMessageL( aMessage, *message, EFalse );
    //the sendmessagel will store the message's properties!

    TTime sentTime;
    sentTime.UniversalTime();
    aMessage.SetDate( sentTime );

    CMailboxInfo& mailBox = GetMailboxInfoL( aMessage.GetMailBoxId().Id() );
    SendMessageL( mailBox(), *message, sentTime );

    __LOG_EXIT
    }


/**
 * Plugin could use this method to "send" a message if the CFSMailPlugin's is
 * not necessary. The method also stores the message properties before doing so.
 * This allows for optimizing away of unnecessary writes to the msgstore.
 * @param aSentTime the sent time you want set for the message.
 */
EXPORT_C void CBasePlugin::SendMessageL(
    CMsgStoreMailBox& aMailBox,
    CMsgStoreMessage& aMsg,
    const TTime& aSentTime )    
    {
    __LOG_ENTER( "SendMessageL2" )

    //set the sent stamp.
    aMsg.AddOrUpdatePropertyL( KMsgStorePropertySent, aSentTime );
    // Due to no Received Time in the sent messages, it caused sorting problem
    // from MsgStore
    aMsg.AddOrUpdatePropertyL( KMsgStorePropertyReceivedAt, aSentTime );
    aMsg.StorePropertiesL();

    // move the msg to the outbox.
    TFSMailMsgId id( GetPluginId(), aMailBox.Id() );
    TFSMailMsgId drafts = GetStandardFolderIdL( id, EFSDraftsFolder );
    TFSMailMsgId outbox = GetStandardFolderIdL( id, EFSOutbox );

    aMailBox.CopyMessageL( aMsg.Id(), drafts.Id(), outbox.Id() );
    
    CDelayedDeleteMessagesOp* delayedOp = CDelayedDeleteMessagesOp::NewLC(
        aMailBox.Id(), KMsgStoreInvalidId, aMsg.Id() );
    iDelayedOpsManager->EnqueueOpL( delayedOp );
    CleanupStack::Pop( delayedOp );

    __LOG_EXIT
    }

/**
 *
 */
EXPORT_C void CBasePlugin::MoveMessagesL(
    const TFSMailMsgId& aMailBoxId,
    const RArray<TFSMailMsgId>& aMessageIds,
    const TFSMailMsgId& aSourceFolderId,
    const TFSMailMsgId& aDestinationFolderId )

    {
    CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );

    TInt count = aMessageIds.Count();
    for ( TUint i = 0; i < count; i++ )
        {
        mailBox().MoveMessageL(
            aMessageIds[i].Id(),
            aSourceFolderId.Id(),
            aDestinationFolderId.Id() );
        }    
    }


/**
 *
 */
EXPORT_C void CBasePlugin::CopyMessagesL(
    const TFSMailMsgId& aMailBoxId,
    const RArray<TFSMailMsgId>& aMessageIds,
    RArray<TFSMailMsgId>& aNewMessages,
    const TFSMailMsgId& aSourceFolderId,
    const TFSMailMsgId& aDestinationFolderId )

    {
    CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );

    TFSMailMsgId newId( GetPluginId(), KMsgStoreInvalidId );
    
    TInt count = aMessageIds.Count();
    for ( TUint i = 0; i < count; i++ )
        {
        TMsgStoreId msgStoreId = mailBox().CopyMessageL(
            aMessageIds[i].Id(),
            aSourceFolderId.Id(),
            aDestinationFolderId.Id() );
        
        newId.SetId( msgStoreId );
        aNewMessages.AppendL( newId );
        }
    }


#pragma mark --- "Plugin Helpers" ---


/**
 * Get the MsgStore mailbox instance for the specified FSEF mailbox id.
 *
 * @param aId mailbox id, if none can be found leaves with KErrNotFound.
 */
EXPORT_C CMailboxInfo& CBasePlugin::GetMailboxInfoL(
    TMsgStoreId aId )
    {
    
    __ASSERT_DEBUG( NULL != iMsgStore, ::BasePluginPanic( ENoMsgStoreSessionAssert ) );
    
    //if not present in the cache, add it.
    if ( !iMailboxes.ContainsKey(aId) )
        {
        RPointerArray< CMsgStoreAccount > accounts;
        iMsgStore->AccountsL( accounts );
        CleanupResetAndDestroyClosePushL( accounts );

        TBool found = EFalse;

        TInt count = accounts.Count();
        for ( TInt i = 0; i < count; i++ )
            {
            CMsgStoreMailBox* msbox = iMsgStore->OpenAccountL( *accounts[i] );
            CleanupStack::PushL( msbox );

            if ( aId == msbox->Id() )
                {
                CMailboxInfo* mailBox = new (ELeave) CMailboxInfo( this );
                CleanupStack::PushL( mailBox );
                mailBox->iMailBox = msbox;
                //always observe for mailbox changes to keep the cache
                //up-to-date.
                mailBox->iMailBox->AddObserverL( this );

                mailBox->iMailBoxName = accounts[i]->Name().AllocL();
                mailBox->iBrandingId = KNullDesC().AllocL();
                
                RBuf mailboxDisplayName;
                mailboxDisplayName.CleanupClosePushL();
                GetMailboxDisplayNameL( aId, mailboxDisplayName );
                mailBox->iMailBoxDisplayName = mailboxDisplayName.AllocL();
                CleanupStack::PopAndDestroy( &mailboxDisplayName );
                
                MsgStoreFolderUtils::GetRootFoldersL( *msbox, mailBox->iRootFolders );

                TInt64* key = new (ELeave) TInt64( msbox->Id() );
                CleanupDeletePushL( key );
                iMailboxes.InsertL( key, mailBox );   //the map owns the memory.

                CleanupStack::Pop( key );
                CleanupStack::Pop( mailBox );
                CleanupStack::Pop( msbox );
                
                found = ETrue;
                break;
                }

            CleanupStack::PopAndDestroy( msbox );
            }

        CleanupStack::PopAndDestroy( &accounts );
        
        if( !found )
            {
            User::Leave( KErrNotFound );
            }
        }
    
    return iMailboxes.GetValueL( aId );
    } //GetMailboxInfoL.


/**
 * Get the MsgStore mailbox instance for the specified FSEF mailbox id.
 *
 * @param aId mailbox id, if none can be found leaves with KErrNotFound.
 */
void CBasePlugin::GetMailboxDisplayNameL(
    TMsgStoreId aId,
    RBuf& aDisplayName )
    {
    
    __ASSERT_DEBUG( NULL != iMsgStore, ::BasePluginPanic( ENoMsgStoreSessionAssert ) );
    
    RPointerArray< CMsgStoreAccount > accounts;
    iMsgStore->AccountsL( accounts );
    CleanupResetAndDestroyClosePushL( accounts );

    TInt count = accounts.Count();
    for ( TInt i = 0; i < count; i++ )
        {
        CMsgStoreMailBox* msbox = iMsgStore->OpenAccountL( *accounts[i] );
        CleanupStack::PushL( msbox );

        if( aId == msbox->Id() )
            {
            TUint index = 0;
            if ( msbox->FindProperty( KMsgStorePropertyName, index ) )
                {
                    const TDesC& string = msbox->PropertyValueDesL( index );
                    if (string.Length() > 0)
                        {
                        aDisplayName.Close();
                        aDisplayName.CreateL( string );
                        }
                }
                CleanupStack::PopAndDestroy( msbox );
                break;
            }
        else
            {
	             CleanupStack::PopAndDestroy( msbox );
	        }
        }

        CleanupStack::PopAndDestroy( &accounts );
    } //GetMailboxDisplayNameL.

/**
 * @param aFolderId if set to KMsgStoreInvalidId makes a recursive list.
 */
void CBasePlugin::DoListFoldersL(
    TFSMailMsgId aMailBoxId,
    TMsgStoreId aFolderId,
    TBool aRecursive,
    RPointerArray<CFSMailFolder>& aFolderList )
    
    {
    CMailboxInfo& mailBox = GetMailboxInfoL( aMailBoxId.Id() );
    
    RPointerArray<CMsgStoreFolder> folders;
    CleanupResetAndDestroyClosePushL( folders );
    
    if ( aRecursive )
        {
        mailBox().FoldersL( folders );
        }
    else
        {
        mailBox().FoldersL( aFolderId, folders );
        }
    
    TFSMailMsgId folderId;
    folderId.SetPluginId( TUid::Uid( GetPluginId() ) );
    
    TInt count = folders.Count();
    for( TInt i = 0; i < count; i++ )
        {
        folderId.SetId( folders[i]->Id() );
        
        CFSMailFolder* folder = GetFolderByUidL( aMailBoxId, folderId );

        CleanupStack::PushL( folder );
        aFolderList.AppendL( folder );
        CleanupStack::Pop( folder );
        }
    
    CleanupStack::PopAndDestroy( &folders );
    }


/**
 *
 */
CFSMailAddress* CBasePlugin::FetchEmailAddressL(
    CMsgStorePropertyContainer& aMessage,
    TUint aIdx )

    {
    RMsgStoreAddress value;
    CleanupClosePushL( value );

    aMessage.PropertyValueAddressL( aIdx, value );

    CFSMailAddress* result = CFSMailAddress::NewL();
    result->SetEmailAddress( value.iEmailAddress );
    if ( KNullDesC() != value.iDisplayName )
        {
        result->SetDisplayName( value.iDisplayName );
        }
    else
        {
        /**@ the UI would crash if there was no display name.*/
        result->SetDisplayName( value.iEmailAddress );
        }

    CleanupStack::PopAndDestroy( &value );
    
    return result;
    }


/**
 *
 */
EXPORT_C CMsgStoreMessagePart* CBasePlugin::GetBodyPartL(
    CMsgStoreMessage& aMessage,
    const TDesC& aContentType )
    {
    CMsgStoreMessagePart* result = NULL;
    
    RPointerArray<CMsgStoreMessagePart> parts;
    CleanupResetAndDestroyClosePushL( parts );

    aMessage.ChildPartsL( parts );
    if ( 0 < parts.Count() )
        {
        RPointerArray<CMsgStoreMessagePart> childParts;
        CleanupResetAndDestroyClosePushL( childParts );
        parts[0]->ChildPartsL( childParts );
        
        TInt count = childParts.Count();
        if ( 0 < count )
            {
            for ( TInt i = 0; i < count; i++ )
                {
                TUint idx = 0;
                if ( childParts[i]->FindProperty( KMsgStorePropertyContentType, idx, idx ) )
                    {
                    const TDesC& contentType = childParts[i]->PropertyValueDesL( idx );
                    if ( contentType == aContentType )
                        {
                        result = childParts[i];
                        childParts.Remove( i );
                        break;
                        }
                    }
                }
            
            }
        else
            {
            TUint idx = 0;
            if ( parts[0]->FindProperty( KMsgStorePropertyContentType, idx, idx ) )
                {
                const TDesC& contentType = parts[0]->PropertyValueDesL( idx );
                if ( contentType == aContentType )
                    {
                    result = parts[0];
                    parts.Remove( 0 );
                    }
                }
            }
            
        CleanupStack::PopAndDestroy( &childParts );
        }
        
    CleanupStack::PopAndDestroy( &parts );

    return result;
    } //GetBodyPartL.

/**
 *
 */
EXPORT_C CFSMailMessage* CBasePlugin::CreateForwardReplyMessageL(
    const TFSMailMsgId& aMailBox,
    const TFSMailMsgId& aOriginal,
    const TBool aReplyToAll,
    const TDesC& aHeaderDescriptor,
    TBool aKeepAttachments,
    TBool aKeepMeetingRequestInfo )
    {
    __LOG_ENTER( "CreateForwardReplyMessageL" )
    CMailboxInfo& mailBox = GetMailboxInfoL( aMailBox.Id() );

    CMsgStoreMessage* message = mailBox().FetchMessageL(
        aOriginal.Id(), KMsgStoreInvalidId );
    CleanupStack::PushL( message );

    TMsgStoreId newMsgId = mailBox().CopyMessageL(
        aOriginal.Id(), message->ParentId(),
        mailBox.iRootFolders.iFolders[EFSDraftsFolder] );
    
    CMsgStoreMessage* newMsg = mailBox().FetchMessageL( newMsgId, KMsgStoreInvalidId );
    CleanupStack::PushL( newMsg );

    if ( !aReplyToAll )
        {
        //Clear all To, Cc addresses for Reply, Forward
        RemoveAllPropertiesL( *newMsg, KMsgStorePropertyTo );
        RemoveAllPropertiesL( *newMsg, KMsgStorePropertyCc );
        }
    else
        {
        //Remove the mailbox address from the reply to addresses
        HBufC* mailBoxAdd = GetMailBoxAddressL( aMailBox );
        CleanupStack::PushL( mailBoxAdd );
        
        if ( NULL != mailBoxAdd )
            {           
            TUint idx1 = 0;
            while (newMsg->FindProperty( KMsgStorePropertyTo, idx1, idx1 ) )
                {
                RMsgStoreAddress tempAdd;
                CleanupClosePushL( tempAdd );
                
                newMsg->PropertyValueAddressL( idx1, tempAdd );
                if ( tempAdd.iEmailAddress == *mailBoxAdd )
                    {
                    newMsg->RemovePropertyL( idx1 );
                    CleanupStack::PopAndDestroy( &tempAdd );
                    break;
                    }
                CleanupStack::PopAndDestroy( &tempAdd );
                ++idx1;
                }
        
            idx1 = 0;
            while (newMsg->FindProperty( KMsgStorePropertyCc, idx1, idx1 ) )
                {
                RMsgStoreAddress tempAdd;
                CleanupClosePushL( tempAdd );
                        
                newMsg->PropertyValueAddressL( idx1, tempAdd );
                if ( tempAdd.iEmailAddress == *mailBoxAdd )
                    {
                    newMsg->RemovePropertyL( idx1 );
                    CleanupStack::PopAndDestroy( &tempAdd );
                    break;
                    }
                CleanupStack::PopAndDestroy( &tempAdd );
                ++idx1;
                } 
            }
        
        CleanupStack::PopAndDestroy( mailBoxAdd );
        }
    
	SetReplyOrForwardToFieldL( *newMsg );

    //Clear the response flag.
	TUint idx = 0;
    if ( newMsg->FindProperty( KMsgStorePropertyFlags, idx ) )
        {
        TUint32 flags = newMsg->PropertyValueUint32L( idx );
        flags &= ~EFSMsgFlag_Answered;
        newMsg->AddOrUpdatePropertyL( KMsgStorePropertyFlags, flags );
        }

    //Clear the From field, ReplyTo field
    RemoveAllPropertiesL( *newMsg, KMsgStorePropertyFrom );
    RemoveAllPropertiesL( *newMsg, KMsgStorePropertyReplyTo );
    
    //Use reply-to address, if it exists
    HBufC* replyToAddressString = GetReplyToAddressL( aMailBox );
       
    if ( NULL != replyToAddressString )
        {
        CleanupStack::PushL( replyToAddressString );
           
        if ( replyToAddressString->Length() > 0 )
            {
            RMsgStoreAddress replyToAddress;
            CleanupClosePushL( replyToAddress );
               
            replyToAddress.iEmailAddress.Create( *replyToAddressString );
            replyToAddress.iDisplayName.Create( KNullDesC );
               
            newMsg->AddOrUpdatePropertyL( KMsgStorePropertyReplyTo, replyToAddress );
               
            CleanupStack::PopAndDestroy( &replyToAddress );
            }
        CleanupStack::PopAndDestroy( replyToAddressString );
       }
          
    newMsg->StorePropertiesL();

    //deal with the attachments accordingly.
    /**@ the case where the attachments haven't been downloaded but some smart
     * reply/fw tag is present in the msg body needs to be dealt with in the specific
     * plugins.*/
    if ( aKeepAttachments == EFalse )
        {
        RPointerArray<CMsgStoreMessagePart> parts;
        CleanupResetAndDestroyClosePushL( parts );

        newMsg->ChildPartsL( parts );
        TInt count = parts.Count();

        for ( TInt i = 1; i < count; i++ )
            {
            newMsg->RemoveChildPartL( parts[i]->Id() );
            }
            
        CleanupStack::PopAndDestroy( &parts );
        }

    if ( aKeepMeetingRequestInfo == EFalse )
    	{
    	idx = 0;
    	if ( newMsg->FindProperty( KMsgStorePropertyMeetingRequest, idx ) )
    		{
    		CBasePlugin::RemoveAllPropertiesL( *newMsg, KMsgStorePropertyMeetingRequest );
    		}
    	}
    
    CFSMailMessage* result = CFSMailMessage::NewL(
        TFSMailMsgId( GetPluginId(), newMsgId ) );
    CleanupStack::PushL( result );
    
    TranslateMsgStorePropsL( aMailBox, *newMsg, *result );
    result->SetMailBoxId( aMailBox );

    /**@ candidate for refactoring out to a separate body dealing method.*/
    CMsgStoreMessagePart* srcPart = GetBodyPartL( *message );
    if ( NULL != srcPart )
        {
        CleanupStack::PushL( srcPart );
        CMsgStoreMessagePart* dstPart = GetBodyPartL( *newMsg );

        if ( NULL != dstPart )
            {
            CleanupStack::PushL( dstPart );
            
            HBufC* signature = GetSignatureL( aMailBox );
            if ( NULL != signature )
                {
                CleanupStack::PushL( signature );
                TPtrC8 ptr8(
                    reinterpret_cast<const TUint8*>( signature->Ptr() ),
                    signature->Size() );
                dstPart->ReplaceContentL( ptr8 );
                CleanupStack::PopAndDestroy( signature );

                __LOG_WRITE_INFO( "Set the email signature." )
                }

            //the quoted message header.
            if ( aHeaderDescriptor != KNullDesC )
                {
                TPckgBuf<TReplyForwardParams> rfParsPckg;
                rfParsPckg.Copy( aHeaderDescriptor );
                
                TPtrC8 ptrHeader8(
                    reinterpret_cast<const TUint8*>( rfParsPckg().iHeader->Ptr() ),
                    rfParsPckg().iHeader->Size() );
                NULL != signature ? dstPart->AppendToContentL( ptrHeader8 )
                    : dstPart->ReplaceContentL( ptrHeader8 );

                __LOG_WRITE8_FORMAT1_INFO(
                    "Original body content length: %d.", srcPart->ContentLengthL() )

                //copy the body content from the original.
                TInt startOffset = 0;
                RBuf8 buf;
                buf.Create( KQuotedReadBufferSize );
                CleanupClosePushL( buf );

                do
                    {
                    srcPart->FetchContentToBufferL( buf, startOffset );
                    dstPart->AppendToContentL( buf );
                    
                    startOffset += buf.Size();
                    }
                while ( buf.Size() == KQuotedReadBufferSize );

                CleanupStack::PopAndDestroy( &buf );

                TInt newFetchedSize = dstPart->ContentLengthL();
                __LOG_WRITE8_FORMAT1_INFO(
                    "Reply/fw body content length: %d.", newFetchedSize )

                TInt idx = dstPart->AddOrUpdatePropertyL(
                    KMsgStorePropertySize, static_cast<TUint32>( newFetchedSize ) );
                dstPart->StorePropertyL( idx );
                idx = dstPart->AddOrUpdatePropertyL(
                    KMsgStorePropertyRetrievedSize, static_cast<TUint32>( newFetchedSize ) );
                dstPart->StorePropertyL( idx );
                
                result->SetContentSize( newFetchedSize );
                result->SetFetchedContentSize( newFetchedSize );

                //determine whether the original msg was truncated.
                TBool wasTruncated = EFalse;
                TUint srcIdx = 0;
                if ( srcPart->FindProperty( KMsgStorePropertySize, srcIdx ) )
                    {
                    TUint size = srcPart->PropertyValueUint32L( srcIdx );

                    srcIdx = 0;
                    if ( srcPart->FindProperty( KMsgStorePropertyRetrievedSize, srcIdx ) )
                        {
                        TUint retrievedSize = srcPart->PropertyValueUint32L( srcIdx );
                        
                        if ( retrievedSize < size )
                            {
                            wasTruncated = ETrue;
                            }
                        }
                    }
                    
                //if truncated append msg that the whole msg is available server-side.
                if ( wasTruncated )
                    {
                    _LIT( KTwoLineFeeds, "\n\n" );
                    TPtrC8 ptrTwoLineFeeds8(
                        reinterpret_cast<const TUint8*>( KTwoLineFeeds().Ptr() ),
                        KTwoLineFeeds().Size() );
                    dstPart->AppendToContentL( ptrTwoLineFeeds8 );

                    TPtrC8 ptrSmartTag8(
                        reinterpret_cast<const TUint8*>( rfParsPckg().iSmartTag->Ptr() ),
                        rfParsPckg().iSmartTag->Size() );
                    dstPart->AppendToContentL( ptrSmartTag8 );
                    }
                }

            /**@ incorrect but per activesync request - the base plugin doesn't know anything about how the unicode characters
            are being encoded by the specific implementations when they talk to their backends.*/
            _LIT(KMessageBodyCharset, "UTF-8");
            dstPart->AddPropertyL( KMsgStorePropertyCharset, KMessageBodyCharset );

            CleanupStack::PopAndDestroy( dstPart );
            }
        CleanupStack::PopAndDestroy( srcPart );
        }
    
    CleanupStack::Pop( result );
    CleanupStack::PopAndDestroy( newMsg );
    CleanupStack::PopAndDestroy( message );
    
    __LOG_EXIT
    return result;
    } //CreateForwardReplyMessageL.


/**
 * If there is a reply to address, add it to the TO list
 * else add the FROM address to the TO address list   
 */
/*private*/ void CBasePlugin::SetReplyOrForwardToFieldL( CMsgStoreMessage& aMsg )
	{
    RMsgStoreAddress toAddr;
    CleanupClosePushL( toAddr );
    
    TBool usingReplyTo = EFalse;
    
    TUint idx = 0;
    if( aMsg.FindProperty( KMsgStorePropertyReplyTo, idx ) )
    	{
    	//if both address and name are null strings no memory will be allocated.
        aMsg.PropertyValueAddressL( idx, toAddr );
        
        if ( toAddr.iEmailAddress.Length() || toAddr.iDisplayName.Length() )
        	{
        	usingReplyTo = ETrue;
        	}
    	}

    if ( EFalse == usingReplyTo )
		{
        idx = 0;
        if ( aMsg.FindProperty( KMsgStorePropertyFrom, idx ) )
        	{
            aMsg.PropertyValueAddressL( idx, toAddr );
        	}
		}

    aMsg.AddPropertyL( KMsgStorePropertyTo, toAddr );
    CleanupStack::PopAndDestroy( &toAddr );
	}


/**
 * RefreshMailboxCacheL - This will refresh the mailbox instance cache maintained within the base plugin.  
 *
 */
EXPORT_C CMailboxInfo& CBasePlugin::RefreshMailboxCacheL( TMsgStoreId aMailBoxId )
    {
    //save the observers
    CMailboxInfo& oldMailBox = GetMailboxInfoL( aMailBoxId );
    
    RPointerArray<MFSMailEventObserver> observers;
    // the elements are not owned by the base plugin, so just close the array
    CleanupClosePushL( observers );

    TUint count = oldMailBox.iObservers.Count();
    for ( TUint i = 0; i < count; i++ )
    	{
    	observers.AppendL( oldMailBox.iObservers[i] );
    	}
    
    //remove from the cache
    if ( KErrNotFound != iMailboxes.Find( aMailBoxId ) )
        {
        iMailboxes.RemoveL( aMailBoxId );
        }

    //force the refresh and restore the observes
    CMailboxInfo& newMailBox = GetMailboxInfoL( aMailBoxId );
    
    for ( TUint i = 0; i < count; i++ )
    	{
    	newMailBox.iObservers.AppendL( observers[i] );
    	}
    
    CleanupStack::PopAndDestroy( &observers );
    return newMailBox;
    }


/**
 * RefreshCachedMailBoxDisplayNameL -   This will check to see if the mailbox display name has changed.  If so it will
 *                                      update the cached mailbox display name and set mailBoxNameHasChanged to ETrue 
 *
 */
void CBasePlugin::RefreshCachedMailBoxDisplayNameL( TBool& aMailBoxNameHasChanged, const TMsgStoreId& aMailBoxId )
    {
    aMailBoxNameHasChanged = EFalse;
    
    RBuf currentDisplayName;
    currentDisplayName.CleanupClosePushL();
    GetMailboxDisplayNameL( aMailBoxId, currentDisplayName );
    
    CMailboxInfo& mailboxInfo = GetMailboxInfoL( aMailBoxId );
    TDesC* cachedDisplayName( mailboxInfo.iMailBoxDisplayName );

    if ( ( cachedDisplayName && currentDisplayName != *cachedDisplayName ) ||
         ( !cachedDisplayName && currentDisplayName.Length() ) )
        {
        aMailBoxNameHasChanged = ETrue;
        delete mailboxInfo.iMailBoxDisplayName;
        mailboxInfo.iMailBoxDisplayName = NULL;
        mailboxInfo.iMailBoxDisplayName = currentDisplayName.AllocL();
        }
    
    CleanupStack::PopAndDestroy( &currentDisplayName );
    }