--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mobilemessaging/postcard/postcardsrc/PostcardOperationOpen.cpp Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,986 @@
+/*
+* 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:
+* CPostcardOperationOpen
+*
+*/
+
+
+
+// ========== INCLUDE FILES ================================
+
+#include <AknsConstants.h>
+#include <data_caging_path_literals.hrh>
+#include <apmstd.h> // TDataType
+#include <gulicon.h> // CGulIcon
+#include <txtetext.h> // For TDocumentStorage
+
+#include <MsgMediaInfo.h>
+#include <MsgMedia.hrh>
+#include <MsgImageInfo.h>
+#include <MsgMediaResolver.h> // for CMmsMediaResolver
+#include <MsgTextInfo.h>
+#include <msgtextutils.h>
+#include <MsgMimeTypes.h>
+
+#include <IHLImageFactory.h>
+#include <IHLViewerFactory.h>
+#include <MIHLFileImage.h>
+#include <MIHLBitmap.h>
+#include <MIHLImageViewer.h>
+
+#include <mmsvattachmentmanager.h> // AttachmentManager
+#include <mmsvattachmentmanagersync.h> // AttachmentManagerSync
+#include <cmsvmimeheaders.h> // MimeHeaders
+#include <mmsclient.h>
+
+#include <vprop.h> // VCardPropertyValue
+#include <cntitem.h>
+#include <vcard.h>
+#include <cntfldst.h> // CContactTextField
+
+#include <StringLoader.h> // for StringLoader
+
+#include <Postcard.rsg> // for Postcard resources
+#include "PostcardLaf.h"
+#include "PostcardUtils.h"
+#include "Postcard.hrh"
+#include "PostcardOperationOpen.h"
+#include "PostcardRecipientWrapper.h"
+#include "PostcardContact.h"
+#include "PostcardPrivateCRKeys.h" // cenrep keys
+#include "PostcardCenRep.h"
+
+// ========== EXTERNAL DATA STRUCTURES =====================
+
+// ========== EXTERNAL FUNCTION PROTOTYPES =================
+
+// ========== CONSTANTS ====================================
+
+// ========== MACROS =======================================
+
+// ========== LOCAL CONSTANTS AND MACROS ===================
+
+// This was "FN" in 3.0-3.1 but OMA says it should be "N". Accept
+// both when opening and be compatible with both.
+_LIT8(KPostcardVCardName, "N");
+_LIT8(KPostcardVCardNameFN, "FN");
+_LIT8(KPostcardVCardAddr, "ADR");
+
+// ========== MODULE DATA STRUCTURES =======================
+
+// ========== LOCAL FUNCTION PROTOTYPES ====================
+
+// ========== LOCAL FUNCTIONS ==============================
+
+// ========== MEMBER FUNCTIONS =============================
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::NewL
+// ---------------------------------------------------------
+CPostcardOperationOpen* CPostcardOperationOpen::NewL(
+ MPostcardOperationObserver& aObserver,
+ CPostcardDocument& aDocument,
+ CPostcardAppUi& aAppUi,
+ RFs& aFs )
+ {
+ CPostcardOperationOpen* self =
+ new ( ELeave ) CPostcardOperationOpen( aObserver, aDocument, aAppUi, aFs );
+ CleanupStack::PushL( self );
+ self->ConstructL( );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::CPostcardOperationOpen
+// ---------------------------------------------------------
+CPostcardOperationOpen::CPostcardOperationOpen(
+ MPostcardOperationObserver& aObserver,
+ CPostcardDocument& aDocument,
+ CPostcardAppUi& aAppUi,
+ RFs& aFs ) :
+ CPostcardOperation( aObserver, aDocument, aAppUi, aFs ),
+ iSpecialFormat( aAppUi.CenRep().GetString( KPocaKeyServiceSpecialFormat ) ),
+ iSeparatorChar( aAppUi.CenRep().GetString( KPocaKeyServiceSeparator ) )
+ {
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::CPostcardOperationOpen
+// ---------------------------------------------------------
+CPostcardOperationOpen::~CPostcardOperationOpen( )
+ {
+ if( iEditFile )
+ {
+ iEditFile->Close();
+ delete iEditFile;
+ }
+ delete iImageInfo;
+ delete iImageProcessor;
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::Start
+// ---------------------------------------------------------
+void CPostcardOperationOpen::Start( TInt /*aArgument*/ )
+ {
+ ToState( EPostcardOpenInitializing );
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::Launch
+// ---------------------------------------------------------
+void CPostcardOperationOpen::DoLaunchStepL()
+ {
+ iFlags &= ~EPostcardOpenRequestActive;
+ switch ( iLaunchState )
+ {
+ case EPostcardOpenInitializing:
+ {
+ InitL( );
+ iDocument.InitializeL( iFs );
+ ToState( EPostcardOpenCheckAttas );
+ break;
+ }
+ case EPostcardOpenCheckAttas:
+ {
+ if( !CheckAttasL( ) )
+ { // If there was error, this has been completed already
+ ToState( EPostcardOpenHandleImage );
+ }
+ else
+ {
+ iLaunchState = EPostcardOpenError;
+ }
+ break;
+ }
+ case EPostcardOpenHandleImage:
+ {
+ DoHandleImageL( );
+ break;
+ }
+ case EPostcardOpenProcessImage:
+ {
+ DoStartProcessImageL( );
+ break;
+ }
+ case EPostcardOpenHandleText:
+ {
+ DoHandleTextL( );
+ break;
+ }
+ case EPostcardOpenHandleRecipient:
+ {
+ DoHandleRecipientL( );
+ ToState( EPostcardOpenFinished );
+ break;
+ }
+ case EPostcardOpenFinished:
+ {
+ UnInitL( );
+ iObserver.PostcardOperationEvent(
+ EPostcardOperationOpen,
+ EPostcardOperationComplete );
+ break;
+ }
+ default:
+ UnInitL( );
+ iObserver.PostcardOperationEvent(
+ EPostcardOperationOpen,
+ EPostcardOperationError );
+ break;
+ }
+ }
+
+// ---------------------------------------------------------
+// DoHandleL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::DoHandleImageL( )
+ {
+ if ( iImage != 0 )
+ {
+ if( iDocument.MessageType( ) == EPostcardSendAs )
+ { // SendAs -> Lets see what's inside
+ RFile imageFile = iManager->GetAttachmentFileL( iImage );
+ CleanupClosePushL( imageFile );
+ iImageInfo = iDocument.MediaResolver()->CreateMediaInfoL( imageFile );
+ iDocument.MediaResolver()->ParseInfoDetailsL( iImageInfo, imageFile );
+
+ // Lets first check if the file seems to be ok for inserting
+ if( iImageInfo->Protection( ) )
+ {
+ CleanupStack::PopAndDestroy( &imageFile ); // imageFile
+ ToErrorState( R_POSTCARD_CANNOT_SEND_PROTECTED );
+ return;
+ }
+ if( iImageInfo->Corrupt( ) )
+ {
+ // Corrupt is set to only supported media types
+ CleanupStack::PopAndDestroy( &imageFile ); // imageFile
+ ToErrorState( R_POSTCARD_OBJECT_CORRUPTED );
+ return;
+ }
+ else if ( !iDocument.IsImage( iImageInfo->MimeType( ) ) )
+ {
+ CleanupStack::PopAndDestroy( &imageFile ); // imageFile
+ ToErrorState( R_POSTCARD_FORMAT_NOT_SUPPORTED );
+ return;
+ }
+ else if ( iImageInfo->MediaType() != EMsgMediaImage )
+ {
+ CleanupStack::PopAndDestroy( &imageFile ); // imageFile
+ ToErrorState( R_POSTCARD_FORMAT_NOT_SUPPORTED );
+ return;
+ }
+ else if ( static_cast<CMsgImageInfo*>(iImageInfo)->IsAnimation( ) )
+ {
+ CleanupStack::PopAndDestroy( &imageFile ); // imageFile
+ ToErrorState( R_POSTCARD_FORMAT_NOT_SUPPORTED );
+ return;
+ }
+
+ TSize dimensions = static_cast<CMsgImageInfo*>(iImageInfo)->Dimensions( );
+ TInt imageWidth = dimensions.iWidth>dimensions.iHeight?dimensions.iWidth:dimensions.iHeight;
+ TInt imageHeight = dimensions.iWidth>dimensions.iHeight?dimensions.iHeight:dimensions.iWidth;
+
+ TSize maxSize = iDocument.MaxImageDimensions( );
+
+ // OK, it seems to be pretty ok, now lets see what we can do
+ if( ( iImageInfo->MimeType( ).CompareF( KMsgMimeImagePng ) == 0 )
+ || ( ( imageWidth > maxSize.iWidth || imageHeight > maxSize.iHeight )
+ && iImageInfo->FileSize( ) > iDocument.MaxImageSize( ) ) )
+ { // This is PNG or it's a too wide JPEG file
+ iEditFile = new ( ELeave ) RFile;
+ CMsvAttachment* attachment = CMsvAttachment::NewL( CMsvAttachment::EMsvFile );
+ CleanupStack::PushL( attachment );
+ attachment->SetAttachmentNameL( KPostcardFilenameScaled );
+ iManager->CreateAttachmentL( KPostcardFilenameScaled, *iEditFile, attachment, iStatus );
+ iFlags |= EPostcardOpenRequestActive;
+ CleanupStack::Pop( attachment ); // attachment
+ iEditAtta = attachment;
+ iLaunchState = EPostcardOpenProcessImage;
+ SetActive();
+ CleanupStack::PopAndDestroy( &imageFile ); // imagefile
+ return;
+ }
+ else if( iImageInfo->FileSize( ) > iDocument.MaxImageSize( ) )
+ { // Image is too big, but not too wide -> create empty attachment for now
+ iEditFile = new ( ELeave ) RFile;
+ CMsvAttachment* attachment = CMsvAttachment::NewL( CMsvAttachment::EMsvFile );
+ CleanupStack::PushL( attachment );
+ attachment->SetAttachmentNameL( KPostcardFilenameCompressed );
+ iManager->CreateAttachmentL( KPostcardFilenameCompressed, *iEditFile, attachment, iStatus );
+ iFlags |= EPostcardOpenRequestActive;
+ CleanupStack::Pop( attachment ); // attachment
+ iEditAtta = attachment;
+ iLaunchState = EPostcardOpenProcessImage;
+ SetActive();
+ CleanupStack::PopAndDestroy( &imageFile ); // imagefile
+ return;
+ }
+ else
+ { // OK, the file is ok, we just need to update the MsvHeaders
+ DoUpdateSendasAttachmentL( iImageInfo->MimeType( ) );
+ }
+ CleanupStack::PopAndDestroy( ); // imagefile
+ }
+ // Either this is not sendas or the image did not need conversion or compression
+ RFile imageFile = iManager->GetAttachmentFileL( iImage );
+ CleanupClosePushL( imageFile );
+
+ // Scale image to bitmap to be drawn on the screen
+ iSourceImage = IHLImageFactory::OpenFileImageL( imageFile );
+ iDestinationBitmap = IHLBitmap::CreateL();
+ iImageHandler = IHLViewerFactory::CreateImageViewerL( PostcardLaf::Image( ).Size( ),
+ *iSourceImage,
+ *iDestinationBitmap,
+ *this,
+ TUint32( 0 ) );
+ User::LeaveIfError( iImageHandler->SetSourceRectPosition( TPoint( 0, 0 ) ) );
+
+ CleanupStack::PopAndDestroy( &imageFile ); // imageFile
+ }
+ else
+ {
+ ToState( EPostcardOpenHandleText );
+ }
+ }
+
+// ---------------------------------------------------------
+// DoStartProcessImageL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::DoStartProcessImageL( )
+ {
+ RFile sourceFile = iManager->GetAttachmentFileL( iImage );
+ CleanupClosePushL( sourceFile );
+ if( !iImageProcessor )
+ {
+ iImageProcessor = new (ELeave) CUniImageProcessor( this );
+ }
+ TSize maxDimensions = iDocument.MaxImageDimensions( );
+
+ TSize origDimensions = static_cast<CMsgImageInfo*>(iImageInfo)->Dimensions( );
+
+ if( origDimensions.iWidth < origDimensions.iHeight )
+ { // It's portrait so swap max dimensions
+ origDimensions = maxDimensions;
+ maxDimensions.iWidth = origDimensions.iHeight;
+ maxDimensions.iHeight = origDimensions.iWidth;
+ }
+
+ iImageProcessor->ProcessImageL( sourceFile,
+ *iEditFile,
+ maxDimensions,
+ KMsgMimeImageJpeg,
+ ETrue,
+ iDocument.MaxImageSize( ) );
+ CleanupStack::PopAndDestroy(); // sourceFile
+ }
+
+// ---------------------------------------------------------
+// DoUpdateSendasAttachmentL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::DoUpdateSendasAttachmentL( const TDataType& aMimeType )
+ {
+ CMsvMimeHeaders* headers = CMsvMimeHeaders::NewLC( );
+ if( aMimeType.Des8( ).CompareF( KMsgMimeImageGif ) == 0 )
+ { // Image is gif
+ headers->SetContentLocationL( KPostcardFilenameNoOpGif);
+ }
+ else
+ {
+ headers->SetContentLocationL( KPostcardFilenameNoOp );
+ }
+ headers->SetContentTypeL( aMimeType.Des8( ) );
+
+ // As this function is called only when in SendAs
+ // there's certainly just one attachment so we index it directly
+ CMsvAttachment* attachment = iManager->GetAttachmentInfoL( 0 );
+ CleanupStack::PushL( attachment );
+ headers->StoreL( *attachment );
+ attachment->SetMimeTypeL( aMimeType.Des8( ) );
+ iStore->AttachmentManagerExtensionsL( ).ModifyAttachmentInfoL( attachment );
+ CleanupStack::Pop( attachment );
+
+ CleanupStack::PopAndDestroy( headers );
+
+ iStore->Commit( );
+ // Lets check again (to get right AttachmentIds)
+ CheckAttasL( );
+ }
+
+// ---------------------------------------------------------
+// ImageProcessingReady
+// ---------------------------------------------------------
+void CPostcardOperationOpen::ImageProcessingReady( TSize aBitmapSize, TInt aFileSize, TBool /*aCompressed*/ )
+ {
+ if( iEditFile )
+ {
+ iEditFile->Close();
+ delete iEditFile;
+ iEditFile = NULL;
+ }
+
+ TBool imageFits = EFalse;
+ TSize maxDimensions = iDocument.MaxImageDimensions( );
+ if( aBitmapSize.iWidth <= maxDimensions.iWidth &&
+ aBitmapSize.iHeight <= maxDimensions.iHeight )
+ {
+ imageFits = ETrue;
+ }
+ else if( aBitmapSize.iWidth <= maxDimensions.iHeight &&
+ aBitmapSize.iHeight <= maxDimensions.iWidth )
+ {
+ imageFits = ETrue;
+ }
+
+ if( !imageFits || aFileSize > iDocument.MaxImageSize( ) )
+ { // The process was not successful
+ ToErrorState( R_POSTCARD_PROCESS_NOT_SUCCESSFUL );
+ return;
+ }
+
+ // Call this to start scaling to screen (deletes the previous image etc..)
+ TRAPD( err, StartScalingToScreenL( ) );
+ if( err )
+ {
+ ToErrorState( R_POSTCARD_FORMAT_NOT_SUPPORTED );
+ }
+ }
+
+// ---------------------------------------------------------
+// StartScalingToScreenL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::StartScalingToScreenL( )
+ {
+ TInt oldImage = TMsvIdToIndexL( iImage );
+ iStore->AttachmentManagerExtensionsL( ).RemoveAttachmentL( oldImage );
+ iStore->Commit( );
+
+ DoUpdateSendasAttachmentL( iImageInfo->MimeType( ) );
+
+ // Lets add headers
+ RFile imageFile = iManager->GetAttachmentFileL( iImage );
+ CleanupClosePushL( imageFile );
+
+ iSourceImage = IHLImageFactory::OpenFileImageL( imageFile );
+ iDestinationBitmap = IHLBitmap::CreateL();
+
+ iImageHandler = IHLViewerFactory::CreateImageViewerL( PostcardLaf::Image( ).Size( ),
+ *iSourceImage,
+ *iDestinationBitmap,
+ *this,
+ TUint32( 0 ) );
+ User::LeaveIfError( iImageHandler->SetSourceRectPosition( TPoint( 0, 0 ) ) );
+
+ CleanupStack::PopAndDestroy( &imageFile ); // imageFile
+ }
+
+// ---------------------------------------------------------
+// ViewerBitmapChangedL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::ViewerBitmapChangedL()
+ {
+ CFbsBitmap* bitmap = new (ELeave) CFbsBitmap;
+ CFbsBitmap* mask = NULL;
+ bitmap->Duplicate( iDestinationBitmap->Bitmap().Handle( ) );
+
+ if ( iDestinationBitmap->HasMask() )
+ {
+ mask = new (ELeave) CFbsBitmap;
+ mask->Duplicate( iDestinationBitmap->Mask().Handle( ) );
+ }
+
+ delete iDestinationBitmap;
+ iDestinationBitmap = NULL;
+
+ delete iSourceImage;
+ iSourceImage = NULL;
+
+ delete iImageHandler;
+ iImageHandler = NULL;
+
+ iLaunchState = EPostcardOpenHandleText;
+
+ CGulIcon* icon = NULL;
+ TRAPD( err, icon = CGulIcon::NewL( bitmap, mask ) );
+
+ if( err )
+ { // Lets nullify it if there was an error
+ icon = NULL;
+ }
+
+ iAppUi.SetImage( icon );
+
+ CompleteSelf( KErrNone );
+
+ }
+
+// ---------------------------------------------------------
+// ViewerError
+// ---------------------------------------------------------
+void CPostcardOperationOpen::ViewerError( TInt /*aError*/ )
+ {
+ ToErrorState( R_POSTCARD_FORMAT_NOT_SUPPORTED );
+ }
+
+// ---------------------------------------------------------
+// DoHandleTextL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::DoHandleTextL( )
+ {
+/* if ( iText != 0 )
+ { // Lets externalize the text itself
+ RFile file = iManager->GetAttachmentFileL( iText );
+
+ CMmsTextInfo* info = static_cast<CMmsTextInfo*>(iDocument.MediaResolver()->ResolveFileTransferInfoL( file ));
+ CleanupStack::PushL( info );
+ TUint attaCharset = info->CharacterSet();
+ CleanupStack::PopAndDestroy( info );
+ RFileReadStream input_stream( file );
+
+ CPlainText::TImportExportParam param;
+ param.iForeignEncoding = attaCharset; //charconvCharsetID;
+ param.iOrganisation = CPlainText::EOrganiseByParagraph;
+ CPlainText::TImportExportResult result;
+ TRAPD( error, text->ImportTextL( 0, input_stream, param, result) );
+ input_stream.Close( );
+ file.Close( );
+ }
+*/
+
+ TPostcardMsgType type = iDocument.MessageType( );
+ if( iText > 0 && type == EPostcardSendAs )
+ { // If type is SendAs and file is from Phonebook -> Handle this case first
+ CMsvAttachment* atta = iManager->GetAttachmentInfoL( iText );
+ CleanupStack::PushL( atta );
+ if( atta->AttachmentName( ).Find( _L("X-Nokia-PhonebookId_") ) != -1 )
+ {
+ // All right, it was from Phonebook
+ RFile file = iManager->GetAttachmentFileL( iText );
+ CleanupClosePushL( file );
+
+ CPostcardContact* contact = CPostcardContact::NewL( iFs );
+ CleanupStack::PushL( contact );
+ contact->FetchContactL( file );
+ DoHandlePhonebookSendAsL( *contact );
+ CleanupStack::PopAndDestroy( 3, atta ); // contact, file, atta
+
+ ToState( EPostcardOpenFinished );
+ return;
+ }
+ // Ok, it was not from Phonebook, so lets continue normally..
+ CleanupStack::PopAndDestroy( atta );
+ }
+
+ CPlainText* text = CPlainText::NewL( CEditableText::ESegmentedStorage, KPostcardDefaultGreetingSegment );
+ CleanupStack::PushL( text );
+
+ if ( iText > 0 )
+ { // Lets externalize the text itself
+ RFile file = iManager->GetAttachmentFileL( iText );
+ CleanupClosePushL( file );
+
+ CMsvAttachment* atta = iManager->GetAttachmentInfoL( iText );
+ CleanupStack::PushL( atta );
+
+ CMsvMimeHeaders* msvMime = CMsvMimeHeaders::NewLC();
+ msvMime->RestoreL( *atta );
+
+ TUint attaCharset = msvMime->MimeCharset( ); // only charset needed
+
+ CleanupStack::PopAndDestroy( 2, atta ); // mime, atta
+
+ if( attaCharset == 0 )
+ {
+ //assume US-ASCII - mandated by RFC 2046
+ attaCharset = KMmsUsAscii;
+ }
+
+ TUint finalCharset = iDocument.TextUtils()->MibIdToCharconvIdL( attaCharset );
+
+ RFileReadStream input_stream( file );
+
+ CPlainText::TImportExportParam param;
+ param.iForeignEncoding = finalCharset;
+ param.iOrganisation = CPlainText::EOrganiseByParagraph;
+ CPlainText::TImportExportResult result;
+ TRAP_IGNORE( text->ImportTextL( 0, input_stream, param, result) );
+ input_stream.Close( );
+ CleanupStack::PopAndDestroy( &file ); // file
+ }
+
+ if( type == EPostcardSendAs )
+ {
+ // Otherwise there's no text or text is just text
+ CleanupStack::Pop( text );
+ iAppUi.SetTextL( *text ); // AppUI takes the ownership
+ ToState( EPostcardOpenHandleRecipient );
+ return;
+ }
+ else if( type == EPostcardForward ||
+ type == EPostcardEdit ||
+ type == EPostcardSent ||
+ type == EPostcardDraft )
+ {
+ // The recipient might be added into the greeting text only when the entry
+ // is opened from Sent folder or is forwarded or edited
+ if( iSpecialFormat.Length( ) > 0 && text->DocumentLength( ) > 0 && iRecipient == 0 )
+ { // if special send format is defined and there's no separate recipient attachment
+ TPtrC16 textBuf ( text->Read( 0 ) );
+ if( textBuf.Find( iSeparatorChar ) != KErrNotFound )
+ { // There are separators -> this msg has been sent
+ // lets dig the recipient info from the text
+ DoHandleSpecialFormatOpenL( *text );
+ CleanupStack::PopAndDestroy( text );
+ ToState( EPostcardOpenFinished );
+ return;
+ }
+ else
+ {
+ // There are no separators -> we can normally continue
+ // and use "text" as the real greeting text
+ }
+ }
+ }
+ CleanupStack::Pop( text );
+ iAppUi.SetTextL( *text ); // AppUI takes the ownership
+ ToState( EPostcardOpenHandleRecipient );
+ }
+
+// ---------------------------------------------------------
+// DoHandleRecipientL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::DoHandleRecipientL( )
+ {
+ CContactCard* card = CContactCard::NewLC();
+
+ if( iRecipient != 0 )
+ {
+ TPostcardMsgType type = iDocument.MessageType( );
+
+ if( type == EPostcardForward )
+ { // We are opening a forward entry -> delete VCard
+ TInt oldImage = TMsvIdToIndexL( iRecipient );
+ iStore->AttachmentManagerExtensionsL( ).RemoveAttachmentL( oldImage );
+ iCommit = ETrue;
+ }
+ else
+ {
+ ParseRecipientL( *card );
+ }
+ }
+ CleanupStack::Pop( card );
+ iAppUi.SetRecipientL( *card ); //ownership moves.. the function does not leave before card is set as a member
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::ParseRecipientL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::ParseRecipientL( CContactCard& aContactCard )
+ {
+ RFile file = iManager->GetAttachmentFileL( iRecipient );
+ CleanupClosePushL( file );
+
+ CParserVCard* parser = CParserVCard::NewL();
+ CleanupStack::PushL(parser);
+
+ RFileReadStream vCardStream( file );
+ vCardStream.PushL();
+ MStreamBuf* buf = vCardStream.Source();
+ if( !buf )
+ {
+ User::Leave( KErrGeneral );
+ }
+
+ parser->InternalizeL(vCardStream);
+
+ vCardStream.Close();
+ vCardStream.Pop();
+
+ // Does not take ownership
+ CArrayPtr<CParserProperty>* arr = parser->ArrayOfProperties(EFalse);
+ for( TInt a = 0; a < arr->Count( ); a++ )
+ {
+ CParserProperty* prop = arr->At( a );
+ TPtrC8 propName = prop->Name();
+ CParserPropertyValue *propValue = prop->Value();
+ if( propValue )
+ {
+ if( propValue->Uid().iUid == KVersitPropertyCDesCArrayUid )
+ {
+ CParserPropertyValueCDesCArray* arrayProperty =
+ reinterpret_cast<CParserPropertyValueCDesCArray*>( propValue );
+ CDesCArray* values = arrayProperty->Value();
+ if( propName.Compare( KPostcardVCardName ) == 0 )
+ {
+ TPostcardUtils::AddContactFieldL( aContactCard,
+ TPostcardUtils::ContactItemNameFromId( EPostcardAddressName ),
+ values->MdcaPoint( 0 ) );
+ }
+ else if( propName.Compare( KPostcardVCardAddr ) == 0 )
+ {
+ // This is the order items are read from the VCard store
+ static const TInt indexToId[] =
+ {
+ 0, // PO Box in the array will be ignored
+ EPostcardAddressInfo, EPostcardAddressStreet,
+ EPostcardAddressCity, EPostcardAddressState,
+ EPostcardAddressZip, EPostcardAddressCountry
+ };
+ const TInt KNumIds =
+ sizeof( indexToId ) / sizeof( indexToId[0] );
+ TPostcardMsgType type = iDocument.MessageType();
+ // Skip PO Box at beginning of the array
+ for (TInt i = 1; i < values->Count() && i < KNumIds; i++)
+ {
+ TPtrC value = values->MdcaPoint(i);
+ // If viewing a sent postcard, all available fields are
+ // initialized. Otherwise the field is initialized if
+ // it's visible in address dialog (max. length is not zero).
+ if( value.Length() &&
+ ( type == EPostcardSent || iAppUi.MaxTextLength( indexToId[i] ) ) )
+ {
+ TPostcardUtils::AddContactFieldL( aContactCard,
+ TPostcardUtils::ContactItemNameFromId( indexToId[i] ),
+ value );
+ }
+ }
+ }
+ }
+ else if( propValue->Uid().iUid == KVersitPropertyHBufCUid )
+ {
+ // Postcard before S60 3.2 release used FN (full name) property.
+ // Since 3.2, N property is used
+ if( propName.Compare( KPostcardVCardNameFN ) == 0 )
+ {
+ TPostcardUtils::AddContactFieldL( aContactCard,
+ TPostcardUtils::ContactItemNameFromId( EPostcardAddressName ),
+ static_cast<CParserPropertyValueHBufC*>( propValue )->Value() );
+ }
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy( 2, &file ); // file, parser
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::ConstructL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::ConstructL( )
+ {
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::DoCancel
+// ---------------------------------------------------------
+void CPostcardOperationOpen::DoCancel( )
+ {
+ if( iManager )
+ {
+ if( iFlags & EPostcardOpenRequestActive )
+ {
+ iManager->CancelRequest();
+ }
+ }
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::RunL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::RunL( )
+ {
+ DoLaunchStepL( );
+ }
+
+// ---------------------------------------------------------
+// RunError
+// ---------------------------------------------------------
+TInt CPostcardOperationOpen::RunError( TInt aError )
+ {
+ iLaunchState = -1;
+ SetError( aError );
+ iObserver.PostcardOperationEvent(
+ EPostcardOperationOpen,
+ EPostcardOperationError );
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::DoHandlePhonebookSendAsL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::DoHandlePhonebookSendAsL( CPostcardContact& aContact )
+ {
+ CPostcardRecipientWrapper* recWrapper =
+ CPostcardRecipientWrapper::NewL( iDocument, iAppUi, aContact );
+ CleanupStack::PushL( recWrapper );
+
+ // First remove wait note so that the dialog can be shown
+ iAppUi.RemoveWaitNote( );
+
+ // Location asking is done in recipientWrapper
+ CPostcardContact::TLocation location;
+ TBool hasLocation = recWrapper->AskLocationL( location );
+ CleanupStack::PopAndDestroy( recWrapper );
+
+ iAppUi.ShowWaitNoteL( R_POSTCARD_WAIT_OPENING, EFalse );
+
+ if ( !hasLocation )
+ {
+ // Contact not found or cancel selected..
+ CContactCard* card = CContactCard::NewL();
+ // Ownership moves..
+ // The function does not leave before card is set as a member
+ iAppUi.SetRecipientL( *card );
+ CPlainText* emptyText = CPlainText::NewL(
+ CEditableText::ESegmentedStorage, KPostcardDefaultGreetingSegment );
+ // Ownership moves..
+ // The function does not leave before card is set as a member
+ iAppUi.SetTextL( *emptyText );
+ }
+ else
+ {
+ // Otherwise location now tells the chosen location
+
+ CContactCard* card = CContactCard::NewLC();
+ UpdateContactCardL( *card, aContact, location );
+
+ CleanupStack::Pop( card ); // card
+ // Ownership moves..
+ // The function does not leave before card is set as a member
+ iAppUi.SetRecipientL( *card );
+ iDocument.SetChanged( EPostcardRecipient );
+ iCommit = ETrue; // Remove the original atta way as it's just a phonebook atta
+ MMsvAttachmentManagerSync& managerSync = iStore->AttachmentManagerExtensionsL();
+ TInt textIndex = TMsvIdToIndexL( iText );
+ managerSync.RemoveAttachmentL( textIndex );
+ iText = 0;
+ CPlainText* emptyText = CPlainText::NewL(
+ CEditableText::ESegmentedStorage, KPostcardDefaultGreetingSegment );
+ // Ownership moves..
+ // The function does not leave before card is set as a member
+ iAppUi.SetTextL( *emptyText );
+ }
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::UpdateContactCardL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::UpdateContactCardL( CContactCard& aCard,
+ CPostcardContact& aContact, CPostcardContact::TLocation aLocation )
+ {
+
+ // Get contact name, combined last and first name
+ HBufC* contactName = aContact.GetNameLC();
+ if ( contactName->Length() )
+ {
+ // Create a new CContactCard field
+ AddContactCardFieldL( aCard, *contactName, EPostcardAddressName );
+ }
+ CleanupStack::PopAndDestroy( contactName ); // contactName
+
+ // Handle rest of the address fields
+ for( TInt i = EPostcardAddressInfo; i <= EPostcardAddressCountry; i++)
+ {
+ // Initialize address field only if it's visible to user
+ // (max. length is not zero)
+ if ( iAppUi.MaxTextLength( i ) )
+ {
+ HBufC* fieldText = aContact.GetAddressFieldLC( aLocation,
+ CPostcardContact::ControlIdToAddrField( i ) );
+ if ( fieldText->Length() )
+ {
+ // Create a new CContactCard field
+ AddContactCardFieldL( aCard, *fieldText, i );
+ }
+ CleanupStack::PopAndDestroy( fieldText ); // fieldText
+ }
+ }
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::AddContactCardFieldL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::AddContactCardFieldL( CContactCard& aCard,
+ const TPtrC& aText, TInt aFieldSelect )
+ {
+ TPostcardUtils::AddContactFieldL(aCard,
+ TPostcardUtils::ContactItemNameFromId( aFieldSelect ),
+ aText);
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::ParseSpecialFormatTextL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::ParseSpecialFormatTextL( CPlainText& aText,
+ CContactCard& aCard, CPlainText& aGreeting )
+ {
+ TPtrC format( iSpecialFormat );
+ TPtrC srcText( aText.Read( 0 , aText.DocumentLength() ) );
+
+ const TInt KTagLen = 3;
+
+ // Find tags from format and parse source text accordingly
+ TInt tag;
+ TInt position = TPostcardUtils::NextTag( format, tag );
+ // Eat prefix and tag from format. Assume the format has at least one tag.
+ format.Set( format.Right( format.Length() - position - KTagLen ) );
+ // Eat prefix from source text
+ srcText.Set( srcText.Right( srcText.Length() - position ) );
+ while( position != KErrNotFound )
+ {
+ TInt newTag;
+ position = TPostcardUtils::NextTag( format, newTag );
+ TPtrC text;
+ if ( position != KErrNotFound )
+ {
+ // Separator string from previous tag to this one. This cannot
+ // be empty, otherwise text fields cannot be separated from each other.
+ TPtrC separator( format.Left( position ) );
+ TInt separatorPos = srcText.Find( separator );
+ TInt srcLen = srcText.Length() - position - separatorPos;
+ if ( separatorPos == KErrNotFound || srcLen < 0 )
+ {
+ // Unexpected. Cannot parse.
+ return;
+ }
+ text.Set( srcText.Left( separatorPos ) );
+ // Eat separator and tag from format
+ format.Set( format.Right( format.Length() - position - KTagLen ) );
+ // Eat text and separator from source
+ srcText.Set( srcText.Right( srcLen ) );
+ }
+ else
+ {
+ // No new tags. Text is source string minus postfix
+ text.Set( srcText.Left( srcText.Length() - format.Length() ) );
+ }
+ if ( text.Length() )
+ {
+ if ( tag == 0 )
+ {
+ aGreeting.InsertL( 0, text );
+ }
+ else
+ {
+ if ( iDocument.MessageType() != EPostcardForward )
+ { // Add the fields only when not in Forward mode
+ TPostcardUtils::AddContactFieldL(aCard,
+ TPostcardUtils::ContactItemNameFromTag( tag ),
+ text);
+ }
+ }
+ }
+ tag = newTag;
+ }
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::DoHandleSpecialFormatOpenL
+// ---------------------------------------------------------
+void CPostcardOperationOpen::DoHandleSpecialFormatOpenL( CPlainText& aText )
+ {
+ CContactCard* newCard = CContactCard::NewLC(); // New ContactCard
+ CPlainText* newText = CPlainText::NewL( CEditableText::ESegmentedStorage, KPostcardDefaultGreetingSegment ); // New PlainText for greeting text
+ CleanupStack::PushL( newText );
+
+ ParseSpecialFormatTextL( aText, *newCard, *newText );
+
+ CleanupStack::Pop(); // newText
+ iAppUi.SetTextL( *newText ); // AppUI takes the ownership
+ CleanupStack::Pop(); // newCard
+ iAppUi.SetRecipientL( *newCard );
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::ToState
+// ---------------------------------------------------------
+void CPostcardOperationOpen::ToState( TPostcardOpenState aState )
+ {
+ iLaunchState = aState;
+ CompleteSelf( KErrNone );
+ }
+
+// ---------------------------------------------------------
+// CPostcardOperationOpen::ToErrorState
+// ---------------------------------------------------------
+void CPostcardOperationOpen::ToErrorState( TInt aResourceId )
+ {
+ SetError( aResourceId );
+ iLaunchState = EPostcardOpenError;
+ CompleteSelf( KErrCancel );
+ }
+
+// EOF