mobilemessaging/postcard/postcardsrc/PostcardOperationSave.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:44:11 +0200
changeset 0 72b543305e3a
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2005 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:  
*       CPostcardOperationSave
*
*/



// ========== INCLUDE FILES ================================

#include <badesca.h>
#include <AknsConstants.h>
#include <data_caging_path_literals.hrh> 
#include <apmstd.h>  // TDataType
#include <mmsvattachmentmanager.h>	// AttachmentManager
#include <mmsvattachmentmanagersync.h>	// AttachmentManager
#include <cmsvmimeheaders.h>		// MimeHeaders

#include <StringLoader.h>			// For StringLoader

#include <mmsclient.h>
#include <mmsconst.h>
#include <mmsmsventry.h>

#include <MsgMimeTypes.h>

#include <vprop.h>	// VCardPropertyValue
#include <cntitem.h>
#include <vcard.h>
#include <cntfldst.h> // CContactTextField

#include <Postcard.rsg>
#include "PostcardOperationSave.h"
#include "PostcardUtils.h"
#include "Postcard.hrh"
#include "PostcardAddressForm.h"
#include "PostcardPrivateCRKeys.h"  // cenrep keys
#include "PostcardCenRep.h"

// ========== EXTERNAL DATA STRUCTURES =====================

// ========== EXTERNAL FUNCTION PROTOTYPES =================

// ========== CONSTANTS ====================================

// ========== MACROS =======================================

// ========== LOCAL CONSTANTS AND MACROS ===================

_LIT8( KReplaceChar8, "_" );
_LIT8( KPostcardVCardName, "N"); // This was "FN" in 3.0-3.1 but OMA says it should be "N"
_LIT8( KPostcardVCardAddr, "ADR");
_LIT8( KPostcardGreetingXParameter, "X-MMS-GREETING-TEXT" );

// ========== MODULE DATA STRUCTURES =======================

// ========== LOCAL FUNCTION PROTOTYPES ====================

// ========== LOCAL FUNCTIONS ==============================

// ========== MEMBER FUNCTIONS =============================

// ---------------------------------------------------------
// NewL
// ---------------------------------------------------------
CPostcardOperationSave* CPostcardOperationSave::NewL(
            MPostcardOperationObserver& aObserver,
            CPostcardDocument& aDocument,
            CPostcardAppUi& aAppUi,
            RFs& aFs,
            CContactCard& aContact,
            CPlainText& aPlainText )
    {
    CPostcardOperationSave* self = 
        new ( ELeave ) CPostcardOperationSave( aObserver, aDocument, aAppUi, aFs, aContact, aPlainText );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// ---------------------------------------------------------
// CPostcardOperationSave
// ---------------------------------------------------------
CPostcardOperationSave::CPostcardOperationSave(
            MPostcardOperationObserver& aObserver,
            CPostcardDocument& aDocument,
            CPostcardAppUi& aAppUi,
            RFs& aFs,
			CContactCard& aContact,
			CPlainText& aPlainText ) :
    CPostcardOperation( aObserver, aDocument, aAppUi, aFs ),
    iContact( aContact ),
    iPlainText( aPlainText )
    {
    }

// ---------------------------------------------------------
// CPostcardOperationSave
// ---------------------------------------------------------
CPostcardOperationSave::~CPostcardOperationSave( )
    {
    Cancel( );
    if( iTempFile )
        {
        iTempFile->Close( );
        delete iTempFile;
        }
    delete iSendOperation;
    delete iCharConv;
    delete iRecipientName;
    }

// ---------------------------------------------------------
// Start
// ---------------------------------------------------------
void CPostcardOperationSave::Start( TInt aArgument )
    {
    if( aArgument )
    	{
    	iFlags |= EPostcardSaveSend;
    	}
    if( iAppUi.CenRep().GetString( KPocaKeyServiceSpecialFormat ).Length() > 0 &&
        ( iFlags & EPostcardSaveSend ) )
        { // if special send format is defined and we are sending -> take it into use
        iFlags |= EPostcardSaveSpecialFormat;
        }
    iLaunchState = EPostcardSaveInitializing;
    CompleteSelf( KErrNone );
    }

// ---------------------------------------------------------
// DoLaunchStepL
// ---------------------------------------------------------
void CPostcardOperationSave::DoLaunchStepL( )
    {
    iFlags &= ~EPostcardSaveRequestActive;
    switch ( iLaunchState )
        {        
    	case EPostcardSaveInitializing:
    		{
    		InitL( );			
            iLaunchState = EPostcardSaveCheckAttas;
            CompleteSelf( KErrNone );
            break;    			
    		}
        case EPostcardSaveCheckAttas:
            {
            if( !CheckAttasL( ) )
            	{ // If there was an error, this has been completed already
	            iLaunchState = EPostcardSaveRemoveOldAttas; 
	            CompleteSelf( KErrNone );            		
            	}
            break;
            }
        case EPostcardSaveRemoveOldAttas:
            {
            RemoveOldAttasL( );
            // Let's see the next phase..
            if( iPlainText.DocumentLength( ) > 0 && iDocument.Changed( EPostcardText ) )
                { // We have text and it has changed -> so save it..
                iLaunchState = EPostcardSaveCreateTextAtta;
                }
            else if ( ( iFlags & EPostcardSaveSend ) &&
                      ( iFlags & EPostcardSaveSpecialFormat ) )
                { // Text has not changed, but we have special format on -> so create text atta anyway
                iLaunchState = EPostcardSaveCreateTextAtta;                
                }
            else if ( iDocument.Changed( EPostcardRecipient ) )
                { // We are not sending special format, but the recipient has changed
                iLaunchState = EPostcardSaveCreateRecipientAtta;
                }
            else if(   !iSmil && 
                    (  iFlags & EPostcardSaveSend ) &&
                    !( iFlags & EPostcardSaveSpecialFormat ) )
                { // Text and recipient have not changed, but we are sending OMA Postcard and there's no SMIL yet
                iLaunchState = EPostcardSaveCreateSmilAtta;
                }
            else
                {
                iLaunchState = EPostcardSaveUninit;
                }
            CompleteSelf( KErrNone );
            break;
            }
        case EPostcardSaveCreateTextAtta:
            {
            CreateNewTextAttaL( );
            iLaunchState = EPostcardSaveSaveTextAtta;
		    SetActive();    
            break;
            }
        case EPostcardSaveSaveTextAtta:
            {
            HandleTextL( );
            iLaunchState = EPostcardSaveFinalizeTextAtta;
            CompleteSelf( KErrNone );
            break;
            }
        case EPostcardSaveFinalizeTextAtta:
            {
            FinalizeTextL( );
            if ( iDocument.Changed( EPostcardRecipient ) &&
                ( iFlags & EPostcardSaveHasContact ) )
                { // We are not sending special format, but the recipient has changed
                iLaunchState = EPostcardSaveCreateRecipientAtta;
                }
            else if(   !iSmil && 
                    (  iFlags & EPostcardSaveSend ) &&
                    !( iFlags & EPostcardSaveSpecialFormat ) )
                { // Recipient has not changed, but we are sending OMA Postcard and there's no SMIL yet
                iLaunchState = EPostcardSaveCreateSmilAtta;
                }
            else
                {
                iLaunchState = EPostcardSaveUninit;
                }
            CompleteSelf( KErrNone );
            break;
            }
        case EPostcardSaveCreateRecipientAtta:
            {
            CreateNewRecipientAttaL( );
            iLaunchState = EPostcardSaveSaveRecipientAtta;
		    SetActive( );        	
            break;
            }
        case EPostcardSaveSaveRecipientAtta:
            {
            HandleRecipientL( );
            iLaunchState = EPostcardSaveFinalizeRecipientAtta;
            CompleteSelf( KErrNone );
            break;
            }
        case EPostcardSaveFinalizeRecipientAtta:
            {
            FinalizeRecipientL( );
            if( !iSmil && 
                 ( iFlags & EPostcardSaveSend ) &&
                !( iFlags & EPostcardSaveSpecialFormat ) )
                { // Smil is created only to confront OMA Postcard spec
                iLaunchState = EPostcardSaveCreateSmilAtta;
                }
            else
                {
                // Smil seems to exists already or we are not sending
                iLaunchState = EPostcardSaveUninit;                
                }
            CompleteSelf( KErrNone );
            break;
            }
        case EPostcardSaveCreateSmilAtta:
            {
            CreateNewSmilAttaL( );
            iLaunchState = EPostcardSaveSaveSmilAtta;
		    SetActive( );        	
            break;
            }
        case EPostcardSaveSaveSmilAtta:
            {
            HandleSmilL( );
            iLaunchState = EPostcardFinalizeSmilAtta;
            CompleteSelf( KErrNone );
            break;
            }
        case EPostcardFinalizeSmilAtta:
            {
            FinalizeSmilL( );
            iLaunchState = EPostcardSaveUninit;            
            CompleteSelf( KErrNone );
            break;
            }
        case EPostcardSaveUninit:
            {
            UnInitL( );
            iLaunchState = EPostcardSaveFinalizeMessage;
            CompleteSelf( KErrNone );
            break;
            }
        case EPostcardSaveFinalizeMessage:
            {
            FinalizeMessageL( );
            if( iFlags & EPostcardSaveSend )
            	{
	            iLaunchState = EPostcardSaveStartSend;        	            		
            	}
            else
            	{
	            iLaunchState = EPostcardSaveFinished;        	
            	}
            CompleteSelf( KErrNone );
            break;
            }
        case EPostcardSaveStartSend:
            {
            StartSendingL( );
            iLaunchState = EPostcardSaveFinished;        	
		    SetActive();    
            break;
            }
        case EPostcardSaveFinished:
            {
            iObserver.PostcardOperationEvent(
                EPostcardOperationSave,
                EPostcardOperationComplete ); 
            break;
            }
        default:
            iObserver.PostcardOperationEvent(
                EPostcardOperationSave,
                EPostcardOperationError ); 
            break;
        }
    }

// ---------------------------------------------------------
// RemoveOldAttasL
// ---------------------------------------------------------
void CPostcardOperationSave::RemoveOldAttasL( )
	{
	if( 	iDocument.Changed( EPostcardText ) || 
		( ( iFlags & EPostcardSaveSend ) && ( iFlags & EPostcardSaveSpecialFormat ) ) )
		{
		if( iText )
			{ // Remove old
			TInt old = TMsvIdToIndexL( iText );
			if( old != KErrNotFound )
			    {
			    // If there is an old text atta and a no new text atta, we need to
			    // ask commit here, otherwise old atta would be left with the message.
			    iCommit = ETrue;
    			iStore->AttachmentManagerExtensionsL( ).RemoveAttachmentL( old );			    
			    }
			}		
		}
	if( 	iDocument.Changed( EPostcardRecipient ) || 
		( ( iFlags & EPostcardSaveSend ) && ( iFlags & EPostcardSaveSpecialFormat ) ) )
		{
		if( iRecipient )
			{ // Remove old
			TInt old = TMsvIdToIndexL( iRecipient );
			if( old != KErrNotFound )
			    {
    			iStore->AttachmentManagerExtensionsL( ).RemoveAttachmentL( old );
			    }
			}		
		}	
	}
	
// ---------------------------------------------------------
// CreateNewTextAttaL
// ---------------------------------------------------------
void CPostcardOperationSave::CreateNewTextAttaL( )
	{
    // Now lets create a new attachment
    TFileName file( _L("greeting.txt") );
    StartCreatingEmptyAttachmentL( file );
	}
	
// ---------------------------------------------------------
// HandleTextL
// ---------------------------------------------------------
void CPostcardOperationSave::HandleTextL( )
	{
    if( !iCharConv )
        {
        iCharConv = CCnvCharacterSetConverter::NewL( );
        }
		
    if ( iCharConv->PrepareToConvertToOrFromL( KCharacterSetIdentifierUtf8, iFs )
        != CCnvCharacterSetConverter::EAvailable )
        {
        User::Leave( KErrNotSupported );
        }
	
    // Delete possible old headers
    delete iHeaders;
    iHeaders = NULL;
    iHeaders = CMsvMimeHeaders::NewL( );

    if( ( iFlags & EPostcardSaveSend ) && !( iFlags & EPostcardSaveSpecialFormat ) )
        {
        iHeaders->XTypeParams().AppendL( KPostcardGreetingXParameter );
        iHeaders->XTypeParams().AppendL( TPtrC8() );	    
        }

    _LIT(KFileName, "text.txt");
    iHeaders->SetContentLocationL( KFileName );
    iHeaders->SetMimeCharset( KMmsUtf8 );

    TInt slash = KMsgMimeTextPlain().Locate( '/' );
    iHeaders->SetContentTypeL( KMsgMimeTextPlain().Left( slash ) );
    iHeaders->SetContentSubTypeL( KMsgMimeTextPlain().Mid( slash + 1 ) );

    iTempAtta->SetMimeTypeL( KMsgMimeTextPlain );

    iText = iTempAtta->Id( );
    RFileWriteStream writer( *iTempFile );
    writer.PushL( );
    delete iTempFile; // not close as write does it..
    iTempFile = NULL;
    
    TPtrC16 remainderOfUnicodeText;
    TInt numCleanupItems = 0;
    
    if( (iFlags & EPostcardSaveSend) && (iFlags & EPostcardSaveSpecialFormat ) )
        {
        // If we are here -> we are sending so we must have iContact OK
        HBufC* wholeText = MakeSpecialFormatTextL();
        CleanupStack::PushL( wholeText );
        numCleanupItems++;

        remainderOfUnicodeText.Set( wholeText->Des( ) );	
        
        // Now we remove the HasContact flag so that the recipient is not stored separately
		iFlags &=  ~EPostcardSaveHasContact;
		}
    else
        {
        remainderOfUnicodeText.Set(
            iPlainText.Read( 0, iPlainText.DocumentLength() ) );
        }

    // Now remainOfUnicodeText has the stuff needed to store into the greeting text
    TBuf8<128> outputBuffer;
    TInt returnValue;
    do
        {
        returnValue = iCharConv->ConvertFromUnicode(
            outputBuffer, remainderOfUnicodeText );
        if ( returnValue < 0 )
            {
            User::Leave(
                returnValue == CCnvCharacterSetConverter::EErrorIllFormedInput ?
                KErrCorrupt:KErrGeneral );
            }
        writer.WriteL( outputBuffer );
        remainderOfUnicodeText.Set( remainderOfUnicodeText.Right(
            returnValue ) );
        }
    while( returnValue );

    CleanupStack::PopAndDestroy( numCleanupItems );
    writer.Pop( );
    writer.Close( );	
	}

// ---------------------------------------------------------
// MakeSpecialFormatTextL
// ---------------------------------------------------------
HBufC* CPostcardOperationSave::MakeSpecialFormatTextL()
    {
    CContactItemFieldSet& set = iContact.CardFields( );
    // Organise the address into an array
    CDesCArrayFlat* desarr = AddressArrayLC( set );

    const TDesC& replacement =
        iAppUi.CenRep().GetString( KPocaKeyServiceReplaceString );
    const TDesC& separator =
        iAppUi.CenRep().GetString( KPocaKeyServiceSeparator );

    // Add the greeting text.
    
    TInt len = iPlainText.DocumentLength();
    HBufC* buf = HBufC::NewLC( len );
    *buf = iPlainText.Read( 0, len );

    // Replace illegal chars
    TPtr des = buf->Des();
    ReplaceWith( des, separator, replacement );
    // And add this to the desarr
    desarr->InsertL( 0, *buf );

    // Read the format string from cenrep
    const TDesC& specialFormat =
        iAppUi.CenRep().GetString( KPocaKeyServiceSpecialFormat );

    // Construct the text to be sent. Room for each tag, strings between
    // tags and prefix and postfix.
    const TInt KMaxItems = TPostcardUtils::ENumSpecFormatTags * 2 + 1;
    TPtrC textItems[KMaxItems];

    TPtrC format(specialFormat);
    TInt position = 0;
    TInt numItems = 0;
    while(numItems < KMaxItems - 1 && position != KErrNotFound)
        {
        TInt tag;
        position = TPostcardUtils::NextTag(format, tag);
        if ( position != KErrNotFound )
            {
            textItems[numItems++].Set( format.Left( position ) );
            textItems[numItems++].Set( desarr->MdcaPoint( tag ) );
            format.Set( format.Right( format.Length() - position - 3 ) );
            }
        else
            {
            textItems[numItems++].Set( format );
            }
        }
        
    // Calculate buffer length needed to fit the whole text
    TInt buffSize = 0;
    for( TInt i = 0; i < numItems; i++ )
        {
        buffSize += textItems[i].Length();
        }

    // Copy text into buffer
    HBufC* dstBuf = HBufC::NewL( buffSize );
    TPtr dst = dstBuf->Des();
    for( TInt i = 0; i < numItems; i++ )
        {
        dst.Append( textItems[i] );
        }

    CleanupStack::PopAndDestroy( 2 ); // buff, desarr

    return dstBuf;
    }

// ---------------------------------------------------------
// FinalizeTextL
// ---------------------------------------------------------
void CPostcardOperationSave::FinalizeTextL( )
	{
	iHeaders->StoreL( *iTempAtta );
	}
	
// ---------------------------------------------------------
// CreateNewRecipientAttaL
// ---------------------------------------------------------
void CPostcardOperationSave::CreateNewRecipientAttaL( )
	{
    // Now lets create a new attachment
    TFileName file( _L("recipient.vcf") );
    StartCreatingEmptyAttachmentL( file );
	}
	
// ---------------------------------------------------------
// HandleRecipientL
// ---------------------------------------------------------
void CPostcardOperationSave::HandleRecipientL( )
	{
	if( !iCharConv )
		{
	    iCharConv = CCnvCharacterSetConverter::NewL( );
		}
    if ( iCharConv->PrepareToConvertToOrFromL( KCharacterSetIdentifierAscii, iFs ) !=
        CCnvCharacterSetConverter::EAvailable )
        {
        User::Leave( KErrNotSupported );
        }

	// Delete possible old headers
	delete iHeaders;
	iHeaders = NULL;
	iHeaders = CMsvMimeHeaders::NewL( );
   	iHeaders->SetContentLocationL( _L("recipient.vcf") );
	
	TInt slash = KMsgMimeVCard().Locate( '/' );
    iHeaders->SetContentTypeL( KMsgMimeVCard().Left( slash ) );
    iHeaders->SetContentSubTypeL( KMsgMimeVCard().Mid( slash + 1 ) );
	
	iTempAtta->SetMimeTypeL( KMsgMimeVCard );

    iRecipient = iTempAtta->Id( );    
        
    CParserVCard* parser = CParserVCard::NewL();
    CleanupStack::PushL(parser);

    RFileWriteStream vCardStream( *iTempFile );
    vCardStream.PushL( );    
    delete iTempFile; // not close as VCardStream does it..
    iTempFile = NULL;

	iCharConv->SetReplacementForUnconvertibleUnicodeCharactersL( KReplaceChar8 );
	
	CContactItemFieldSet& set = iContact.CardFields( );

    const CContactItemField* field = TPostcardUtils::FieldOrNull( set,
        TPostcardUtils::ContactItemNameFromId( EPostcardAddressName ) );

    if( field )
        {
		CParserPropertyValueHBufC* val =
		    CParserPropertyValueHBufC::NewL( field->TextStorage()->Text() );
		CleanupStack::PushL( val );
		CArrayPtrFlat<CParserParam>* array = new(ELeave)CArrayPtrFlat<CParserParam>(1);
		CleanupStack::PushL( array );
		CParserProperty* property = CParserProperty::NewL( *val, KPostcardVCardName, array);
		CleanupStack::PushL( property );
		parser->AddPropertyL( property );
		CleanupStack::Pop( 3, val );				
		}

	CDesCArrayFlat* desarr = VCardAddressArrayL( set ); // Organise the address into an array
	CleanupStack::PushL( desarr );
	// AddressArrayL does not add empty "PO Box" descriptor into the desarr
	desarr->InsertL( 0, KNullDesC );

    CParserPropertyValue* val = new (ELeave)CParserPropertyValueCDesCArray(desarr);
    CleanupStack::Pop(desarr);
	CleanupStack::PushL( val );
	CArrayPtrFlat<CParserParam>* array = new(ELeave)CArrayPtrFlat<CParserParam>(1);
	CleanupStack::PushL( array );

	CParserProperty* property = CParserProperty::NewL( *val, KPostcardVCardAddr, array);
	CleanupStack::PushL( property );
	parser->AddPropertyL( property );
	CleanupStack::Pop( 3, val );				
        
    parser->ExternalizeL(vCardStream);

    vCardStream.Pop( );
    vCardStream.Close( );

    CleanupStack::PopAndDestroy(parser);
	}
	
// ---------------------------------------------------------
// FinalizeRecipientL
// ---------------------------------------------------------
void CPostcardOperationSave::FinalizeRecipientL( )
	{
	iHeaders->StoreL( *iTempAtta );	
	}

// ---------------------------------------------------------
// CreateNewSmilAttaL
// ---------------------------------------------------------
void CPostcardOperationSave::CreateNewSmilAttaL( )
    {
    // Now lets create a new attachment
    TFileName file( _L("postcard.smil") );
    StartCreatingEmptyAttachmentL( file );
    }
    
// ---------------------------------------------------------
// HandleSmilL
// ---------------------------------------------------------
void CPostcardOperationSave::HandleSmilL( )
    {
	// Delete possible old headers
	delete iHeaders;
	iHeaders = NULL;
	
	iHeaders = CMsvMimeHeaders::NewL( );
   	iHeaders->SetContentLocationL( _L("pres.smil") );
	
	TInt slash = KMsgMimeSmil().Locate( '/' );
    iHeaders->SetContentTypeL( KMsgMimeSmil().Left( slash ) );
    iHeaders->SetContentSubTypeL( KMsgMimeSmil().Mid( slash + 1 ) );
    
	iTempAtta->SetMimeTypeL( KMsgMimeSmil );

    iSmil = iTempAtta->Id( );
    
    // Get the name of the image file to be inserted into the SMIL file
    HBufC* fileName = GetImageFileNameL( );
    CleanupStack::PushL( fileName );
	TInt resId = R_POSTCARD_OMA_SMIL;
	HBufC* smil = StringLoader::LoadL( resId, *fileName );
    CleanupStack::PopAndDestroy( fileName );
    CleanupStack::PushL( smil );

    // convert the smil to 8-bit
    HBufC8* smil8 = HBufC8::NewLC( smil->Des( ).Length( ) );
    smil8->Des().Copy( smil->Des( ) );

    RFileWriteStream smilStream( *iTempFile );
    smilStream.PushL( );    
    
    delete iTempFile; // not close as smilStream does it
    iTempFile = NULL;

    smilStream.WriteL( *smil8 );

    smilStream.Close( );
    smilStream.Pop( );
    CleanupStack::PopAndDestroy( 2, smil ); // smil, smil8
    }

// ---------------------------------------------------------
// FinalizeSmilL
// ---------------------------------------------------------
void CPostcardOperationSave::FinalizeSmilL( )
    {
	iHeaders->StoreL( *iTempAtta );
    }
	
// ---------------------------------------------------------
// FinalizeMessageL
// ---------------------------------------------------------
void CPostcardOperationSave::FinalizeMessageL( )
	{
	
    const CMsvRecipientList& addresses = iDocument.Mtm( ).AddresseeList();
    
    if( addresses.Count( ) < 1 )
    	{
        iDocument.Mtm().AddAddresseeL(
            iAppUi.CenRep().GetString( KPocaKeyServiceProvider ) );
    	}
	
	// Disable delivery reports for postcards
	iDocument.Mtm().SetDeliveryReport( EMmsNo );
	
    iDocument.Mtm().SaveMessageL();

    TMmsMsvEntry tEntry = static_cast<TMmsMsvEntry>( iDocument.Entry() );
	
    // Update timestamp  
    tEntry.iDate.UniversalTime();

    if ( !tEntry.Visible() )
        {
        // Save from close or exit save.
        // Message should be visible after save
        tEntry.SetVisible( ETrue );
        tEntry.SetInPreparation( EFalse );
        }

    if ( !tEntry.EditorOriented() )
        {
        tEntry.SetEditorOriented( ETrue );
        }

	tEntry.iDetails.Set( iRecipientName->Des( ) ) ;
    tEntry.iDescription.Set(
        iPlainText.Read( 0, Min( iPlainText.DocumentLength(), 20 ) ) );
    
	tEntry.iBioType = KUidMsgSubTypeMmsPostcard.iUid;
    
    iDocument.CurrentEntry().ChangeL( tEntry );
	}

// ---------------------------------------------------------
// CPostcardOperationSave::StartSendingL
// ---------------------------------------------------------
void CPostcardOperationSave::StartSendingL( )
	{
    iSendOperation = iDocument.Mtm().SendL( iStatus );
	}

// ---------------------------------------------------------
// CPostcardOperationSave::ConstructL
// ---------------------------------------------------------
void CPostcardOperationSave::ConstructL( )
    {
    if( HasContact() )
        {
        iFlags |=  EPostcardSaveHasContact;
        CContactItemFieldSet& fieldSet =  iContact.CardFields();
        const CContactItemField* field = TPostcardUtils::FieldOrNull( fieldSet,
            TPostcardUtils::ContactItemNameFromId( EPostcardAddressName ) );
        if( field )
            {
            iRecipientName = field->TextStorage()->Text().AllocL();
            }
        }
    if( !iRecipientName )
        {
        iRecipientName = HBufC::NewL( 0 );
        }
    }

// ---------------------------------------------------------
// CPostcardOperationSave::DoCancel
// ---------------------------------------------------------
void CPostcardOperationSave::DoCancel( )
    {
    if( iManager )
        {
        if( iFlags & EPostcardSaveRequestActive )
            { // Attachment Manager request going on -> cancel
            iManager->CancelRequest();        
            }
        }
    }

// ---------------------------------------------------------
// RunL
// ---------------------------------------------------------
void CPostcardOperationSave::RunL( )
    {
    DoLaunchStepL( );
    }

// ---------------------------------------------------------
// RunError
// ---------------------------------------------------------
TInt CPostcardOperationSave::RunError( TInt aError )
    {
    iLaunchState = -1;
    SetError( aError );
    iObserver.PostcardOperationEvent(
        EPostcardOperationSave,
        EPostcardOperationError );     
    return KErrNone;
    }

// ---------------------------------------------------------
// StartCreatingEmptyAttachmentL
// ---------------------------------------------------------
void CPostcardOperationSave::StartCreatingEmptyAttachmentL( const TFileName& aFileName )
    {
    CMsvAttachment* attachment = CMsvAttachment::NewL( CMsvAttachment::EMsvFile );
    CleanupStack::PushL( attachment );
    iTempFile = new ( ELeave ) RFile;
    iManager->CreateAttachmentL( aFileName, *iTempFile, attachment, iStatus );
    iFlags |= EPostcardSaveRequestActive;
    CleanupStack::Pop( attachment );
    iTempAtta = attachment;
    iCommit = ETrue;
    }
    
// ---------------------------------------------------------
// HasContact
// ---------------------------------------------------------
TBool CPostcardOperationSave::HasContact( )
	{
	CContactItemFieldSet& set = iContact.CardFields( );
	for( TInt i = 0; i<set.Count( ); i++ )
		{
		CContactItemField& field = set[i];
		if( field.TextStorage( )->Text( ).Length( ) > 0 )
			{
			return ETrue;
			}
		}
	return EFalse;	
	}
    
// ---------------------------------------------------------
// AddressArrayLC
// ---------------------------------------------------------
CDesCArrayFlat* CPostcardOperationSave::AddressArrayLC( CContactItemFieldSet& aSet )
	{
    // Get contact fields into an array. No ownership.
    const CContactItemField* fields[ CPostcardAddressForm::ENumAddrFields ];

    const TInt first = EPostcardAddressName;
    const TInt last = EPostcardAddressCountry;
    for( TInt i = first; i <= last; i++)
        {
        fields[i - first] = TPostcardUtils::FieldOrNull(
            aSet, TPostcardUtils::ContactItemNameFromId( i ) );
        }

    CDesCArrayFlat* desarr =
        new( ELeave ) CDesCArrayFlat( CPostcardAddressForm::ENumAddrFields );
    CleanupStack::PushL(desarr);

    for( TInt i = 0; i < CPostcardAddressForm::ENumAddrFields; i++ )
        {
        if( fields[i] )
            {
            if( ( iFlags & EPostcardSaveSend) &&
                (iFlags & EPostcardSaveSpecialFormat ) )
                { // We are sending & have the special format on
                // so lets replace possible user added separator strings
                TPtr string = fields[i]->TextStorage()->Text().AllocLC()->Des();
                // Trim leading and trailing white space so it doesn't affect
                // parsing of special format string when opened from sent
                // folder.
                string.Trim();
                ReplaceWith( string,
                    iAppUi.CenRep().GetString( KPocaKeyServiceSeparator ),
                    iAppUi.CenRep().GetString( KPocaKeyServiceReplaceString )
                    );
                desarr->AppendL( string );
                CleanupStack::PopAndDestroy(); // string
                }
            else
                { // Otherwise just add the data field
                desarr->AppendL( fields[i]->TextStorage()->Text() );
                }
            }
        else
            {
            desarr->AppendL( KNullDesC );
            }
        }
    return desarr;
    }

// ---------------------------------------------------------
// VCardAddressArrayL
// ---------------------------------------------------------
CDesCArrayFlat* CPostcardOperationSave::VCardAddressArrayL( CContactItemFieldSet& aSet )
    {
    // Exclude name
    const TInt KPocaVCardAddrFields = CPostcardAddressForm::ENumAddrFields - 1;

    // Get contact fields into an array. No ownership.
    const CContactItemField* fields[ KPocaVCardAddrFields ];

    // Order of contact fields in array
    static const TInt ids[KPocaVCardAddrFields] =
        {
        EPostcardAddressInfo, EPostcardAddressStreet, EPostcardAddressCity,
        EPostcardAddressState, EPostcardAddressZip, EPostcardAddressCountry
        };
    
    for( TInt i = 0; i < KPocaVCardAddrFields; i++)
        {
        fields[i] = TPostcardUtils::FieldOrNull(
            aSet, TPostcardUtils::ContactItemNameFromId( ids[i] ) );
        }

    CDesCArrayFlat* desarr = new(ELeave) CDesCArrayFlat( KPocaVCardAddrFields );
    CleanupStack::PushL( desarr );

    for( TInt i = 0; i < KPocaVCardAddrFields; i++ )
        {
        desarr->AppendL(
            fields[i] ? fields[i]->TextStorage()->Text() : KNullDesC() );
        }

	CleanupStack::Pop( desarr );
	return desarr;
    }

// ---------------------------------------------------------
// ReplaceWith
// ---------------------------------------------------------
void CPostcardOperationSave::ReplaceWith( TDes& aOrig, const TDesC& aWhat,
    const TDesC& aWith )
    {    
	TInt pos = 0;
	TInt foundPos = 0;
	TBool found = ETrue;

	while( found )
	    {
	    found = EFalse;
		if( pos >= aOrig.Length( ) )
			{
			continue; // as found is false -> while is not true anymore
			}	
				
    	foundPos =  aOrig.Mid( pos, aOrig.Length()-pos ).Find( aWhat );
    	
		if( foundPos == KErrNotFound )
			{ // Not found anymore, so the rest is ok
			continue; // as found is false -> while is not true anymore
			}
			
        found = ETrue;
		// As foundPos is related to previous sepa char, we need to add the beginning, too
		foundPos += pos;
		aOrig.Replace( foundPos, aWhat.Length( ), aWith );
	    pos = foundPos + aWhat.Length( ) + ( aWith.Length( ) - aWhat.Length( ) );
	    }    
    }

// ---------------------------------------------------------
// GetImageFileName
// ---------------------------------------------------------
HBufC* CPostcardOperationSave::GetImageFileNameL( )
    {
    // Goes thru the attas and check how many images, text and recipients there are
    TInt count = iManager->AttachmentCount( );
    CMsvAttachment* atta = NULL;

    HBufC* nameString = NULL;
    for(TInt a = 0; a<count && !nameString; a++)
        {
        atta = iManager->GetAttachmentInfoL( a );
        CleanupStack::PushL( atta );

        switch( RecogniseFileType( atta->MimeType( ) ) )
            {
            case EPostcardFileImage:
                {
                CMsvMimeHeaders* msvMime = CMsvMimeHeaders::NewLC();
                msvMime->RestoreL( *atta );
                nameString = msvMime->ContentLocation().AllocL();
                CleanupStack::PopAndDestroy( msvMime ); // msvMime, atta
                break;
                }
            default:
                break;
            }
        CleanupStack::PopAndDestroy( atta );
        }
    return nameString ? nameString : HBufC::NewL( 0 );
    }
    
// EOF