diff -r 000000000000 -r 8466d47a6819 emailuis/emailui/src/ncscomposeview.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emailuis/emailui/src/ncscomposeview.cpp Thu Dec 17 08:39:21 2009 +0200 @@ -0,0 +1,2960 @@ +/* +* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description : Compose view class +* +*/ + +// INCLUDE FILES +#include "emailtrace.h" +#include +#include +#include +#include +#include // +#include // +// +#include +#include "CFSMailBox.h" +#include "CFSMailMessage.h" +#include "CFSMailAddress.h" +#include "CFSMailClient.h" +#include "CFSMailCommon.h" +#include +// +// Touch +#include +#include +#include +// Touch +#include +#include + +#include "ncscomposeview.h" +#include "ncscomposeviewcontainer.h" +#include "ncsconstants.h" +#include "ncsutility.h" +#include "ncsemailaddressobject.h" +#include "FreestyleEmailCenRepHandler.h" +#include "FreestyleEmailUi.hrh" +#include "FreestyleEmailUiConstants.h" +#include "FreestyleEmailUiSendAttachmentsListControl.h" +#include "FreestyleEmailUiSendAttachmentsListVisualiser.h" +#include "FreestyleEmailUiSendAttachmentsListModel.h" +#include "FreestyleEmailUiUtilities.h" +#include "FreestyleEmailUiConstants.h" +#include "FSAutoSaver.h" +#include "FSEmail.pan" + + +// line separators that should not appear in Subject +_LIT(KLineSeparators, "\u2029"); +const TChar KReplacementChar = ' '; + + +#pragma mark +++COMPOSE VIEW - CONSTRUCTORS AND DESTRUCTORS + +// ----------------------------------------------------------------------------- +// Safe pointer deletion +// +// ----------------------------------------------------------------------------- +// +template void SafeDelete( T*& aPtr ) + { + delete aPtr; + aPtr = NULL; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::CNcsComposeView() +// C++ default constructor can NOT contain any code, that might leave. +// ----------------------------------------------------------------------------- +// +CNcsComposeView::CNcsComposeView( CFreestyleEmailUiAppUi& aAppUi, + CAlfEnv& aEnv, CAlfControlGroup& aSendAttachmentControlGroup, + CFSMailClient& aMailClient, CMsvSession& aMsvSession ) + : CFsEmailUiViewBase( aSendAttachmentControlGroup, aAppUi ), + iMailClient( aMailClient ), iOrigMessage( NULL ), iNewMessage( NULL ), + iMsvSession( aMsvSession ), iEnv( aEnv ) + ,iFakeSyncGoingOn(EFalse), iFetchDialogCancelled(EFalse),iExecutingDoExitL(EFalse)// + { + FUNC_LOG; + + iAttachmentListSaveDraft = EFalse; + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::NewL() +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CNcsComposeView* CNcsComposeView::NewL( CFSMailClient& aMailClient, CAlfEnv& aEnv, + CFreestyleEmailUiAppUi* aAppUi, CAlfControlGroup& aControlGroup, + CMsvSession& aMsvSession ) + { + FUNC_LOG; + + CNcsComposeView* self = CNcsComposeView::NewLC( aMailClient, aEnv, aAppUi, + aControlGroup, aMsvSession ); + CleanupStack::Pop( self ); + + return self; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::NewLC() +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CNcsComposeView* CNcsComposeView::NewLC( + CFSMailClient& aMailClient, + CAlfEnv& aEnv, + CFreestyleEmailUiAppUi* aAppUi, + CAlfControlGroup& aControlGroup, + CMsvSession& aMsvSession ) + { + FUNC_LOG; + + CNcsComposeView* self = new ( ELeave ) CNcsComposeView( *aAppUi, aEnv, aControlGroup, aMailClient, aMsvSession ); + CleanupStack::PushL( self ); + self->ConstructL(); + + return self; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::ConstructL() +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::ConstructL() + { + FUNC_LOG; + + BaseConstructL( R_NCS_COMPOSE_VIEW ); + iFirstStartCompleted = EFalse; + } + +// CFSEmailUiMsgDetailsVisualiser::DoFirstStartL() +// Purpose of this function is to do first start only when msg details is +// really needed to be shown. Implemented to make app startuo faster. +void CNcsComposeView::DoFirstStartL() + { + FUNC_LOG; + // Attachment list for compose screen + CAlfControlGroup& attListControlGroup = iEnv.NewControlGroupL( KSendAttachmentManagerDisplayGroup ); // owned by AlfEnv + CFSEmailUiSendAttachmentsListVisualiser* sendAttachmentVisualiser = + CFSEmailUiSendAttachmentsListVisualiser::NewLC( + iEnv, &iAppUi, attListControlGroup ); + iAppUi.AddViewL( sendAttachmentVisualiser ); + CleanupStack::Pop( sendAttachmentVisualiser ); + + iCrHandler = CFSEmailCRHandler::InstanceL(); // singleton, not owned + + iEnv.AddActionObserverL( this ); + + iAutoSaver = CFsAutoSaver::NewL( iEnv, KAutoSaveTimeDelayMs ); + iAutoSaver->Enable( EFalse ); + iFirstStartCompleted = ETrue; + iCheckQuery = EFalse; + iAsyncCallback = new (ELeave) CAsyncCallBack( CActive::EPriorityLow ); + // msk context menu added into composer + MenuBar()->SetContextMenuTitleResourceId( R_NCS_COMPOSE_BODY_MSK_MENUBAR ); + iActiveHelper = CActiveHelper::NewL(this); + + iAsyncAttachmentAdd = new (ELeave) CAsyncCallBack( CActive::EPriorityStandard ); + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::~CNcsComposeView() +// Destructor. +// ----------------------------------------------------------------------------- +// +CNcsComposeView::~CNcsComposeView() + { + FUNC_LOG; + delete iAutoSaver; + if ( iAsyncCallback ) + { + iAsyncCallback->Cancel(); + delete iAsyncCallback; + } + delete iFetchLogic; + if(iActiveHelper) + { + iActiveHelper->Cancel(); + delete iActiveHelper; + } + if (iAsyncAttachmentAdd) + { + iAsyncAttachmentAdd->Cancel(); + delete iAsyncAttachmentAdd; + } + } + +void CNcsComposeView::PrepareForExit() + { + FUNC_LOG; + if ( iCheckQuery && iDlg ) + { + TKeyEvent check = { EKeyEscape, EStdKeyNull, 0, 0 }; + TRAP_IGNORE( iDlg->OfferKeyEventL( check, EEventKey ) ); + iDlg = NULL; + + iAsyncCallback->Cancel(); // cancel any outstanding callback just to be safe + iAsyncCallback->Set( TCallBack( AsyncExit, this ) ); + iAsyncCallback->CallBack(); + } + else if(iFakeSyncGoingOn || iExecutingDoExitL) //we starts this low priority active obj so that iwait in plugins finish + { + iActiveHelper->Cancel(); + iActiveHelper->Start(); + } + else + { + DoSafeExit( ESaveDraft ); + //iAppUi.Exit(); + } + + if(iFetchLogic) + { + iFetchLogic->CancelFetchings(); + } + + //ResetComposer(); // already done in DoExitL + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::Id() +// Returns View's ID. +// ----------------------------------------------------------------------------- +// +TUid CNcsComposeView::Id() const + { + FUNC_LOG; + return MailEditorId; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::ChildDoActivateL() +// Activate the Compose view +// ----------------------------------------------------------------------------- +// +// Toolbar +/*void CNcsComposeView::DoActivateL( const TVwsViewId& aPrevViewId, + TUid aCustomMessageId, const TDesC8& aCustomMessage )*/ +void CNcsComposeView::ChildDoActivateL( const TVwsViewId& aPrevViewId, + TUid aCustomMessageId, const TDesC8& aCustomMessage ) +// Toolbar + { + FUNC_LOG; + if ( !iFirstStartCompleted ) + { + DoFirstStartL(); + } + Toolbar()->SetDimmed(ETrue); + // Set status pane indicators + iStatusPaneIndicators = iAppUi.GetStatusPaneIndicatorContainer(); + iStatusPaneIndicators->ShowStatusPaneIndicators(); + + // Notify base class about view being entered unless we returned from another view + if ( aCustomMessageId.iUid != KEditorCmdReturnToPrevious ) + { + ViewEntered( aPrevViewId ); + } + + // Cleanup the previous message before opening a new one + SaveAndCleanPreviousMessage(); + + // Get the launch parameters + if ( aCustomMessageId.iUid == KEditorCmdReturnToPrevious ) + { + // Use previous launch parameters when returning to previously open message + iMailBox = iMailClient.GetMailBoxByUidL( iLaunchParams.iMailboxId ); + } + else if ( aCustomMessage.Length() > 0 ) + { + + TPckgBuf buf( iLaunchParams ); + buf.Copy( aCustomMessage ); + iLaunchParams = buf(); + iMailBox = iMailClient.GetMailBoxByUidL( iLaunchParams.iMailboxId ); + + } + else + { + iLaunchParams.iActivatedExternally = ETrue; + } + + // Inform the AppUi about external view activation to fix the view stack. Normally + // this happens based on the previous view AppUid in the BaseView but in case + // contacts action menu was used within FsEmail, this doesn' work. It doesn't + // hurt to call this again even if it was already called once from BaseView. + if ( iLaunchParams.iActivatedExternally ) + { + iAppUi.ViewActivatedExternallyL( Id() ); + } + + // Try to get the mailbox by other means if using launch parameters failed + if ( !iMailBox ) + { + TInt error( KErrNone ); + + // can we get it from MSV Id + // MSV id is passed to us when account is defined email key settings + if ( aCustomMessageId != TUid::Null() ) + { + TRAP( error, iMailBox = TFsEmailUiUtility::GetMailboxForMtmIdL( iMailClient, iMsvSession, aCustomMessageId.iUid ) ); + } + + error = KErrNone; + + // try to use mailbox set as default in MCE + if ( !iMailBox ) + { + TRAP( error, iMailBox = TFsEmailUiUtility::GetMceDefaultMailboxL( iMailClient, iMsvSession ) ); + } + + // use first mail account from the list + if ( !iMailBox ) + { + TFSMailMsgId id; + RPointerArray mailboxes; + CleanupResetAndDestroyClosePushL( mailboxes ); + iMailClient.ListMailBoxes( id, mailboxes ); + if ( mailboxes.Count() > 0 ) + { + iMailBox = iMailClient.GetMailBoxByUidL( mailboxes[0]->GetId() ); + } + CleanupStack::PopAndDestroy( &mailboxes ); + } + + // could not get mailbox so leave + if ( !iMailBox ) + { + User::Leave( KErrGeneral ); + } + + aCustomMessageId = TUid::Uid( KEditorCmdCreateNew ); + } + + + iMailSent = EFalse; + iMailSendFailed = EFalse; + iCustomMessageId = aCustomMessageId; + + CreateContainerL(); + + TRAPD( err, HandleActivationCommandL( aCustomMessageId ) ); + if ( !err ) + { + err = iMailFetchingErrCode; + } + + if ( err == KErrCancel || err == KErrCouldNotConnect || err == KErrConnectionTerminated ) + { + // Just close composer without any notes if operation was cancelled. For connection + // errors, DownloadInfoMediator already shows error message, so no need to show another one. + ExitComposer(); + } + else if ( err ) + { + // some other error => show generic error note and close composer + if(!iAppUi.AppUiExitOngoing()) // + TFsEmailUiUtility::ShowErrorNoteL( R_FREESTYLE_EMAIL_ERROR_GENERAL_UNABLE_TO_COMPLETE, ETrue ); + ExitComposer(); + } + else + { + // everything went fine => do rest of the generic initialization + InitUiGeneralL(); + iAppUi.StartEndKeyCapture(); + iContainer->SetMskL(); + iViewReady = ETrue; + Toolbar()->SetDimmed(EFalse); + RefreshToolbar(); + } + } + + +// ----------------------------------------------------------------------------- +// CNcsComposeView::OfferToolbarEventL +// ----------------------------------------------------------------------------- +void CNcsComposeView::OfferToolbarEventL( TInt aCommand ) + { + FUNC_LOG; + bool attachmentAddition = EFalse; + switch (aCommand) + { + case EFsEmailUiTbCmdSend: + if (iContainer && iContainer->AreAddressFieldsEmpty()) + { + RefreshToolbar(); + } + else + { + HandleCommandL( ENcsCmdSend ); + } + break; + case EFsEmailUiTbCmdAddRecipient: + if (iContainer) + { + iContainer->AppendAddressesL(); + } + break; + case EFsEmailUiTbCmdInsertAudio: + iAttachmentAddType = MsgAttachmentUtils::EAudio; + attachmentAddition = ETrue; + break; + case EFsEmailUiTbCmdInsertImage: + iAttachmentAddType = MsgAttachmentUtils::EImage; + attachmentAddition = ETrue; + break; + case EFsEmailUiTbCmdInsertVideo: + iAttachmentAddType = MsgAttachmentUtils::EVideo; + attachmentAddition = ETrue; + break; + case EFsEmailUiTbCmdInsertNote: + iAttachmentAddType = MsgAttachmentUtils::ENote; + attachmentAddition = ETrue; + break; + case EFsEmailUiTbCmdInsertPresentation: + iAttachmentAddType = MsgAttachmentUtils::ESVG; + attachmentAddition = ETrue; + break; + case EFsEmailUiTbCmdInsertOther: + iAttachmentAddType = MsgAttachmentUtils::EUnknown; + attachmentAddition = ETrue; + break; + default: + break; + } + if (attachmentAddition) + { + iAsyncAttachmentAdd->Cancel(); // cancel any outstanding callback just to be safe + iAsyncAttachmentAdd->Set( TCallBack( AsyncAddAttachment, this ) ); + iAsyncAttachmentAdd->CallBack(); + } + } + +// Toolbar +// ----------------------------------------------------------------------------- +// CNcsComposeView::ToolbarResourceId() +// ----------------------------------------------------------------------------- +// +TInt CNcsComposeView::ToolbarResourceId() const + { + FUNC_LOG; + return R_FREESTYLE_EMAIL_UI_TOOLBAR_MESSAGE_EDITOR; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::GetInitiallyDimmedItemsL() +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::GetInitiallyDimmedItemsL( const TInt aResourceId, + RArray& aDimmedItems ) const + { + FUNC_LOG; + aDimmedItems.Reset(); + switch (aResourceId) + { + case R_FREESTYLE_EMAIL_UI_TOOLBAR_MESSAGE_EDITOR: + aDimmedItems.AppendL(EFsEmailUiTbCmdSend); + break; + default: + break; + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::RefreshToolbar() +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::RefreshToolbar() + { + FUNC_LOG; + if (iContainer) + { + // DimAllOptions if remotesearch is in progress, cos it takes you in a different view + TBool dimAllOptions = iContainer->IsRemoteSearchInprogress(); + SetToolbarItemDimmed( EFsEmailUiTbCmdExpandInsert, dimAllOptions ); + SetToolbarItemDimmed( EFsEmailUiTbCmdSend, + iContainer->AreAddressFieldsEmpty() ); + if ( (iContainer->IsFocusBcc() || iContainer->IsFocusCc() || iContainer->IsFocusTo()) && !dimAllOptions ) + { + SetToolbarItemDimmed( EFsEmailUiTbCmdAddRecipient, EFalse ); + } + else + { + SetToolbarItemDimmed( EFsEmailUiTbCmdAddRecipient, ETrue ); + } + } + } +// Toolbar + + +// ----------------------------------------------------------------------------- +// CNcsComposeView::ChildDoDeactivate() +// Deactivate the Compose view +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::ChildDoDeactivate() + { + FUNC_LOG; + + iAppUi.StopEndKeyCapture(); + + SafeDelete( iFetchLogic ); + + // Normally Comopser state has been already cleaned by now but in special + // cases (like external view activation while in Composer) this may not be + // the case. In those cases the message needs to be saved before the view + // is deactivated. + if ( !iAppUi.AppUiExitOngoing() ) + { + SaveAndCleanPreviousMessage(); + } + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::DynInitMenuPaneL() +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::DynInitMenuPaneL( TInt aResourceId, + CEikMenuPane* aMenuPane ) + { + FUNC_LOG; + + if ( !iViewReady ) + { + User::Leave( KErrNcsComposeViewNotReady ); + } + + __ASSERT_DEBUG( iContainer, Panic( ENcsBasicUi ) ); + __ASSERT_DEBUG( iMailBox, Panic( ENcsBasicUi ) ); + __ASSERT_DEBUG( iNewMessage, Panic( ENcsBasicUi ) ); + + // + //we are forbiding to change MSK label, cause popup will be opend + iContainer->SwitchChangeMskOff(ETrue); + // + + if ( aResourceId == R_NCS_COMPOSE_MENU ) + { + if (FeatureManager::FeatureSupported( KFeatureIdFfCmailIntegration )) + { + // remove help support in pf5250 + aMenuPane->SetItemDimmed( EAknCmdHelp, ETrue); + } + + // Disable send if there are no addresses in any of the AIF fields, + if ( iContainer->AreAddressFieldsEmpty() ) + { + aMenuPane->DeleteMenuItem( ENcsCmdSend ); + } + + // If no attachments currently, delete the remove attachments menu item + CFreestyleEmailUiSendAttachmentsListControl* attachmentControl; + attachmentControl = AttachmentsListControl(); + TInt count = attachmentControl->Model()->Count(); + + // if mail has remote attachments then attachments can't be removed via options menu + if ( count <= 0 || AttachmentsListControl()->Model()->HasReadOnlyAttachments() ) + { + aMenuPane->DeleteMenuItem( ENcsCmdRemoveAttachment ); + aMenuPane->DeleteMenuItem( ENcsCmdRemoveAllAttachments ); + } + else if ( count == 1 ) + { + aMenuPane->DeleteMenuItem( ENcsCmdRemoveAllAttachments ); + } + else + { + aMenuPane->DeleteMenuItem( ENcsCmdRemoveAttachment ); + } + + if ( iContainer->GetCcFieldLength() > 0 && + iContainer->GetBccFieldLength() > 0 ) + { + aMenuPane->DeleteMenuItem( ENcsCmdMore ); + } + + if ( !TFsEmailUiUtility::IsFollowUpSupported( *iMailBox ) ) + { + aMenuPane->DeleteMenuItem( ENcsCmdFlag ); + } + } + + if ( aResourceId == R_NCS_MORE_MENU ) + { + // Select which View->CC menu items to show + if ( iContainer->IsCcFieldVisible() ) + { + aMenuPane->DeleteMenuItem( ENcsCmdShowCc ); + // if there is text in Cc field do not show "hide Cc" menu item + if ( iContainer->GetCcFieldLength() > 0 ) + { + aMenuPane->DeleteMenuItem( ENcsCmdHideCc ); + } + } + else + { + aMenuPane->DeleteMenuItem( ENcsCmdHideCc ); + } + + // Select which View->BCC menu items to show + if ( iContainer->IsBccFieldVisible() ) + { + aMenuPane->DeleteMenuItem( ENcsCmdShowBcc ); + // if there is text in Bcc field do not show "hide Bcc" menu item + if ( iContainer->GetBccFieldLength() > 0 ) + { + aMenuPane->DeleteMenuItem( ENcsCmdHideBcc ); + } + } + else + { + aMenuPane->DeleteMenuItem( ENcsCmdHideBcc ); + } + } + + if ( aResourceId == R_NCS_PRIORITY_MENU ) + { + + if ( iNewMessage->IsFlagSet( EFSMsgFlag_Important ) ) + { + aMenuPane->DeleteMenuItem( ENcsCmdPriorityHigh ); + } + else if ( iNewMessage->IsFlagSet( EFSMsgFlag_Low ) ) + { + aMenuPane->DeleteMenuItem( ENcsCmdPriorityLow ); + } + else + { + aMenuPane->DeleteMenuItem( ENcsCmdPriorityNormal ); + } + } + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::HandleCommandL() +// Takes care of Command handling. +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::HandleCommandL( TInt aCommand ) + { + FUNC_LOG; + + // Attempt to handle commands only after view is fully activated and exit has not yet been initiated. + if ( iViewReady && !iAppUi.ViewSwitchingOngoing() ) + { + __ASSERT_DEBUG( iContainer, Panic( ENcsBasicUi ) ); + __ASSERT_DEBUG( iNewMessage, Panic( ENcsBasicUi ) ); + __ASSERT_DEBUG( iCrHandler, Panic( ENcsBasicUi ) ); + + switch( aCommand ) + { + case ENcsCmdSend: + { + // Show query if the Subject field is empty (default text is as subject) + if ( iContainer->IsSubjectFieldEmpty() ) + { + TInt answer = TFsEmailUiUtility::ShowConfirmationQueryL( R_FREESTYLE_EMAIL_QUERY_NO_SUBJECT ); + if ( !answer ) + { + // user didn't want to send yet -> go back to the message + return; + } + } + + TRAPD( error, DoSendL() ); + if ( !error ) + { + // Sending successful + HBufC* confMessage = NULL; + if ( !TFsEmailUiUtility::IsOfflineModeL() ) + { + // when sync status is currently ONLINE + confMessage = StringLoader::LoadLC( R_FREESTYLE_EMAIL_CONFIRM_NOTE_SENDING_QUEUED ); + } + else + { + // when sync status is currently OFFLINE + confMessage = StringLoader::LoadLC( R_FREESTYLE_EMAIL_CONFIRM_NOTE_QUEUED_UNTIL_ONLINE ); + } + CAknConfirmationNote* note = new (ELeave) CAknConfirmationNote( ETrue ); //waiting + note->SetTimeout( CAknNoteDialog::ELongTimeout ); + note->ExecuteLD( *confMessage ); + CleanupStack::PopAndDestroy( confMessage ); + DoSafeExit(); // Exit after successful sending + } + else if ( error == KErrBadName ) + { + // sending failed because recipient address was invalid + TFsEmailUiUtility::ShowErrorNoteL( R_FREESTYLE_EMAIL_CONFIRM_NOTE_INVALID_EMAIL_ADDRESS, ETrue ); + } + else + { + // sending failed for some other reason + TFsEmailUiUtility::ShowErrorNoteL( R_FREESTYLE_EMAIL_CONFIRM_NOTE_MESSAGE_NOT_SENT, ETrue ); + DoSafeExit(); // Exit after sending failed for other reason than KErrBadName + } + } + break; + case ENcsCmdAddAttachment: + { + // Touch + if ( AknLayoutUtils::PenEnabled() ) + { + // show the toolbar + UpdateToolbarL(); + if ( Toolbar() && Toolbar()->ToolbarExtension() ) + { + Toolbar()->ToolbarExtension()->SetShown( ETrue ); + } + } + else + { + // + iAttachmentAddType = MsgAttachmentUtils::EUnknown; + iAsyncAttachmentAdd->Cancel(); // cancel any outstanding callback just to be safe + iAsyncAttachmentAdd->Set( TCallBack( AsyncAddAttachment, this ) ); + iAsyncAttachmentAdd->CallBack(); + iContainer->SetMskL(); + // Touch + } + // + } + break; + case EFsEmailUiCmdOpenAttachment: + case EFsEmailUiCmdOpenAttachmentList: + { + DoOpenAttachmentListL(); + } + break; + case ENcsCmdRemoveAttachment: // remove one and only attachment + case ENcsCmdRemoveAllAttachments: + { + AttachmentsListControl()->RemoveAllAttachmentsL(); + SetAttachmentLabelContentL(); + } + break; + case ENcsCmdPriorityHigh: + { + iNewMessage->ResetFlag( EFSMsgFlag_Low ); + iNewMessage->SetFlag( EFSMsgFlag_Important ); + iNewMessage->SaveMessageL(); + iStatusPaneIndicators->SetPriorityFlag(EMsgPriorityHigh); + } + break; + case ENcsCmdPriorityNormal: + { + iNewMessage->ResetFlag( EFSMsgFlag_Low ); + iNewMessage->ResetFlag( EFSMsgFlag_Important ); + iNewMessage->SaveMessageL(); + iStatusPaneIndicators->SetPriorityFlag(EMsgPriorityNormal); + } + break; + case ENcsCmdPriorityLow: + { + iNewMessage->ResetFlag( EFSMsgFlag_Important ); + iNewMessage->SetFlag( EFSMsgFlag_Low ); + iNewMessage->SaveMessageL(); + iStatusPaneIndicators->SetPriorityFlag(EMsgPriorityLow); + } + break; + case ENcsCmdShowCc: + { + iContainer->SetCcFieldVisibleL( ETrue ); + iCrHandler->SetEditorCCVisible( 1 ); + } + break; + case ENcsCmdHideCc: + { + iContainer->SetCcFieldVisibleL( EFalse ); + iCrHandler->SetEditorCCVisible( 0 ); + } + break; + case ENcsCmdShowBcc: + { + iContainer->SetBccFieldVisibleL( ETrue ); + iCrHandler->SetEditorBCVisible( 1 ); + } + break; + case ENcsCmdHideBcc: + { + iContainer->SetBccFieldVisibleL( EFalse ); + iCrHandler->SetEditorBCVisible( 0 ); + } + break; + case ENcsCmdFlag: + { + RunFollowUpFlagDlgL(); + } + break; + case ENcsCmdQuickText: + { + DoQuickTextL(); + } + break; + case ENcsCmdInsertContact: + case ENcsInsertContact: + { + iContainer->AppendAddressesL(); + } + break; + case ENcsCmdSaveDraft: + { + + iContainer->FixSemicolonL(); + + + TRAPD( saveDraftError, DoSaveDraftL( EFalse ) ); + if ( saveDraftError == KErrNone ) + { + // Saving successful + if(!iAppUi.AppUiExitOngoing()) // + TFsEmailUiUtility::ShowInfoNoteL( R_FREESTYLE_EMAIL_CONFIRM_NOTE_SAVED_TO_DRAFTS, ETrue ); + } + else + { + // error occured in saving -> show an error message + if(!iAppUi.AppUiExitOngoing()) // + TFsEmailUiUtility::ShowErrorNoteL( R_FREESTYLE_EMAIL_ERROR_GENERAL_UNABLE_TO_COMPLETE, ETrue ); + } + + DoSafeExit( ENoSave ); + } + break; + case EAknCmdHelp: + { + TFsEmailUiUtility::LaunchHelpL( KFSE_HLP_LAUNCHER_GRID ); + } + break; + case EAknSoftkeySelect: + { + iContainer->DoPopupSelectL(); + } + break; + case EAknSoftkeyCancel: + { + iContainer->ClosePopupContactListL(); + } + break; + case EAknSoftkeyClose: + { + DoSafeExit(); + } + break; + case ENcsCmdExit: + { + // This is for a special case when SaveDeleteQuery appears and user presses immediately End key + // we are first checking if Queryexists ,if yes then we forward event to iDlg->offerkeyEventL and + // then call Asynchronously Exit method so that iDlg->OfferkeyEventL gets some time before calling + // Async Exit method + // these things are now handeled in prepare for exit + /*if ( iCheckQuery ) + { + TKeyEvent check = { EKeyEscape, EStdKeyNull, 0, 0 }; + TKeyResponse ret = iDlg->OfferKeyEventL(check, EEventKey ); + iDlg = NULL; + + iAsyncCallback->Cancel(); // cancel any outstanding callback just to be safe + iAsyncCallback->Set( TCallBack( AsyncExit, this ) ); + iAsyncCallback->CallBack(); + } + else + { + DoSafeExit( ESaveDraft );*/ + iAppUi.Exit(); + //} + // + } + break; + default: + { + // empty implementation + // these commands are passed next to FEP for processing + } + break; + } + } + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::DoSendL() +// Send message +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::DoSendL() + { + FUNC_LOG; + + // check that addresses exist + if ( iContainer->AreAddressFieldsEmpty() ) + { + User::Leave( KErrNotFound ); + } + + CommitL(); + + TRAPD(r, iMailBox->SendMessageL( *iNewMessage ) ); + if ( KErrNone != r ) + { + iMailSendFailed = ETrue; + User::Leave( r ); + } + + // prevent sending failure if original message is + // removed from server while replying/forwarding + TRAPD( flagError, SetReplyForwardFlagL() ); + + if ( KErrNone != flagError && KErrNotFound != flagError ) + { + iMailSendFailed = ETrue; + User::Leave( flagError ); + } + // + + iMailSent = ETrue; + + } + + +// ----------------------------------------------------------------------------- +// CNcsComposeView::DoSaveDraftL() +// Saves message to Drafts +// Displays dialog asking user choice if preferred +// Pressing cancel in the query dialog causes Leave with code KErrCancel +// ----------------------------------------------------------------------------- +// +TBool CNcsComposeView::DoSaveDraftL( TBool aAskUser ) + { + FUNC_LOG; + + __ASSERT_DEBUG( iNewMessage, Panic( ENcsBasicUi ) ); + + TBool result( ETrue ); + + if ( aAskUser ) + { + TInt selectedOption( -1 ); + CDesCArrayFlat* array = new (ELeave) CDesCArrayFlat( 2 ); + CleanupStack::PushL( array ); + + HBufC* saveItem = StringLoader::LoadLC( R_NCS_DRAFT_SAVE ); + array->AppendL( *saveItem ); + CleanupStack::PopAndDestroy( saveItem ); + + HBufC* deleteItem = StringLoader::LoadLC( R_NCS_DRAFT_DELETE ); + array->AppendL( *deleteItem ); + CleanupStack::PopAndDestroy( deleteItem ); + + iDlg = new (ELeave) CAknListQueryDialog( &selectedOption ); + iDlg->PrepareLC( R_DRAFT_QUERY_DIALOG ); + // CleanupStack::Pop(iDlg); + iDlg->SetItemTextArray( array ); + iDlg->SetOwnershipType( ELbmDoesNotOwnItemArray ); + + iCheckQuery = ETrue; + //we are forbiding to change MSK label, cause popup will be opend + iContainer->SwitchChangeMskOff(ETrue); + TInt ret = iDlg->RunLD(); + iDlg = NULL; + + iCheckQuery = EFalse; + iContainer->SwitchChangeMskOff(EFalse); + + if ( !ret ) + { + selectedOption = KErrCancel; + } + + switch ( selectedOption ) + { + case 0: + { + TRAPD( saveError, SaveToDraftsL( ETrue ) ); + + if ( saveError == KErrNone ) + { + // User wanted to save to Drafts and saving was successful + if(!iAppUi.AppUiExitOngoing()) // + TFsEmailUiUtility::ShowInfoNoteL( R_FREESTYLE_EMAIL_CONFIRM_NOTE_SAVED_TO_DRAFTS, ETrue ); + } + else + { + + // error occured in saving -> show an error message + if(!iAppUi.AppUiExitOngoing()) // + TFsEmailUiUtility::ShowErrorNoteL( R_FREESTYLE_EMAIL_ERROR_GENERAL_UNABLE_TO_COMPLETE, ETrue ); + + // let's return EFalse so after completing this query + // so the focus would stay in compose view (same behaviour as if Cancel was pressed ) + result = EFalse; + } + } + break; + case 1: + { + TRAPD( error, SaveToDraftsL( ETrue ) ); + if ( KErrNone != error ) + { + } + iFakeSyncGoingOn = ETrue; // for delete messages fake sync callscalls + error = NcsUtility::DeleteMessage( iMailClient, + iMailBox->GetId(), + iNewMessage->GetFolderId(), + iNewMessage->GetMessageId() ); + + if ( KErrNone == error && iMailBox->HasCapability( EFSMBoxCapaSupportsDeletedItemsFolder ) ) + { + error = NcsUtility::DeleteMessage( iMailClient, + iMailBox->GetId(), + iMailBox->GetStandardFolderId( EFSDeleted ), + iNewMessage->GetMessageId() ); + } + iFakeSyncGoingOn = EFalse; // + + if( !iAppUi.AppUiExitOngoing() ) + { + if ( KErrNone != error ) + { + // error occured in saving -> show an error message + TFsEmailUiUtility::ShowErrorNoteL( + R_FREESTYLE_EMAIL_ERROR_GENERAL_UNABLE_TO_COMPLETE, ETrue ); + } + else + { + // Simulate delete event so that drafts folder is + // updated correctly. + RArray messageIds; + CleanupClosePushL( messageIds ); + messageIds.AppendL( iNewMessage->GetMessageId() ); + TFSMailMsgId folderId = iNewMessage->GetFolderId(); + TFSMailMsgId mailboxId = iNewMessage->GetMailBoxId(); + iAppUi.EventL( TFSEventMailDeleted, + mailboxId, &messageIds, &folderId, NULL ); + CleanupStack::PopAndDestroy( &messageIds ); + } + } + } + break; + default: + { + result = EFalse; + } + break; + } + + //iCheckQuery = EFalse; // + CleanupStack::PopAndDestroy( array ); + } + else // no question from user + { + SaveToDraftsL( ETrue ); + } + + return result; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::NewMessage() +// Returns pointer to currently composed mail message +// ----------------------------------------------------------------------------- +// +CFSMailMessage* CNcsComposeView::NewMessage() + { + FUNC_LOG; + return iNewMessage; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::AsyncAddAttachmentL() +// Open file dialog and add selected file as an attachment +// ----------------------------------------------------------------------------- +// +TInt CNcsComposeView::AsyncAddAttachment( TAny* aSelfPtr ) + { + FUNC_LOG; + + CNcsComposeView* self = static_cast(aSelfPtr); + + // get pointer to attachment list view + CFreestyleEmailUiSendAttachmentsListControl* attachmentControl; + attachmentControl = self->AttachmentsListControl(); + + // show file dialog and get file name + TBool ok = EFalse; + TRAPD( error, ok = attachmentControl->AppendAttachmentToListL(self->iAttachmentAddType) ); + if ( ok && error == KErrNone ) + { + TRAPD( error, self->SetAttachmentLabelContentL() ); + return error; + } + return error; + } + +// ----------------------------------------------------------------------------- +// RunFollowUpFlagDlgL() +// Query user for followup flag +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::RunFollowUpFlagDlgL() + { + FUNC_LOG; + if ( iNewMessage && TFsEmailUiUtility::IsFollowUpSupported( *iMailBox ) ) + { + TFollowUpNewState newState = + TFsEmailUiUtility::SetMessageFollowupFlagL( *iNewMessage, EFalse ); + + switch ( newState ) + { + case EFollowUp: + { + iStatusPaneIndicators->SetFollowUpFlag( CCustomStatuspaneIndicators::EFollowUp ); + } + break; + case EFollowUpComplete: + { + iStatusPaneIndicators->SetFollowUpFlag( CCustomStatuspaneIndicators::EFollowUpComplete ); + } + break; + case EFollowUpClear: + { + iStatusPaneIndicators->SetFollowUpFlag( CCustomStatuspaneIndicators::EFollowUpNone ); + } + break; + default: + { + // do nothing. + } + break; + } + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::SetAttachmentLabelContentL() +// Open file dialog and add selected file as an attachment +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::SetAttachmentLabelContentL() + { + FUNC_LOG; + if ( iFirstStartCompleted ) // Safety + { + CFreestyleEmailUiSendAttachmentsListControl* attachmentControl; + attachmentControl = AttachmentsListControl(); + + // read number of attachments + TInt count = attachmentControl->Model()->Count(); + + if ( count > 1 ) + { + TInt totalSizeInBytes = attachmentControl->Model()->TotalAttachmentSize(); + HBufC* stringBuf = NULL; + + HBufC* sizeDesc = TFsEmailUiUtility::CreateSizeDescLC( totalSizeInBytes ); + stringBuf = StringLoader::LoadL( R_NCS_ATTACHMENTS_FIELD_TEXT, + *sizeDesc, count ); + CleanupStack::PopAndDestroy( sizeDesc ); + + CleanupStack::PushL( stringBuf ); + iContainer->SetAttachmentLabelTextL( *stringBuf ); + CleanupStack::PopAndDestroy( stringBuf ); + iContainer->SetFocusToAttachmentField(); + } + else if ( count == 1 ) + { + CFSEmailUiSendAttachmentsListModelItem* item = + static_cast( + attachmentControl->Model()->Item( 0 ) ); + + HBufC* sizeBuf = TFsEmailUiUtility::CreateSizeDescLC( item->FileSize() ); + iContainer->SetAttachmentLabelTextL( item->FileName(), *sizeBuf ); + CleanupStack::PopAndDestroy( sizeBuf ); + + iContainer->SetFocusToAttachmentField(); + } + else + { + iContainer->SetAttachmentLabelTextL( KNullDesC ); + iContainer->HideAttachmentLabel(); + } + } + + } + + +// ----------------------------------------------------------------------------- +// CNcsComposeView::AttachmentsListControl() +// +// ----------------------------------------------------------------------------- +// +CFreestyleEmailUiSendAttachmentsListControl* CNcsComposeView::AttachmentsListControl() + { + FUNC_LOG; + CFreestyleEmailUiSendAttachmentsListControl* attachmentControl(0); + if ( iFirstStartCompleted ) // Safety + { + CFSEmailUiSendAttachmentsListVisualiser* attachmentView = + static_cast( + iAvkonViewAppUi->View( SendAttachmentMngrViewId ) ); + attachmentControl = static_cast( + attachmentView->ViewerControl() ); + } + return attachmentControl; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::ProcessCommandL() +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::ProcessCommandL( TInt aCommand ) + { + FUNC_LOG; + + // Block all the commands while we are exiting + if ( !iExecutingDoExitL ) + { + CFsEmailUiViewBase::ProcessCommandL( aCommand ); + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::HandleActivationCommandL() +// +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::HandleActivationCommandL( TUid aCustomMessageId ) + { + FUNC_LOG; + // Called from doactivate in which case first start is completed + iMailFetchingErrCode = KErrNone; + + if ( aCustomMessageId == TUid::Uid( KEditorCmdCreateNew ) ) + { + iOrigMessage = NULL; + iFakeSyncGoingOn = ETrue;// this is actually a waited async method + iNewMessage = iMailBox->CreateMessageToSend(); + iFakeSyncGoingOn = EFalse; + if ( !iNewMessage ) + { + User::Leave( KErrGeneral ); + } + iFakeSyncGoingOn = ETrue; + TFsEmailUiUtility::MoveMessageToDraftsL( *iMailBox, *iNewMessage ); + iFakeSyncGoingOn = EFalse;// + + if ( iNewMessage->GetContentType() != KFSMailContentTypeMultipartMixed ) + { + iNewMessage->SetContentType( KFSMailContentTypeMultipartMixed ); + iNewMessage->SaveMessageL(); + } + + TFsEmailUiUtility::CreatePlainTextPartL( *iNewMessage, iNewMessageTextPart ); + IncludeMessageTextL( ETrue ); + AttachmentsListControl()->Model()->Clear(); + iContainer->SelectAllToFieldTextL(); + } + else if ( aCustomMessageId == TUid::Uid( KEditorCmdReply ) || + aCustomMessageId == TUid::Uid( KEditorCmdReplyAll ) ) + { + + iOrigMessage = iMailClient.GetMessageByUidL( iLaunchParams.iMailboxId, iLaunchParams.iFolderId, iLaunchParams.iMsgId, EFSMsgDataStructure ); + if ( !iOrigMessage ) + { + User::Leave( KErrNotFound ); + } + + SafeDelete( iFetchLogic ); + iFetchLogic = CFsComposerFetchLogic::NewL( iMailClient, iLaunchParams.iMailboxId, + iOrigMessage->GetFolderId(), iLaunchParams.iMsgId, *this, iAppUi ); + ShowFetchingWaitNoteL(); + iFetchLogic->RunReplyLogicL(); + + // now fetch logic object runs its tasks and gives callback + // to CNcsComposeView::FetchLogicComplete when it is finished + } + else if ( aCustomMessageId == TUid::Uid( KEditorCmdForward ) ) + { + + iOrigMessage = iMailClient.GetMessageByUidL( iLaunchParams.iMailboxId, iLaunchParams.iFolderId, iLaunchParams.iMsgId, EFSMsgDataStructure ); + if ( !iOrigMessage ) + { + User::Leave( KErrNotFound ); + } + + SafeDelete( iFetchLogic ); + iFetchLogic = CFsComposerFetchLogic::NewL( iMailClient, iLaunchParams.iMailboxId, + iOrigMessage->GetFolderId(), iLaunchParams.iMsgId, *this, iAppUi ); + ShowFetchingWaitNoteL(); + iFetchLogic->RunForwardLogicL(); + + // now fetch logic object runs its tasks and gives callback + // to CNcsComposeView::FetchLogicComplete when it is finished + } + else if ( aCustomMessageId == TUid::Uid( KEditorCmdOpen ) || + aCustomMessageId == TUid::Uid( KEditorCmdReturnToPrevious ) ) // for now, we handle returning from attachments list just like any message opening + { + + iNewMessage = iMailClient.GetMessageByUidL( iLaunchParams.iMailboxId, iLaunchParams.iFolderId, iLaunchParams.iMsgId, EFSMsgDataStructure ); + if ( !iNewMessage ) + { + User::Leave( KErrNotFound ); + } + + // Show "Opening" wait note if the message body is large + TInt waitNoteId = KErrNotFound; + if ( TFsEmailUiUtility::IsMessageBodyLargeL(iNewMessage) ) + { + waitNoteId = TFsEmailUiUtility::ShowGlobalWaitNoteLC( R_FSE_WAIT_OPENING_TEXT ); + } + + iOrigMessage = NULL; + iNewMessage->SetContentType( KFSMailContentTypeMultipartMixed ); + iNewMessage->SaveMessageL(); + TFsEmailUiUtility::CreatePlainTextPartL( *iNewMessage, iNewMessageTextPart ); + InitFieldsL(); + IncludeMessageTextL(); + AttachmentsListControl()->Model()->Clear(); + GetAttachmentsFromMailL(); + SetAttachmentLabelContentL(); + iAttachmentListSaveDraft = ETrue; + + // Close the "Opening" wait note if it was shown + if ( waitNoteId != KErrNotFound ) + { + CleanupStack::PopAndDestroy( (TAny*)waitNoteId ); + } + } + else if ( aCustomMessageId == TUid::Uid( KEditorCmdInternalMailto ) ) + { + FUNC_LOG; + + iOrigMessage = NULL; + // this is actually a waited async method + iFakeSyncGoingOn = ETrue; + iNewMessage = iMailBox->CreateMessageToSend(); + iFakeSyncGoingOn = EFalse; + // + if ( !iNewMessage ) + { + User::Leave( KErrGeneral ); + } + iNewMessage->SetContentType( KFSMailContentTypeMultipartMixed ); + iNewMessage->SaveMessageL(); + + TFsEmailUiUtility::CreatePlainTextPartL( *iNewMessage, iNewMessageTextPart ); + + IncludeMessageTextL( ETrue ); + + CFSMailAddress* toAddress = static_cast( iLaunchParams.iExtra ); // not owned + RPointerArray toRecipients; + CleanupResetAndDestroyClosePushL( toRecipients ); + CNcsEmailAddressObject* ncsToAddress = NcsUtility::CreateNcsAddressL( *toAddress ); + CleanupStack::PushL( ncsToAddress ); + toRecipients.AppendL( ncsToAddress ); + CleanupStack::Pop( ncsToAddress ); // owned by toRecipients now + iContainer->SetToFieldAddressesL( toRecipients ); + CleanupStack::PopAndDestroy( &toRecipients ); + + iContainer->SetFocusToMessageFieldL(); + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::DoQuickTextL() +// +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::DoQuickTextL() + { + FUNC_LOG; + + __ASSERT_DEBUG( iContainer, Panic( ENcsBasicUi ) ); + + HBufC* title = iEikonEnv->AllocReadResourceLC( R_NCS_QUICK_TEXT_TITLE_TEXT ); + HBufC* buf(0); + TRAPD( err, buf = CNotepadApi::FetchTemplateL( title ) ); + if (err == KLeaveExit) + { //If end key was pressed the dialog leaves with the above error code. + //In that case we must leave as well or the application will become stuck + //as the exit will be incomplete. + User::Leave(err); + } + + if ( buf && err == KErrNone ) // Safety check, 0 if user cancel + { + CleanupStack::PushL( buf ); + iContainer->AddQuickTextL( *buf ); + CleanupStack::PopAndDestroy( buf ); + } + CleanupStack::PopAndDestroy( title ); + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::HandleDynamicVariantSwitchL() +// +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::HandleDynamicVariantSwitchL( + CFsEmailUiViewBase::TDynamicSwitchType aType ) + { + FUNC_LOG; + + if ( iFirstStartCompleted && iContainer ) + { + if ( aType == CFsEmailUiViewBase::EScreenLayoutChanged ) + { + iContainer->HandleLayoutChangeL(); + } + else if ( aType == CFsEmailUiViewBase::ESkinChanged ) + { + iContainer->HandleSkinChangeL(); + } + else + { + } + } + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::InitReplyFieldsL() +// Initialises the reply fields from the reply message created by the plug-in. +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::InitReplyFieldsL( TBool /*aReplyAll*/ ) + { + FUNC_LOG; + + __ASSERT_DEBUG( iContainer, Panic( ENcsBasicUi ) ); + + // Get TO recipients + RPointerArray& toRecipients = iNewMessage->GetToRecipients(); + RPointerArray recipients; + CleanupResetAndDestroyClosePushL( recipients ); + NcsUtility::ConvertAddressArrayL( toRecipients, recipients ); + iContainer->SetToFieldAddressesL( recipients ); + CleanupStack::PopAndDestroy( &recipients ); + + // Get CC recipients + RPointerArray& ccRecipients = iNewMessage->GetCCRecipients(); + NcsUtility::ConvertAddressArrayL( ccRecipients, recipients ); + iContainer->SetCcFieldAddressesL( recipients ); + recipients.ResetAndDestroy(); + + // Get BCC recipients + RPointerArray& bccRecipients = iNewMessage->GetBCCRecipients(); + NcsUtility::ConvertAddressArrayL( bccRecipients, recipients ); + iContainer->SetBccFieldAddressesL( recipients ); + recipients.ResetAndDestroy(); + + // Get subject line from original message + HBufC* prefix = StringLoader::LoadLC( R_NCS_ENGINE_EMAIL_REPLY_PREFIX ); + HBufC* formattedSubject = NcsUtility::FormatSubjectLineL( + iOrigMessage->GetSubject(), *prefix ); + CleanupStack::PushL( formattedSubject ); + iContainer->SetSubjectL( *formattedSubject ); + CleanupStack::PopAndDestroy( formattedSubject ); + CleanupStack::PopAndDestroy( prefix ); + + // clear attachments + AttachmentsListControl()->Model()->Clear(); + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::RemoveOwnAddress() +// +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::RemoveOwnAddress( RPointerArray& aAddressList ) + { + FUNC_LOG; + TInt index = 0; + TDesC& ownAddress( iMailBox->OwnMailAddress().GetEmailAddress() ); + while ( index < aAddressList.Count() ) + { + if ( !aAddressList[index]->EmailAddress().CompareC(ownAddress) ) + { + // The entry will be removed from the arry. + aAddressList.Remove(index); + break; + } + index++; + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::IncludeMessageTextL() +// +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::IncludeMessageTextL( TBool aEnsureSpaceInBegin /*= EFalse*/ ) + { + FUNC_LOG; + + __ASSERT_DEBUG( iContainer, Panic( ENcsBasicUi ) ); + + HBufC* body = NULL; + HBufC* rawBody = GetMessageBodyL(); + CleanupStack::PushL( rawBody ); + + // Ensure there's free space in the beginning of the message if required + if ( aEnsureSpaceInBegin && rawBody->Length() ) + { + TText firstChar = (*rawBody)[0]; + _LIT( KNewLines, "\r\n\x2028\x2029" ); + if ( KNewLines().Locate( firstChar ) == KErrNotFound ) + { + // First character is not a new line character. Insert one. + body = HBufC::NewL( rawBody->Length() + KIMSLineFeed().Length() ); + TPtr ptr = body->Des(); + ptr.Append( KIMSLineFeed ); + ptr.Append( *rawBody ); + CleanupStack::PopAndDestroy( rawBody ); + rawBody = NULL; + CleanupStack::PushL( body ); + } + } + // If no modifications were needed, then just set body pointer to point the rawBody + if ( !body ) + { + body = rawBody; + rawBody = NULL; + } + // Now we have possibly decorated message text in body pointer and in cleanup stack + + // Divide the contents into normal body field and the read-only quote field + TInt readOnlyLength = iNewMessageTextPart->ReadOnlyPartSize() / 2; // convert bytes to words + TInt modifiableLength = body->Length() - readOnlyLength; + + // Remove one newline from the end of the modifiable body if there's read-only quote present. + // This is because the field boundary appears as newline on the screen. This newline + // is added back when saving the message. + TInt lfLength = KIMSLineFeed().Length(); + if ( readOnlyLength && modifiableLength >= lfLength && + body->Mid( modifiableLength-lfLength, lfLength ) == KIMSLineFeed ) + { + modifiableLength -= lfLength; + } + + iContainer->SetBodyContentL( body->Left( modifiableLength ), + body->Right( readOnlyLength ) ); + + CleanupStack::PopAndDestroy( body ); + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::InitForwardFieldsL() +// +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::InitForwardFieldsL() + { + FUNC_LOG; + + __ASSERT_DEBUG( iContainer, Panic( ENcsBasicUi ) ); + + // set subject + HBufC* prefix = StringLoader::LoadLC( R_NCS_ENGINE_EMAIL_FORWARD_PREFIX ); + HBufC* formattedSubject = NcsUtility::FormatSubjectLineL( iOrigMessage->GetSubject(), *prefix ); + CleanupStack::PushL( formattedSubject ); + iContainer->SetSubjectL( *formattedSubject ); + CleanupStack::PopAndDestroy( formattedSubject ); + CleanupStack::PopAndDestroy( prefix ); + + // attachments + AttachmentsListControl()->Model()->Clear(); + // + TInt error = KErrNone; + TRAP( error, GetAttachmentsFromMailL() ); + // + SetAttachmentLabelContentL(); + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::SetPriority() +// +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::SetPriority() + { + FUNC_LOG; + + __ASSERT_DEBUG( iContainer, Panic( ENcsBasicUi ) ); + + if ( iNewMessage && iNewMessage->IsFlagSet( EFSMsgFlag_Important ) ) + { + iStatusPaneIndicators->SetPriorityFlag( EMsgPriorityHigh ); + } + else if ( iNewMessage && iNewMessage->IsFlagSet( EFSMsgFlag_Low ) ) + { + iStatusPaneIndicators->SetPriorityFlag( EMsgPriorityLow ); + } + } + +// ----------------------------------------------------------------------------- +// Sets follow-up flags to status pane indicators +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::SetFollowUp() + { + if ( iNewMessage && iStatusPaneIndicators ) + { + if ( iNewMessage->IsFlagSet( EFSMsgFlag_FollowUp ) ) + { + iStatusPaneIndicators->SetFollowUpFlag( + CCustomStatuspaneIndicators::EFollowUp ); + } + else if ( iNewMessage->IsFlagSet( EFSMsgFlag_FollowUpComplete ) ) + { + iStatusPaneIndicators->SetFollowUpFlag( + CCustomStatuspaneIndicators::EFollowUpComplete ); + } + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::InitFieldsL() +// +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::InitFieldsL() + { + FUNC_LOG; + + __ASSERT_DEBUG( iContainer, Panic( ENcsBasicUi ) ); + + // to + RPointerArray& toRecipients = iNewMessage->GetToRecipients(); + RPointerArray ncsToRecipients; + CleanupResetAndDestroyClosePushL( ncsToRecipients ); + NcsUtility::ConvertAddressArrayL( toRecipients, ncsToRecipients ); + iContainer->SetToFieldAddressesL( ncsToRecipients ); + CleanupStack::PopAndDestroy( &ncsToRecipients ); + + // cc + RPointerArray& ccRecipients = iNewMessage->GetCCRecipients(); + RPointerArray ncsCcRecipients; + CleanupResetAndDestroyClosePushL( ncsCcRecipients ); + NcsUtility::ConvertAddressArrayL( ccRecipients, ncsCcRecipients ); + iContainer->SetCcFieldAddressesL( ncsCcRecipients ); + CleanupStack::PopAndDestroy( &ncsCcRecipients ); + + // bcc + RPointerArray& bccRecipients = iNewMessage->GetBCCRecipients(); + RPointerArray ncsBccRecipients; + CleanupResetAndDestroyClosePushL( ncsBccRecipients ); + NcsUtility::ConvertAddressArrayL( bccRecipients, ncsBccRecipients ); + iContainer->SetBccFieldAddressesL( ncsBccRecipients ); + CleanupStack::PopAndDestroy( &ncsBccRecipients ); + + // set subject line + iContainer->SetSubjectL( iNewMessage->GetSubject() ); + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::GetMessageBodyL() +// +// ----------------------------------------------------------------------------- +// +HBufC* CNcsComposeView::GetMessageBodyL() + { + FUNC_LOG; + + __ASSERT_DEBUG( iNewMessageTextPart, Panic( ENcsBasicUi ) ); + + TInt messageSize = iNewMessageTextPart->FetchedContentSize(); + + HBufC* data = NULL; + + if ( messageSize > 0 ) + { + // fetch message body if there is something to fetch + data = HBufC::NewLC( messageSize ); + TPtr dataPtr = data->Des(); + iNewMessageTextPart->GetContentToBufferL( dataPtr, 0 ); + CleanupStack::Pop( data ); + } + else + { + data = KNullDesC().AllocL(); + } + + return data; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::CommitL() +// +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::CommitL( TBool aParseAddresses, TFieldToCommit aFieldToCommit ) + { + FUNC_LOG; + __ASSERT_DEBUG( iNewMessage, Panic( ENcsBasicUi ) ); + __ASSERT_DEBUG( iNewMessageTextPart, Panic( ENcsBasicUi ) ); + + TBool commitToField = EFalse; + TBool commitCcField = EFalse; + TBool commitBccField = EFalse; + TBool commitSubjectField = EFalse; + TBool commitBodyField = EFalse; + + switch ( aFieldToCommit ) + { + case EAllFields: + commitToField = ETrue; + commitCcField = ETrue; + commitBccField = ETrue; + commitSubjectField = ETrue; + commitBodyField = ETrue; + break; + case EToField: + commitToField = ETrue; + break; + case ECcField: + commitCcField = ETrue; + break; + case EBccField: + commitBccField = ETrue; + break; + case EBodyField: + commitBodyField = ETrue; + break; + case ESubjectField: + commitSubjectField = ETrue; + break; + default: + break; + } + + if ( commitToField ) + { + // get addresses from UI to MSG object + RPointerArray toAddresses; + CleanupResetAndDestroyClosePushL( toAddresses ); + NcsUtility::ConvertAddressArrayL( iContainer->GetToFieldAddressesL( aParseAddresses ), toAddresses ); + iNewMessage->GetToRecipients().ResetAndDestroy(); + for ( TInt i = 0 ; i < toAddresses.Count() ; i++ ) + { + iNewMessage->AppendToRecipient( toAddresses[i] ); + // Ownership of the message pointer was transferred from our array to iNewMessage + toAddresses[i] = NULL; + } + CleanupStack::PopAndDestroy( &toAddresses ); + } + + if ( commitCcField ) + { + RPointerArray ccAddresses; + CleanupResetAndDestroyClosePushL( ccAddresses ); + NcsUtility::ConvertAddressArrayL( iContainer->GetCcFieldAddressesL( aParseAddresses ), ccAddresses ); + iNewMessage->GetCCRecipients().ResetAndDestroy(); + for ( TInt i = 0 ; i < ccAddresses.Count() ; i++ ) + { + iNewMessage->AppendCCRecipient( ccAddresses[i] ); + // Ownership of the message pointer was transferred from our array to iNewMessage + ccAddresses[i] = NULL; + } + CleanupStack::PopAndDestroy( &ccAddresses ); + } + + if ( commitBccField ) + { + RPointerArray bccAddresses; + CleanupResetAndDestroyClosePushL( bccAddresses ); + NcsUtility::ConvertAddressArrayL( iContainer->GetBccFieldAddressesL( aParseAddresses ), bccAddresses ); + iNewMessage->GetBCCRecipients().ResetAndDestroy(); + for ( TInt i = 0; i < bccAddresses.Count() ; i++ ) + { + iNewMessage->AppendBCCRecipient( bccAddresses[i] ); + // Ownership of the message pointer was transferred from our array to iNewMessage + bccAddresses[i] = NULL; + } + CleanupStack::PopAndDestroy( &bccAddresses ); + } + + if ( commitSubjectField ) + { + // get subject from UI to MSG object + HBufC* subject = iContainer->GetSubjectLC(); + TPtr ptr = subject->Des(); + // replace new line characters with spaces as Subject is normally one line only + AknTextUtils::ReplaceCharacters( ptr, KLineSeparators, KReplacementChar ); + iNewMessage->SetSubject( *subject ); + CleanupStack::PopAndDestroy( subject ); + } + + if ( commitBodyField ) + { + HBufC* body = iContainer->GetBodyContentLC(); + TPtr bodyPtr = body->Des(); // this TPtr is needed only because of incorrect argument type in FW API, can be removed when API fixed + iNewMessageTextPart->SetContent( bodyPtr ); + CleanupStack::PopAndDestroy( body ); + + TInt error = KErrNone; + if ( iNewMessageTextPart ) + { + TRAP( error, iNewMessageTextPart->SaveL() ); + } + } + + // Save message if at least one field committed + if ( iNewMessage || commitToField || commitCcField || commitBccField + || commitSubjectField || commitBodyField ) + { + TInt error = KErrNone; + TRAP( error, iNewMessage->SaveMessageL() ); + RefreshToolbar(); + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::DoSafeExit +// ----------------------------------------------------------------------------- +void CNcsComposeView::DoSafeExit( TExitMode aMode ) + { + FUNC_LOG; + + if ( !iExecutingDoExitL ) + { + iExecutingDoExitL = ETrue; + TRAP_IGNORE( DoExitL( aMode ) ); + iExecutingDoExitL = EFalse; + } + } + + +// ----------------------------------------------------------------------------- +// CNcsComposeView::DoExitL +// ----------------------------------------------------------------------------- +void CNcsComposeView::DoExitL( TExitMode aMode ) + { + FUNC_LOG; + + // + TBool emptyMessage = ETrue; + + if ( iAutoSaver && iContainer ) + { + iAutoSaver->Enable( EFalse ); + + // check that there's some user input in some header field or in message body + TInt attaCount = AttachmentsListControl()->Model()->Count(); + emptyMessage = iContainer->AreAddressFieldsEmpty() && + iContainer->IsSubjectFieldEmpty() && + iContainer->GetMessageFieldLength() < 1 && + attaCount <= 0; + } + // + + // Consider saving the draft if the message is not completely empty + if ( !emptyMessage ) + { + if ( aMode == ESaveDraftQuery && !iMailSent && !iMailSendFailed ) + { + TBool actionSucceeded = EFalse; + + // DoSaveDraftL returns EFalse if the user query was cancelled or saving to Drafts failed + TRAPD( saveDraftError, actionSucceeded = DoSaveDraftL( ETrue ) ); + if ( saveDraftError == KErrNone ) + { + if ( !actionSucceeded ) + { + // return to normal action (cancel was pressed in the query) + iAutoSaver->Enable( ETrue ); + return; + } + } + else + { + } + } + else if ( aMode == ESaveDraft ) + { + DoSaveDraftL( EFalse ); + } + } + else if ( iNewMessage ) // message is empty; delete the draft if it has been already saved earlier + { + TInt err = NcsUtility::DeleteMessage( iMailClient, iMailBox->GetId(), + iNewMessage->GetFolderId(), iNewMessage->GetMessageId() ); + if ( !err && iMailBox->HasCapability( EFSMBoxCapaSupportsDeletedItemsFolder ) ) + { + err = NcsUtility::DeleteMessage( iMailClient, iMailBox->GetId(), + iMailBox->GetStandardFolderId( EFSDeleted ), + iNewMessage->GetMessageId() ); + } + + if ( !err && !iAppUi.AppUiExitOngoing() ) + { + // Simulate delete event so that drafts folder is + // updated correctly. + RArray messageIds; + CleanupClosePushL( messageIds ); + messageIds.AppendL( iNewMessage->GetMessageId() ); + TFSMailMsgId folderId = iNewMessage->GetFolderId(); + TFSMailMsgId mailboxId = iNewMessage->GetMailBoxId(); + iAppUi.EventL( TFSEventMailDeleted, + mailboxId, &messageIds, &folderId, NULL ); + CleanupStack::PopAndDestroy( &messageIds ); + } + } + + // + // Clear attachment control now that message has been sent + // othewise this will kind of leak memory by leaving attachments + // in the list, even if they have been sent. + CFreestyleEmailUiSendAttachmentsListControl* attachmentControl; + attachmentControl = AttachmentsListControl(); + if ( attachmentControl && attachmentControl->Model() ) + { + attachmentControl->Model()->Clear(); + } + // + + ExitComposer(); + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::DoOpenAttachmentList +// Saves current editor message to drafts and opens attachment list view +// ----------------------------------------------------------------------------- +void CNcsComposeView::DoOpenAttachmentListL() + { + FUNC_LOG; + + CFreestyleEmailUiSendAttachmentsListControl* attachmentControl + = AttachmentsListControl(); + + if ( attachmentControl->Model()->Count() == 1 ) + { + CFSEmailUiSendAttachmentsListModelItem* item = + static_cast( + attachmentControl->Model()->Item( 0 ) ); + if ( !item->IsRemote() ) // we cannot open remote attachments + { + CFSMailMessagePart* msgPart = iNewMessage->ChildPartL( item->MailMsgPartId() ); + CleanupStack::PushL( msgPart ); + TFsEmailUiUtility::OpenAttachmentL( *msgPart ); + CleanupStack::PopAndDestroy( msgPart ); + } + } + // open attachment list + else + { + // set current email parameters to package buffer + TEditorLaunchParams editorParams; + editorParams.iMailboxId = iNewMessage->GetMailBoxId(); + editorParams.iMsgId = iNewMessage->GetMessageId(); + editorParams.iFolderId = iNewMessage->GetFolderId(); + editorParams.iActivatedExternally = EFalse; + TPckgBuf buf( editorParams ); + + // save email to drafts + iAttachmentListSaveDraft = ETrue; + TRAPD( saveDraftError, DoSaveDraftL( EFalse ) ); + if ( saveDraftError != KErrNone ) + { + // error occured in saving -> show an error message + if ( !iAppUi.AppUiExitOngoing() ) // + TFsEmailUiUtility::ShowErrorNoteL( R_FREESTYLE_EMAIL_ERROR_GENERAL_UNABLE_TO_COMPLETE, ETrue ); + return; + } + + // open attachment list view + iAppUi.EnterFsEmailViewL( + SendAttachmentMngrViewId, + TUid::Uid( KEditorCmdOpenAttachmentsList ), + buf ); + } + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::LaunchAttachmentActionMenuL +// Show action menu for the attachments line +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::LaunchAttachmentActionMenuL() + { + FUNC_LOG; + + // Remove old items from action menu + CFSEmailUiActionMenu::RemoveAllL(); + + // Construct item list + RFsEActionMenuIdList itemList; + CleanupClosePushL( itemList ); + + CFreestyleEmailUiSendAttachmentsListControl* attachmentControl = + AttachmentsListControl(); + TInt count = attachmentControl->Model()->Count(); + TBool remoteAtt = AttachmentsListControl()->Model()->HasRemoteAttachments(); + TBool readOnlyAtt = AttachmentsListControl()->Model()->HasReadOnlyAttachments(); + + // Open/View all + if ( count == 1 && !remoteAtt ) + { + itemList.AppendL( FsEActionAttachmentOpen ); + } + else if ( count > 1 ) + { + itemList.AppendL( FsEActionAttachmentViewAll ); + } + + // Add + itemList.AppendL( FsEActionAttachmentAdd ); + + // Remove/Remove all + if ( !readOnlyAtt ) + { + if ( count == 1 ) + { + itemList.AppendL( FsEActionAttachmentRemove ); + } + else if ( count > 1 ) + { + itemList.AppendL( FsEActionAttachmentRemoveAll ); + } + } + + // Execute action list + TActionMenuCustomItemId itemId = CFSEmailUiActionMenu::ExecuteL( itemList ); + CleanupStack::PopAndDestroy( &itemList ); + + // Handle action menu selection + switch ( itemId ) + { + case FsEActionAttachmentOpen: + HandleCommandL( EFsEmailUiCmdOpenAttachment ); + break; + case FsEActionAttachmentViewAll: + HandleCommandL( EFsEmailUiCmdOpenAttachmentList ); + break; + case FsEActionAttachmentRemove: + HandleCommandL( ENcsCmdRemoveAttachment ); + break; + case FsEActionAttachmentRemoveAll: + HandleCommandL( ENcsCmdRemoveAllAttachments ); + break; + case FsEActionAttachmentAdd: + HandleCommandL( ENcsCmdAddAttachment ); + break; + default: + break; + } + + } + +// +// ----------------------------------------------------------------------------- +// CNcsComposeView::DismissAttachmentActionMenuL +// +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::DismissAttachmentActionMenuL() + { + FUNC_LOG; + CFSEmailUiActionMenu::Dismiss( ETrue ); + } +// + +// ----------------------------------------------------------------------------- +// CNcsComposeView::GetAttachmentsFromMail +// ----------------------------------------------------------------------------- +void CNcsComposeView::GetAttachmentsFromMailL() + { + FUNC_LOG; + + TInt error( KErrNone ); + + RPointerArray attachments; + CleanupResetAndDestroyClosePushL( attachments ); + TRAP( error, iNewMessage->AttachmentListL( attachments ) ); + User::LeaveIfError( error ); + + for ( TInt i=0; iAttachmentNameL(), + attachments[i]->GetContentType() ); + + TBool isReadOnly = ( attachments[i]->ReadOnlyPartSize() > 0 ); + TBool isRemote = EFalse; + + if ( attachments[i]->FetchedContentSize() < attachments[i]->ContentSize() ) + { + if ( iMailBox->HasCapability( EFSMBoxCapaSmartForward ) ) + { + isRemote = ETrue; + } + else + { + __ASSERT_DEBUG( EFalse, Panic(EFSEmailUiUnexpectedValue) ); + User::Leave( KErrNotFound ); + continue; + } + } + + AttachmentsListControl()->AppendFileToModelL( + attachments[i]->GetPartId(), + attachments[i]->AttachmentNameL(), + attachments[i]->ContentSize(), + fileType, + isReadOnly, + isRemote ); + } + + CleanupStack::PopAndDestroy( &attachments ); + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::FileExistsInModel +// ----------------------------------------------------------------------------- +TBool CNcsComposeView::FileExistsInModel( TFSMailMsgId aAttachmentId ) + { + FUNC_LOG; + + TInt count( AttachmentsListControl()->Model()->Count() ); + + for ( TInt i=0; i < count; ++i ) + { + CFSEmailUiSendAttachmentsListModelItem* item = + static_cast( + AttachmentsListControl()->Model()->Item(i) ); + if ( aAttachmentId.Id() == item->MailMsgPartId().Id() ) + { + return ETrue; + } + } + + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::GenerateReplyHeaderLC +// ----------------------------------------------------------------------------- +HBufC* CNcsComposeView::GenerateReplyHeaderLC() + { + FUNC_LOG; + + __ASSERT_DEBUG( iOrigMessage, Panic( ENcsBasicUi ) ); + + // separator line + HBufC* separator = StringLoader::LoadLC( R_NCS_ENGINE_EMAIL_MESSAGE_LINE_SEPARATOR ); //1 + + // from line + RPointerArray senderArray; + CleanupResetAndDestroyClosePushL( senderArray ); + CFSMailAddress* sender = iOrigMessage->GetSender(); + if ( sender ) + { + CNcsEmailAddressObject* ncsSender = NcsUtility::CreateNcsAddressL( *sender ); + CleanupStack::PushL( ncsSender ); + senderArray.AppendL( ncsSender ); + CleanupStack::Pop( ncsSender ); // now owned by senderArray + } + HBufC* fromLine = NcsUtility::GenerateFromLineToMessageBodyL( senderArray ); + CleanupStack::PopAndDestroy( &senderArray ); + CleanupStack::PushL( fromLine ); //2 + + // sent line + HBufC* sentLine = NcsUtility::GenerateSentLineToMessageBodyL( *iOrigMessage ); + CleanupStack::PushL( sentLine ); //3 + + // to line + RPointerArray ncsToRecipients; + CleanupResetAndDestroyClosePushL( ncsToRecipients ); + RPointerArray& toRecipients = iOrigMessage->GetToRecipients(); + NcsUtility::ConvertAddressArrayL( toRecipients, ncsToRecipients ); + HBufC* toLine = NcsUtility::GenerateAddressLineToMessageBodyL( ncsToRecipients, NcsUtility::ERecipientTypeTo ); + CleanupStack::PopAndDestroy( &ncsToRecipients ); + CleanupStack::PushL( toLine ); //4 + + // cc line + RPointerArray& ccRecipients = iOrigMessage->GetCCRecipients(); + TBool hasCcLine = ( ccRecipients.Count() > 0 ); + HBufC* ccLine = NULL; + if ( hasCcLine ) + { + RPointerArray ncsCcRecipients; + CleanupResetAndDestroyClosePushL( ncsCcRecipients ); + NcsUtility::ConvertAddressArrayL( ccRecipients, ncsCcRecipients ); + ccLine = NcsUtility::GenerateAddressLineToMessageBodyL( ncsCcRecipients, NcsUtility::ERecipientTypeCc ); + CleanupStack::PopAndDestroy( &ncsCcRecipients ); + CleanupStack::PushL( ccLine ); //5 + } + + // subject line + HBufC* subjectLine = NcsUtility::GenerateSubjectLineToMessageBodyL( iOrigMessage->GetSubject() ); + CleanupStack::PushL( subjectLine ); //6 + + // Body + HBufC* body = NULL; + TBool hasBody = EFalse; + CFSMailMessagePart* textBodyPart = iOrigMessage->PlainTextBodyPartL(); + if ( textBodyPart ) + { + // Plain text body part present, no need + // to generate it from HTML body part + delete textBodyPart; + } + else + { + // Generate body part for reply + CFSMailMessagePart* htmlBodyPart = iOrigMessage->HtmlBodyPartL(); + if ( htmlBodyPart ) + { + CleanupStack::PushL( htmlBodyPart ); + + HBufC* htmlData = HBufC::NewLC( htmlBodyPart->FetchedContentSize() ); + TPtr pointer = htmlData->Des(); + htmlBodyPart->GetContentToBufferL( pointer, 0 ); + + body = TFsEmailUiUtility::ConvertHtmlToTxtL( *htmlData ); + + CleanupStack::PopAndDestroy( htmlData ); + CleanupStack::PopAndDestroy( htmlBodyPart ); + + CleanupStack::PushL( body ); //7 + + hasBody = ETrue; + } + } + // calculate total length + TInt length = 0; + length += separator->Length(); + length += KIMSLineFeed().Length(); + length += fromLine->Length(); + length += KIMSLineFeed().Length(); + length += sentLine->Length(); + length += KIMSLineFeed().Length(); + length += toLine->Length(); + if ( hasCcLine ) + { + length += KIMSLineFeed().Length(); + length += ccLine->Length(); + } + length += KIMSLineFeed().Length(); + length += subjectLine->Length(); + length += KIMSLineFeed().Length(); + if ( hasBody ) + { + length += body->Length(); + } + length += KIMSLineFeed().Length(); + length += KIMSLineFeed().Length(); + + // create buffer and write contents + HBufC* header = HBufC::NewL( length ); + TPtr ptr = header->Des(); + ptr.Append( *separator ); + ptr.Append( KIMSLineFeed ); + ptr.Append( *fromLine ); + ptr.Append( KIMSLineFeed ); + ptr.Append( *sentLine ); + ptr.Append( KIMSLineFeed ); + ptr.Append( *toLine ); + if ( hasCcLine ) + { + ptr.Append( KIMSLineFeed ); + ptr.Append( *ccLine ); + } + ptr.Append( KIMSLineFeed ); + ptr.Append( *subjectLine ); + ptr.Append( KIMSLineFeed ); + if ( hasBody ) + { + ptr.Append( *body ); + } + ptr.Append( KIMSLineFeed ); + ptr.Append( KIMSLineFeed ); + + // leave header on the cleanup stack + if ( hasBody ) + { + CleanupStack::PopAndDestroy( body ); //-7 + } + CleanupStack::PopAndDestroy( subjectLine ); //-6 + if ( hasCcLine ) + { + CleanupStack::PopAndDestroy( ccLine ); //-5 + } + CleanupStack::PopAndDestroy( toLine ); //-4 + CleanupStack::PopAndDestroy( sentLine ); //-3 + CleanupStack::PopAndDestroy( fromLine ); //-2 + CleanupStack::PopAndDestroy( separator ); //-1 + + CleanupStack::PushL( header ); + + return header; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::GenerateSmartTagLC +// ----------------------------------------------------------------------------- +HBufC* CNcsComposeView::GenerateSmartTagLC() + { + FUNC_LOG; + + HBufC* tag = StringLoader::LoadLC( R_FSE_EDITOR_SMART_TAG ); + + return tag; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::InitReplyOrForwardUiL +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::InitReplyOrForwardUiL() + { + FUNC_LOG; + // Show "Opening" wait note if the message body is large + TInt waitNoteId = KErrNotFound; + if ( TFsEmailUiUtility::IsMessageBodyLargeL(iOrigMessage) ) + { + waitNoteId = TFsEmailUiUtility::ShowGlobalWaitNoteLC( R_FSE_WAIT_OPENING_TEXT ); + } + + if ( iCustomMessageId == TUid::Uid( KEditorCmdReply ) ) + { + GenerateReplyMessageL( EFalse ); + InitReplyUiL( EFalse ); + } + else if ( iCustomMessageId == TUid::Uid( KEditorCmdReplyAll ) ) + { + GenerateReplyMessageL( ETrue ); + InitReplyUiL( ETrue ); + } + else if ( iCustomMessageId == TUid::Uid( KEditorCmdForward ) ) + { + GenerateForwardMessageL(); + InitForwardUiL(); + } + else + { + // This shouldn't ever happen. Panic in debug builds. + ASSERT( EFalse ); + } + + // Close the "Opening" wait note if it was shown + if ( waitNoteId != KErrNotFound ) + { + CleanupStack::PopAndDestroy( (TAny*)waitNoteId ); + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::GenerateReplyMessageL +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::GenerateReplyMessageL( TBool aReplyAll ) + { + FUNC_LOG; + + __ASSERT_DEBUG( iMailBox, Panic( ENcsBasicUi ) ); + + TReplyForwardParams params; + params.iHeader = GenerateReplyHeaderLC(); + params.iSmartTag = GenerateSmartTagLC(); + TPckgBuf buf( params ); + HBufC* temp = HBufC::NewLC( buf.Length() ); + temp->Des().Copy( buf ); + + // this is actually a waited async method + iFakeSyncGoingOn = ETrue; + iNewMessage = iMailBox->CreateReplyMessage( iLaunchParams.iMsgId, aReplyAll, *temp ); + iFakeSyncGoingOn = EFalse; + // + // Compose screen does not send cal messages, make sure + // that cal event flag is not left active by some protocol + if ( iNewMessage ) + { + iNewMessage->ResetFlag( EFSMsgFlag_CalendarMsg ); + } + CleanupStack::PopAndDestroy( temp ); + CleanupStack::PopAndDestroy( params.iSmartTag ); + CleanupStack::PopAndDestroy( params.iHeader ); + if ( !iNewMessage ) + { + User::Leave( KErrGeneral ); + } + iFakeSyncGoingOn = ETrue; // + TRAPD( error, TFsEmailUiUtility::MoveMessageToDraftsL( *iMailBox, *iNewMessage ) ); + iFakeSyncGoingOn = EFalse; // + User::LeaveIfError( error ); + + if ( iNewMessage->GetContentType() != KFSMailContentTypeMultipartMixed ) + { + iNewMessage->SetContentType( KFSMailContentTypeMultipartMixed ); + iNewMessage->SaveMessageL(); + } + + TFsEmailUiUtility::CreatePlainTextPartL( *iNewMessage, iNewMessageTextPart ); + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::GenerateForwardMessageL +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::GenerateForwardMessageL() + { + FUNC_LOG; + + __ASSERT_DEBUG( iMailBox, Panic( ENcsBasicUi ) ); + + TReplyForwardParams params; + params.iHeader = GenerateReplyHeaderLC(); + params.iSmartTag = GenerateSmartTagLC(); + TPckgBuf buf( params ); + HBufC* temp = HBufC::NewLC( buf.Length() ); + temp->Des().Copy( buf ); + + // this is actually a waited async call + iFakeSyncGoingOn = ETrue; + iNewMessage = iMailBox->CreateForwardMessage( iLaunchParams.iMsgId, *temp ); + iFakeSyncGoingOn = EFalse; + // + // Compose screen does not send cal messages, make sure + // that cal event flag is not left active by some protocol + if ( iNewMessage ) + { + iNewMessage->ResetFlag( EFSMsgFlag_CalendarMsg ); + } + CleanupStack::PopAndDestroy( temp ); + CleanupStack::PopAndDestroy( params.iSmartTag ); + CleanupStack::PopAndDestroy( params.iHeader ); + if ( !iNewMessage ) + { + User::Leave( KErrGeneral ); + } + iFakeSyncGoingOn = ETrue; // + TRAPD( error, TFsEmailUiUtility::MoveMessageToDraftsL( *iMailBox, *iNewMessage ) ); + iFakeSyncGoingOn = EFalse; // + User::LeaveIfError( error ); + + if ( iNewMessage->GetContentType() != KFSMailContentTypeMultipartMixed ) + { + iNewMessage->SetContentType( KFSMailContentTypeMultipartMixed ); + iNewMessage->SaveMessageL(); + } + + TFsEmailUiUtility::CreatePlainTextPartL( *iNewMessage, iNewMessageTextPart ); + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::InitReplyUiL +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::InitReplyUiL( TBool aReplyAll ) + { + FUNC_LOG; + if ( iFirstStartCompleted ) // Safety check + { + InitReplyFieldsL( aReplyAll ); + IncludeMessageTextL( ETrue ); + iContainer->SetFocusToMessageFieldL(); + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::InitUiGeneralL +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::InitUiGeneralL() + { + FUNC_LOG; + if ( iFirstStartCompleted ) // Safety check + { + AppUi()->AddToStackL( iContainer ); + iContainer->SetMenuBar( Cba() ); + + // + // TInt ccVisible = iCrHandler->EditorCCVisible(); + // iContainer->SetCcFieldVisibleL( ccVisible == 1, EFalse ); + // TInt bccVisible = iCrHandler->EditorBCVisible(); + // iContainer->SetBccFieldVisibleL( bccVisible == 1, EFalse ); + // + + iContainer->UpdateScrollBarL(); + + // Set title pane text + const TDesC& mbName = iMailBox->GetName(); + iAppUi.SetTitlePaneTextL( mbName ); + + // Set priority flag + SetPriority(); + + // Set follow-up flag + SetFollowUp(); + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::InitForwardUiL +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::InitForwardUiL() + { + FUNC_LOG; + if ( iFirstStartCompleted ) // Safety check + { + InitForwardFieldsL(); + IncludeMessageTextL( ETrue ); + iContainer->SetFocusToToField(); + iContainer->SelectAllToFieldTextL(); + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::SetReplyForwardFlag +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::SetReplyForwardFlagL() + { + FUNC_LOG; + + if ( iFirstStartCompleted && iOrigMessage ) + { + if ( iCustomMessageId == TUid::Uid( KEditorCmdReply ) || + iCustomMessageId == TUid::Uid( KEditorCmdReplyAll ) ) + { + iOrigMessage->SetFlag( EFSMsgFlag_Answered ); + iOrigMessage->SaveMessageL(); + } + else if ( iCustomMessageId == TUid::Uid( KEditorCmdForward ) ) + { + iOrigMessage->SetFlag( EFSMsgFlag_Forwarded ); + iOrigMessage->SaveMessageL(); + } + } + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::MailBoxSupportsSmartReply +// ----------------------------------------------------------------------------- +// +TBool CNcsComposeView::MailBoxSupportsSmartReply() + { + FUNC_LOG; + + __ASSERT_DEBUG( iMailBox, Panic( ENcsBasicUi ) ); + + return iMailBox->HasCapability( EFSMBoxCapaSmartReply ); + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::MailBoxSupportsSmartForward +// ----------------------------------------------------------------------------- +// +TBool CNcsComposeView::MailBoxSupportsSmartForward() + { + FUNC_LOG; + __ASSERT_DEBUG( iMailBox, Panic( ENcsBasicUi ) ); + + return iMailBox->HasCapability( EFSMBoxCapaSmartForward ); + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::HasUnfetchedAttachmentsL +// ----------------------------------------------------------------------------- +// +TBool CNcsComposeView::HasUnfetchedAttachmentsL( CFSMailMessage& aMsg ) + { + FUNC_LOG; + + __ASSERT_DEBUG( &aMsg, Panic( ENcsBasicUi ) ); + + TBool ret = EFalse; + + RPointerArray attachments; + CleanupResetAndDestroyClosePushL( attachments ); + aMsg.AttachmentListL( attachments ); + for ( TInt i=0; iFetchLoadState() ) + { + ret = ETrue; + break; + } + } + CleanupStack::PopAndDestroy( &attachments ); + + return ret; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::HandleActionL +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::HandleActionL( const TAlfActionCommand& aActionCommand ) + { + FUNC_LOG; + if ( iFirstStartCompleted && iNewMessage && iMailBox + && aActionCommand.Id() == KCmdEditorAutoSave ) + { + CommitL( EFalse ); + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::SaveToDraftsL +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::SaveToDraftsL( TBool aParseAddresses ) + { + FUNC_LOG; + if ( iFirstStartCompleted ) // Safety + { + __ASSERT_DEBUG( iMailBox, Panic( ENcsBasicUi ) ); + __ASSERT_DEBUG( iNewMessage, Panic( ENcsBasicUi ) ); + + iFakeSyncGoingOn = ETrue; + TRAPD( error, CommitL( aParseAddresses ) ); + iFakeSyncGoingOn = EFalse; + User::LeaveIfError( error ); + + iFakeSyncGoingOn = ETrue; + TRAP( error, TFsEmailUiUtility::MoveMessageToDraftsL( + *iMailBox, *iNewMessage ) ); + iFakeSyncGoingOn = EFalse; + User::LeaveIfError( error ); + + if ( !iAppUi.AppUiExitOngoing() ) + { + // Simulate a new mail event to ensure that saved message becomes visible in the + // mail list. All protocols do not send event automatically in this case. + RArray messageIdArray; + CleanupClosePushL( messageIdArray ); + messageIdArray.Append( iNewMessage->GetMessageId() ); + TFSMailMsgId folderId = iNewMessage->GetFolderId(); + TFSMailMsgId mailboxId = iNewMessage->GetMailBoxId(); + iAppUi.EventL( + TFSEventNewMail, mailboxId, &messageIdArray, &folderId, NULL ); + // Update displayed mail info if the mail was already created sooner + iAppUi.EventL( + TFSEventMailChanged, mailboxId, &messageIdArray, &folderId, NULL ); + CleanupStack::PopAndDestroy( &messageIdArray ); + } + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::FetchLogicComplete +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::FetchLogicComplete( TComposerFetchState /*aState*/, TInt aError ) + { + FUNC_LOG; + if ( iFirstStartCompleted ) // Safety + { + if ( !aError ) + { + TRAP( aError, InitReplyOrForwardUiL() ); + iAutoSaver->Enable( ETrue ); + } + else + { + // something went wrong + DoSafeExit(ENoSave); + iMailFetchingErrCode = aError; + } + } + if ( iFetchWaitDialog && !iFetchDialogCancelled ) + { + TRAP_IGNORE(iFetchWaitDialog->ProcessFinishedL()); + iFetchWaitDialog = NULL; + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::ExitComposer +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::ExitComposer() + { + FUNC_LOG; + + if ( iStatusPaneIndicators ) + { + iStatusPaneIndicators->HideStatusPaneIndicators(); + } + + // lower flag to indicate that view is no longer able to handle user commands + iViewReady = EFalse; + + // view switching and alfred operations should be avoided + // when Appui exit has been initialised + if ( !iAppUi.AppUiExitOngoing() ) + { + // change to previous view + TRAP_IGNORE( NavigateBackL() ); + } + + // Cleanup message contents to prevent ChildDoDeactivate() from saving the message to drafts again + ResetComposer(); + + SafeDelete( iFetchLogic ); + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::CreateContainerL +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::CreateContainerL() + { + FUNC_LOG; + TInt flags = NULL; + if ( iCrHandler->EditorCCVisible() ) + { + flags |= CNcsComposeViewContainer::ECcFieldVisible; + } + if ( iCrHandler->EditorBCVisible() ) + { + flags |= CNcsComposeViewContainer::EBccFieldVisible; + } + TRect rect = ClientRect(); + iContainer = CNcsComposeViewContainer::NewL( *this, rect, *iMailBox, + *iAutoSaver, flags ); + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::ResetComposer +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::ResetComposer() + { + FUNC_LOG; + + delete iMailBox; + iMailBox = NULL; + delete iOrigMessage; + iOrigMessage = NULL; + delete iNewMessageTextPart; + iNewMessageTextPart = NULL; + delete iNewMessage; + iNewMessage = NULL; + iDlg = NULL; + + if ( iContainer ) + { + AppUi()->RemoveFromStack( iContainer ); + delete iContainer; + iContainer = NULL; + } + + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::SaveAndCleanPreviousMessage +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::SaveAndCleanPreviousMessage() + { + FUNC_LOG; + + if ( iFirstStartCompleted && iContainer && iNewMessage && iMailBox ) + { + + TBool noAddrOrNoMesBody = iContainer->AreAddressFieldsEmpty() && + iContainer->IsSubjectFieldEmpty() && + (iContainer->GetMessageFieldLength() < 1); + + // save to Drafts if there's some user input in some header field or in message body + if ( !noAddrOrNoMesBody ) + { + TRAPD( error, DoSaveDraftL( EFalse ) ); + if ( error ) + { + } + } + + // store the message IDs to launch parameters to be able to return to same message if desired + iLaunchParams.iMsgId = iNewMessage->GetMessageId(); + iLaunchParams.iFolderId = iNewMessage->GetFolderId(); + iLaunchParams.iMailboxId = iMailBox->GetId(); + } + ResetComposer(); + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::AsyncExit +// ----------------------------------------------------------------------------- +// +TInt CNcsComposeView::AsyncExit( TAny* aSelfPtr ) + { + FUNC_LOG; + CNcsComposeView* self = + static_cast( aSelfPtr ); + + TRAPD( err,self->AsyncExitL() ); + return err; + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::AsyncExitL +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::AsyncExitL() + { + FUNC_LOG; + if ( iFakeSyncGoingOn || iExecutingDoExitL ) // if some sync method is still going on, we continue waiting + { + iActiveHelper->Cancel(); + iActiveHelper->Start(); + } + else + { + ExitComposer(); + // for some strange reason composer view is stuck and only option was to call ProcessCommandL with EAknCmdExit + ProcessCommandL( EAknCmdExit ); + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::HandleContainerChangeRequiringToolbarRefresh +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::HandleContainerChangeRequiringToolbarRefresh() + { + RefreshToolbar(); + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::ShowFetchingWaitNoteL +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::ShowFetchingWaitNoteL() + { + FUNC_LOG; + if ( !iAppUi.AppUiExitOngoing() ) + { + if ( !iFetchWaitDialog ) + { + iFetchWaitDialog = new(ELeave)CAknWaitDialog( + (REINTERPRET_CAST(CEikDialog**,&iFetchWaitDialog)), EFalse); + iFetchWaitDialog->SetCallback(this); + iFetchDialogCancelled = EFalse; + iFetchWaitDialog->ExecuteLD(R_FSE_FETCHING_WAIT_DIALOG); + } + } + } + +// ----------------------------------------------------------------------------- +// CNcsComposeView::DialogDismissedL +// ----------------------------------------------------------------------------- +// +void CNcsComposeView::DialogDismissedL( TInt aButtonId ) + { + FUNC_LOG; + if ( (aButtonId == EAknSoftkeyCancel) && iFetchLogic ) + { + iFetchDialogCancelled = ETrue; + iFetchLogic->CancelFetchings(); + } + } + +TBool CNcsComposeView::IsPreparedForExit() + { + return !(iFakeSyncGoingOn ||iExecutingDoExitL); + } + +// --------------------------------------------------------------------------- +// CActiveHelper::NewL() +// --------------------------------------------------------------------------- +// +CActiveHelper* CActiveHelper::NewL(CNcsComposeView* aSession ) + { + CActiveHelper* self = new(ELeave) CActiveHelper(aSession); + CleanupStack::PushL( self ); + self->ConstructL( ); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// CActiveHelper::~CActiveHelper() +// --------------------------------------------------------------------------- +// +CActiveHelper::~CActiveHelper( ) + { + Cancel(); + } + +// --------------------------------------------------------------------------- +// CActiveHelper::Start() +// --------------------------------------------------------------------------- +// +void CActiveHelper::Start() + { + TRequestStatus* status = &iStatus; + User::RequestComplete(status,KErrNone); + SetActive(); + } + +// --------------------------------------------------------------------------- +// CActiveHelper::CActiveHelper() +// --------------------------------------------------------------------------- +// +CActiveHelper::CActiveHelper(CNcsComposeView* aSession ) : CActive(EPriorityLow) + { + iComposeView = aSession; + } + +// --------------------------------------------------------------------------- +// CActiveHelper::RunL() +// --------------------------------------------------------------------------- +// +void CActiveHelper::RunL() + { + if(iComposeView) + iComposeView->AsyncExitL(); + } + +// --------------------------------------------------------------------------- +// CActiveHelper::DoCancel() +// --------------------------------------------------------------------------- +// +void CActiveHelper::DoCancel() + { + // Empty + } + +// --------------------------------------------------------------------------- +// CActiveHelper::ConstructL() +// --------------------------------------------------------------------------- +// +void CActiveHelper::ConstructL() + { + CActiveScheduler::Add(this); + } + +//