diff -r d189ee25cf9d -r 3533d4323edc emailuis/emailui/src/FreestyleEmailUiHtmlViewerContainer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emailuis/emailui/src/FreestyleEmailUiHtmlViewerContainer.cpp Wed Sep 01 12:28:57 2010 +0100 @@ -0,0 +1,2299 @@ +/* +* 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: CFsEmailUiHtmlViewerContainer class implementation +* +*/ + + +#include "emailtrace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +#include "cfsmailmessage.h" +// +#include +#include +#include + +#include + +#include "FreestyleEmailUiAppui.h" +#include "FreestyleEmailUiUtilities.h" +#include "FreestyleEmailUiHtmlViewerContainer.h" +#include "FreestyleEmailUiHtmlViewerView.h" +#include "FreestyleEmailUiShortcutBinding.h" + +#include "FreestyleMessageHeaderHTML.h" +#include "FreestyleMessageHeaderURLEventHandler.h" +#include "FreestyleEmailUiAttachmentsListModel.h" + +_LIT( KContentIdPrefix, "cid:" ); +_LIT( KCDrive, "c:" ); +_LIT( KHtmlPath, "HtmlFile\\" ); +_LIT( KTempHtmlPath, "temp\\" ); +_LIT( KAllFiles, "*" ); + +_LIT( KHeaderHtmlFile, "header.html" ); +_LIT( KBodyHtmlFile, "body.html" ); +_LIT( KMessageHtmlFile, "email.html" ); +_LIT( KMessageHtmlRTLFile, "email_rtl.html" ); +_LIT( KZDrive, "z:" ); +_LIT( KHtmlFlagFile, "html.flag" ); +_LIT( KURLSlash, "/"); +// Constants used in html content modification +const TInt KMaxCharsToSearch( 200 ); +_LIT8( KStartTag, ""); +_LIT8( KHtmlHeader1, "\xD\xA"); +_LIT8( KHtmlHeader3, "\n"); +_LIT8( KHtmlEndTags, "\xD\xA\xD\xA"); +_LIT8( KCharsetTag8, "charset"); +_LIT( KCharsetTag, "charset"); +_LIT8( KHTMLEmptyContent, ""); +_LIT( KHTMLDataScheme, "data:0"); + + +_LIT( KHtmlLineBreak, "
" ); +_LIT( KHtmlLineBreakCRLF, "
\xD\xA" ); +_LIT( KHtmlLessThan, "<" ); +_LIT( KHtmlGreaterThan, ">" ); +_LIT( KHtmlAmpersand, "&" ); +_LIT( KHtmlQuotation, """ ); +_LIT( KURLTypeBody, "body"); + +_LIT( KURLDisplayImages, "cmail://displayImages/" ); +_LIT( KURLLoadImages, "cmail://loadImages/" ); +_LIT( KURLCollapseHeader, "cmail://collapseHeader/" ); +_LIT( KURLExpandHeader, "cmail://expandHeader/" ); +_LIT( KURLExpandItem, "cmail://expand_" ); +_LIT( KURLItemTo, "to" ); +_LIT( KURLItemCc, "cc" ); +_LIT( KURLItemBcc, "bcc" ); +_LIT( KURLItemAttachments, "attachments" ); + +const TText KGreaterThan = 0x3e; +const TText KLessThan = 0x3c; +const TText KAmpersand = 0x26; +const TText KQuotation = 0x22; +const TText KSOH = 0x01; // Start Of Heading +const TText KLF = 0x0a; // Line Feed +const TText KUnicodeNewLineCharacter = 0x2028; +const TText KUnicodeParagraphCharacter = 0x2029; +const TReal KOverlayButtonMarginX = 0.01; // 1% +const TReal KOverlayButtonMarginY = 0.01; // 1% +const TReal KOverlayButtonSizeP = 0.15; // 15% +const TReal KOverlayButtonSizeLs = 0.20; // 25% + + +const TInt KStatusIndicatorHeight = 55; +const TInt KStatusIndicatorXMargin = 58; +const TInt KStatusIndicatorBottomMargin = 6; + +// CONSTANTS +// Zoom levels available on the UI +const TInt KZoomLevels[] = { 75, 100, 125, 150 }; +const TInt KZoomLevelCount = sizeof( KZoomLevels ) / sizeof( TInt ); +const TInt KZoomLevelIndex100 = 1; // 100 in array KZoomLevels + +// CEUiHtmlViewerSettingsKeyListener + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +CEUiHtmlViewerSettingsKeyListener::CEUiHtmlViewerSettingsKeyListener( MObserver& aObserver, TUint32 aKey ) + : CActive( EPriorityStandard ), iObserver( aObserver ), iKey( aKey ) + { + CActiveScheduler::Add(this); + StartListening(); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +CEUiHtmlViewerSettingsKeyListener::~CEUiHtmlViewerSettingsKeyListener() + { + Cancel(); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CEUiHtmlViewerSettingsKeyListener::StartListening() + { + SetActive(); + iObserver.Repository().NotifyRequest(iKey, iStatus); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CEUiHtmlViewerSettingsKeyListener::RunL() + { + iObserver.KeyValueChangedL(iKey); + StartListening(); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CEUiHtmlViewerSettingsKeyListener::DoCancel() + { + iObserver.Repository().NotifyCancel(iKey); + } + +// CEUiHtmlViewerSettings + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +CEUiHtmlViewerSettings* CEUiHtmlViewerSettings::NewL( MObserver& aObserver ) + { + CEUiHtmlViewerSettings* self = new (ELeave) CEUiHtmlViewerSettings(aObserver); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +CEUiHtmlViewerSettings::~CEUiHtmlViewerSettings() + { + iKeyListeners.ResetAndDestroy(); + delete iRepository; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +CEUiHtmlViewerSettings::CEUiHtmlViewerSettings( MObserver& aObserver ) : iObserver( aObserver ) + { + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CEUiHtmlViewerSettings::ConstructL() + { + iRepository = CRepository::NewL(KFreestyleEmailCenRep); + AddKeyListenerL(KFreestyleEmailDownloadHTMLImages); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CEUiHtmlViewerSettings::AddKeyListenerL( TUint32 aKey ) + { + CEUiHtmlViewerSettingsKeyListener* listener = + new (ELeave) CEUiHtmlViewerSettingsKeyListener( *this, aKey ); + CleanupStack::PushL( listener ); + iKeyListeners.AppendL( listener ); + CleanupStack::Pop( listener ); + UpdateValue( aKey ); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CEUiHtmlViewerSettings::UpdateValue( TUint32 aKey ) + { + TInt value; + iRepository->Get(aKey, value); + switch (aKey) + { + case KFreestyleEmailDownloadHTMLImages: + // 0 = automatic, 1 = ask always + iFlags.Assign(aKey, value == 0); + break; + default: + iFlags.Assign(aKey, value); + break; + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CEUiHtmlViewerSettings::KeyValueChangedL( TUint32 aKey ) + { + UpdateValue(aKey); + iObserver.ViewerSettingsChangedL(aKey); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +CRepository& CEUiHtmlViewerSettings::Repository() + { + return *iRepository; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +TBool CEUiHtmlViewerSettings::AutoLoadImages() const + { + return iFlags.IsSet(EAutoLoadImages); + } + +// --------------------------------------------------------------------------- +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +CFsEmailUiHtmlViewerContainer* CFsEmailUiHtmlViewerContainer::NewL( + CFreestyleEmailUiAppUi& aAppUi, CFsEmailUiHtmlViewerView& aView ) + { + FUNC_LOG; + CFsEmailUiHtmlViewerContainer* self = + new (ELeave) CFsEmailUiHtmlViewerContainer( aAppUi, aView ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// C++ constructor. +// --------------------------------------------------------------------------- +// +CFsEmailUiHtmlViewerContainer::CFsEmailUiHtmlViewerContainer( + CFreestyleEmailUiAppUi& aAppUi, CFsEmailUiHtmlViewerView& aView ) + : + iAppUi( aAppUi ), + iView( aView ), + iFs( iCoeEnv->FsSession() ), + iFirstTime( ETrue ), + iZoomLevel( KZoomLevelIndex100 ) + { + FUNC_LOG; + } + +// --------------------------------------------------------------------------- +// Destructor. +// --------------------------------------------------------------------------- +// +CFsEmailUiHtmlViewerContainer::~CFsEmailUiHtmlViewerContainer() + { + FUNC_LOG; + delete iViewerSettings; + if ( iObservingDownload && iAppUi.DownloadInfoMediator() ) + { + iAppUi.DownloadInfoMediator()->StopObserving( this ); + } + iFile.Close(); + iLinkContents.Close(); + iMessageParts.Close(); + delete iEventHandler; + delete iBrCtlInterface; + iConnection.Close(); + iSocketServer.Close(); + delete iStatusIndicator; + delete iOverlayControlNext; + delete iOverlayControlPrev; + } + +void CFsEmailUiHtmlViewerContainer::PrepareForExit() + { + FUNC_LOG; + HideDownloadStatus(); + if ( iObservingDownload && iAppUi.DownloadInfoMediator() ) + { + iAppUi.DownloadInfoMediator()->StopObserving( this ); + iObservingDownload = EFalse; + } + delete iBrCtlInterface; + iBrCtlInterface = NULL; + iConnection.Close(); + iSocketServer.Close(); + } + +void CFsEmailUiHtmlViewerContainer::PrepareForMessageNavigation() + { + FUNC_LOG; + ResetContent(); + } + +void CFsEmailUiHtmlViewerContainer::ZoomInL() + { + SetZoomLevelL( ZoomLevelL() + 1 ); + } + +void CFsEmailUiHtmlViewerContainer::ZoomOutL() + { + SetZoomLevelL( ZoomLevelL() - 1 ); + } + +TInt CFsEmailUiHtmlViewerContainer::ZoomLevelL() const + { + FUNC_LOG; + TInt zoomLevelIdx = iBrCtlInterface->BrowserSettingL( + TBrCtlDefs::ESettingsCurrentZoomLevelIndex ); + + // Behaviour of zooming in Browser Control Interface is different in version 7.1 + // than in previous versions and we need to support both. In older versions there + // are 4 preset zoom levels while version 7.1 can zoom to any percent. + RArray* zoomLevels = iBrCtlInterface->ZoomLevels(); + + if ( !zoomLevels || !zoomLevels->Count() || ( *zoomLevels )[0] != KZoomLevels[0] ) + { + // new browser: + // BrowserControlIf gives zoom level percentage insted of index to array + TBool found = EFalse; + + for ( TInt i = 0 ; i < KZoomLevelCount && !found ; ++i ) + { + if ( zoomLevelIdx == KZoomLevels[i] ) + { + zoomLevelIdx = i; + found = ETrue; + } + } + + if ( !found ) + { + zoomLevelIdx = KErrNotFound; + } + } + return zoomLevelIdx; + } + +void CFsEmailUiHtmlViewerContainer::SetZoomLevelL( const TInt aZoomLevel ) + { + FUNC_LOG; + TInt newValue = KMinTInt; + + // Behaviour of zooming in Browser Control Interface is different in version 7.1 + // than in previous versions and we need to support both. In older versions there + // are 4 preset zoom levels while version 7.1 can zoom to any percent. + RArray* zoomLevels = iBrCtlInterface->ZoomLevels(); + + if ( !zoomLevels || !zoomLevels->Count() || ( *zoomLevels )[0] != KZoomLevels[0] ) + { + // new browser: + // BrowserControlIf takes zoom level percentage insted of index to array + if ( aZoomLevel >= 0 && aZoomLevel < KZoomLevelCount ) + { + newValue = KZoomLevels[aZoomLevel]; + } + } + else + { + // old browser + newValue = aZoomLevel; + } + + iZoomLevel = ( newValue > KMinTInt ) ? newValue : aZoomLevel; + iBrCtlInterface->SetBrowserSettingL( + TBrCtlDefs::ESettingsCurrentZoomLevelIndex, iZoomLevel ); + } + +TInt CFsEmailUiHtmlViewerContainer::DoZoom( TAny* aPtr ) + { + TRAPD( error, reinterpret_cast( aPtr )->DoZoomL() ); + return error; + } + +void CFsEmailUiHtmlViewerContainer::DoZoomL() + { + iBrCtlInterface->SetBrowserSettingL( + TBrCtlDefs::ESettingsCurrentZoomLevelIndex, iZoomLevel ); + } + +TInt CFsEmailUiHtmlViewerContainer::MaxZoomLevel() const + { + return KZoomLevelCount; + } + + +void CFsEmailUiHtmlViewerContainer::CreateBrowserControlInterfaceL() + { + FUNC_LOG; + + if ( iBrCtlInterface ) + { + SetZoomLevelL(100); + iBrCtlInterface->SetBrowserSettingL( TBrCtlDefs::ESettingsAutoLoadImages, iViewerSettings->AutoLoadImages() ); + return; + } + + TUint brCtlCapabilities = TBrCtlDefs::ECapabilityClientResolveEmbeddedURL | + TBrCtlDefs::ECapabilityDisplayScrollBar | + TBrCtlDefs::ECapabilityClientNotifyURL | + TBrCtlDefs::ECapabilityLoadHttpFw | + TBrCtlDefs::ECapabilityCursorNavigation | + TBrCtlDefs::ECapabilityPinchZoom | + TBrCtlDefs::ECapabilityFitToScreen; + + // Set browsercontrol to whole screen + TRect rect( TPoint(), Size() ); + + iBrCtlInterface = CreateBrowserControlL( + this, // aParent + rect, // aRect + brCtlCapabilities, // aBrCtlCapabilities + TBrCtlDefs::ECommandIdBase, // aCommandIdBase + NULL, // aBrCtlSoftkeysObserver + this, // aBrCtlLinkResolver + this, // aBrCtlSpecialLoadObserver + NULL, // aBrCtlLayoutObserver + NULL, // aBrCtlDialogsProvider + this, // aBrCtlWindowObserver + NULL // aBrCtlDownloadObserver + ); + + iBrCtlInterface->SetBrowserSettingL( TBrCtlDefs::ESettingsEmbedded, ETrue ); + iBrCtlInterface->SetBrowserSettingL( TBrCtlDefs::ESettingsAutoLoadImages, iViewerSettings->AutoLoadImages() ); + iBrCtlInterface->SetBrowserSettingL( TBrCtlDefs::ESettingsPageOverview, EFalse ); + iBrCtlInterface->SetBrowserSettingL( TBrCtlDefs::ESettingsTextWrapEnabled, ETrue ); + iBrCtlInterface->SetBrowserSettingL( TBrCtlDefs::ESettingsFontSize, TBrCtlDefs::EFontSizeLevelLarger ); + } + +void CFsEmailUiHtmlViewerContainer::ConstructL() + { + FUNC_LOG; + iViewerSettings = CEUiHtmlViewerSettings::NewL(*this); + + SetHtmlFolderPathL(); + BaflUtils::EnsurePathExistsL( iFs, iHtmlFolderPath ); + SetTempHtmlFolderPath(); + BaflUtils::EnsurePathExistsL( iFs, iTempHtmlFolderPath ); + SetHTMLResourceFlagFullName(); + EnsureHTMLResourceL(); + + CreateWindowL(); + +#if defined( BRDO_MULTITOUCH_ENABLED_FF ) && !defined ( __WINSCW__ ) + //Enable advance pointer info for multi-touch. + Window().EnableAdvancedPointers(); +#endif + + + iEventHandler = CFreestyleMessageHeaderURLEventHandler::NewL( iAppUi, iView ); + + TRect nextButtonRect = OverlayButtonRect( EFalse ); + iOverlayControlNext = COverlayControl::NewL( this, this, nextButtonRect, + EMbmFreestyleemailuiQgn_indi_cmail_arrow_next, + EMbmFreestyleemailuiQgn_indi_cmail_arrow_next_mask ); + + TRect prevButtonRect = OverlayButtonRect( ETrue ); + iOverlayControlPrev = COverlayControl::NewL( this, this, prevButtonRect, + EMbmFreestyleemailuiQgn_indi_cmail_arrow_previous, + EMbmFreestyleemailuiQgn_indi_cmail_arrow_previous_mask ); + iScrollPosition = 0; + iAttachmentDownloadImageHandle = 0; + + iTouchFeedBack = MTouchFeedback::Instance(); + iTouchFeedBack->EnableFeedbackForControl(this, ETrue); + + CreateBrowserControlInterfaceL(); + SetRect( iView.ContainerRect() ); + + ActivateL(); + } + +void CFsEmailUiHtmlViewerContainer::MakeVisible( TBool aVisible ) + { + UpdateOverlayButtons( aVisible ); + CCoeControl::MakeVisible( aVisible ); + } + +void CFsEmailUiHtmlViewerContainer::HandleOverlayPointerEventL( COverlayControl* aControl, + const TPointerEvent& aEvent ) + { + if( aEvent.iType == TPointerEvent::EButton1Up ) + { + if( aControl == iOverlayControlNext ) + { + iView.HandleCommandL( EFsEmailUiCmdNextMessage ); + } + else if( aControl == iOverlayControlPrev ) + { + iView.HandleCommandL( EFsEmailUiCmdPreviousMessage ); + } + } + } + +void CFsEmailUiHtmlViewerContainer::UpdateOverlayButtons( TBool aVisible ) + { + TBool nextAvailable = EFalse; + TBool prevAvailable = EFalse; + if( iMessage ) + { + TFSMailMsgId currentMsgId = iMessage->GetMessageId(); + TFSMailMsgId tmpMsgId; + TFSMailMsgId tmpMsgFolderId; + nextAvailable = iAppUi.IsNextMsgAvailable( currentMsgId, tmpMsgId, tmpMsgFolderId ); + prevAvailable = iAppUi.IsPreviousMsgAvailable( currentMsgId, tmpMsgId, tmpMsgFolderId ); + } + + if( iOverlayControlPrev ) + { + iOverlayControlPrev->SetRect( OverlayButtonRect( ETrue ) ); + iOverlayControlPrev->MakeVisible( aVisible && prevAvailable ); + } + if( iOverlayControlNext ) + { + iOverlayControlNext->SetRect( OverlayButtonRect( EFalse ) ); + iOverlayControlNext->MakeVisible( aVisible && nextAvailable ); + } + } + +// Get rect for button +TRect CFsEmailUiHtmlViewerContainer::OverlayButtonRect( TBool aLeft ) + { + TRect rect = Rect(); + TSize size = rect.Size(); + + TBool landscape = size.iWidth > size.iHeight; + TInt buttonSize; + + if( landscape ) + { + buttonSize = size.iHeight * KOverlayButtonSizeLs; + } + else + { + buttonSize = size.iWidth * KOverlayButtonSizeP; + } + + rect.iBr.iY = size.iHeight * (1-KOverlayButtonMarginY); + + if( aLeft ) + { + rect.iTl.iX = size.iWidth * KOverlayButtonMarginX; + rect.iBr.iX = rect.iTl.iX + buttonSize; + } + else + { + rect.iBr.iX = size.iWidth * (1 - KOverlayButtonMarginX); + rect.iTl.iX = rect.iBr.iX - buttonSize; + } + + rect.iTl.iY = rect.iBr.iY - buttonSize; + return rect; + } + +// Getter for br contro, interface +CBrCtlInterface* CFsEmailUiHtmlViewerContainer::BrowserControlIf() + { + FUNC_LOG; + return iBrCtlInterface; + } + +void CFsEmailUiHtmlViewerContainer::LoadContentFromFileL( const TDesC& aFileName ) + { + FUNC_LOG; + iBrCtlInterface->LoadFileL( aFileName ); + } + +void CFsEmailUiHtmlViewerContainer::LoadContentFromFileL( RFile& aFile ) + { + FUNC_LOG; + iBrCtlInterface->LoadFileL( aFile ); + } + +void CFsEmailUiHtmlViewerContainer::LoadContentFromUrlL( const TDesC& aUrl ) + { + FUNC_LOG; + iBrCtlInterface->LoadUrlL( aUrl ); + } + +// --------------------------------------------------------------------------- +// Loads content from given mail message. +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::LoadContentFromMailMessageL( + CFSMailMessage* aMailMessage, TBool aResetScrollPos ) + { + FUNC_LOG; + ASSERT( aMailMessage ); + iMessage = aMailMessage; + // Cancel any browser fetch operation, just in case the browser is still + // loading a previous message (since we are about to overwrite it). + CancelFetch(); + + TPath headerHtmlFile; + headerHtmlFile.Copy( iHtmlFolderPath ); + headerHtmlFile.Append( KHeaderHtmlFile ); + + // insert email header into email.html file + // CFreestyleMessageHeaderHTML will replace contents of email.html + // So, no need to clear the contents + if(aResetScrollPos) + { + iScrollPosition = 0; + } + const TInt visibleWidth(iAppUi.ClientRect().Width()); + CFreestyleMessageHeaderHTML::ExportL( *iMessage, iFs, headerHtmlFile, visibleWidth, iScrollPosition, + iViewerSettings->AutoLoadImages() || iAppUi.DisplayImagesCache().Contains(*iMessage), iFlags ); + + // Remove all previously created files from temporary HTML folder + EmptyTempHtmlFolderL(); + + TRAPD( error, PrepareBodyHtmlL( KBodyHtmlFile ) ); + if ( error != KErrNone ) + { + WriteEmptyBodyHtmlL( KBodyHtmlFile ); + } + + // pass the emailHtmlFile to the browser for it to load + TPath emailHtmlFile; + emailHtmlFile.Copy( iHtmlFolderPath ); + if ( !AknLayoutUtils::LayoutMirrored() ) + { + emailHtmlFile.Append( KMessageHtmlFile ); + } + else + { + emailHtmlFile.Append( KMessageHtmlRTLFile ); + } + + // If scroll position is not to be reset, re-creation of browser control + // interface object is skipped (we're just reloading the page with new + // content) + if ( aResetScrollPos ) + { + CreateBrowserControlInterfaceL(); + } + + LoadContentFromFileL( emailHtmlFile ); + + UpdateOverlayButtons( ETrue ); + } + +// --------------------------------------------------------------------------- +// Reset content +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::ResetContent( TBool aDisconnect, + TBool aClearFlags ) + { + FUNC_LOG; + if ( iBrCtlInterface ) + { + TRAP_IGNORE( + iBrCtlInterface->HandleCommandL( ( TInt )TBrCtlDefs::ECommandIdBase + + ( TInt )TBrCtlDefs::ECommandFreeMemory ) ); + if (aDisconnect) + { + TRAP_IGNORE( + iBrCtlInterface->HandleCommandL( ( TInt )TBrCtlDefs::ECommandIdBase + + ( TInt )TBrCtlDefs::ECommandDisconnect ) ); + } + } + iFile.Close(); + iLinkContents.Reset(); + iMessageParts.Reset(); + iMessage = NULL; + if ( aClearFlags ) + { + iFlags.ClearAll(); + } + iScrollPosition = 0; + } + +// --------------------------------------------------------------------------- +// From CCoeControl. +// --------------------------------------------------------------------------- +// +CCoeControl* CFsEmailUiHtmlViewerContainer::ComponentControl( TInt aIndex ) const + { + FUNC_LOG; + switch ( aIndex ) + { + case 0: + { + return iBrCtlInterface; + } + case 1: + { + return iOverlayControlNext; + } + case 2: + { + return iOverlayControlPrev; + } + case 3: + { + if ( iStatusIndicator ) + return iStatusIndicator; + else + return NULL; + } + default: + { + return NULL; + } + } + } + +// --------------------------------------------------------------------------- +// From CCoeControl. +// --------------------------------------------------------------------------- +// +TInt CFsEmailUiHtmlViewerContainer::CountComponentControls() const + { + FUNC_LOG; + if ( iStatusIndicator ) + { + return 4; + } + else + { + return 3; + } + } + +// --------------------------------------------------------------------------- +// From CCoeControl. +// Draw this application's view to the screen +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::Draw( const TRect& /*aRect*/ ) const + { + FUNC_LOG; + // Get the standard graphics context + CWindowGc& gc = SystemGc(); + + // Gets the control's extent + TRect rect = Rect(); + + // Clears the screen + gc.Clear( rect ); + } + +// --------------------------------------------------------------------------- +// From CCoeControl. +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::SizeChanged() + { + FUNC_LOG; + + TRect rect = Rect(); + if ( iBrCtlInterface ) + { + iBrCtlInterface->SetRect( rect ); + } + + UpdateOverlayButtons( IsVisible() ); + + if ( iStatusIndicator ) + { + TRect rect = CalcAttachmentStatusRect(); + iStatusIndicator->SetRect( rect ); + } + } + +// --------------------------------------------------------------------------- +// From CCoeControl. +// --------------------------------------------------------------------------- +// +TKeyResponse CFsEmailUiHtmlViewerContainer::OfferKeyEventL( + const TKeyEvent& aKeyEvent, TEventCode aType ) + { + FUNC_LOG; + + TKeyResponse retVal = EKeyWasNotConsumed; + + // Handle keyboard shortcuts already on key down event as all keys + // do not necessarily send the key event at all. + if ( aType == EEventKeyDown ) + { + // Check keyboard shortcuts + TInt shortcutCommand = iAppUi.ShortcutBinding().CommandForShortcutKey( + aKeyEvent, CFSEmailUiShortcutBinding::EContextHtmlViewer ); + + if ( shortcutCommand != KErrNotFound ) + { + iView.HandleCommandL( shortcutCommand ); + retVal = EKeyWasConsumed; + } + } + + if ( iBrCtlInterface && retVal == EKeyWasNotConsumed ) + { + TKeyEvent event = aKeyEvent; + if ( iBrCtlInterface->FocusedElementType() == TBrCtlDefs::EElementButton + && ( aKeyEvent.iScanCode == EStdKeyNkpEnter + || aKeyEvent.iScanCode == EStdKeyEnter ) ) + { + // Enter key events are converted to selection key event in + // order to get browser to handle them in similar way. + event.iScanCode = EStdKeyDevice3; + event.iCode = aKeyEvent.iCode ? EKeyDevice3 : 0; + } + retVal = iBrCtlInterface->OfferKeyEventL( event, aType ); + } + + iView.SetMskL(); + + return retVal; + } + +// --------------------------------------------------------------------------- +// From MBrCtlSpecialLoadObserver. +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::NetworkConnectionNeededL( + TInt* aConnectionPtr, + TInt* aSockSvrHandle, + TBool* aNewConn, + TApBearerType* aBearerType ) + { + FUNC_LOG; + *aBearerType = EApBearerTypeAllBearers; + + if ( iFirstTime ) + { + User::LeaveIfError( iSocketServer.Connect( KESockDefaultMessageSlots ) ); + User::LeaveIfError( iConnection.Open( iSocketServer, KConnectionTypeDefault ) ); + TCommDbConnPref prefs; + prefs.SetDialogPreference( ECommDbDialogPrefDoNotPrompt ); + prefs.SetDirection( ECommDbConnectionDirectionOutgoing ); + prefs.SetIapId( 0 ); // Ask for access point + User::LeaveIfError( iConnection.Start( prefs ) ); + *aNewConn = ETrue; + iFirstTime = EFalse; + } + else + { + *aNewConn = EFalse; + } + + *aConnectionPtr = reinterpret_cast(&iConnection); + *aSockSvrHandle = iSocketServer.Handle(); + } + +// --------------------------------------------------------------------------- +// From MBrCtlSpecialLoadObserver. +// --------------------------------------------------------------------------- +// +TBool CFsEmailUiHtmlViewerContainer::HandleRequestL( + RArray* /*aTypeArray*/, CDesCArrayFlat* /*aDesArray*/ ) + { + FUNC_LOG; + // Let browser control handle these + return EFalse; + } + +// --------------------------------------------------------------------------- +// From MBrCtlSpecialLoadObserver. +// --------------------------------------------------------------------------- +// +TBool CFsEmailUiHtmlViewerContainer::HandleDownloadL( + RArray* /*aTypeArray*/, CDesCArrayFlat* /*aDesArray*/ ) + { + FUNC_LOG; + // Let browser control handle these + return EFalse; + } + +// --------------------------------------------------------------------------- +// From MFSEmailDownloadInformationObserver. +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::RequestResponseL( const TFSProgress& aEvent, + const TPartData& aPart ) + { + FUNC_LOG; + if ( aEvent.iProgressStatus == TFSProgress::EFSStatus_RequestComplete ) + { + MBrCtlLinkContent* linkContent = NULL; + for ( TInt ii = iMessageParts.Count() - 1; ii >= 0 && !linkContent; --ii ) + { + if ( iMessageParts[ii] == aPart ) + { + iMessageParts.Remove( ii ); + linkContent = iLinkContents[ii]; + iLinkContents.Remove( ii ); + } + } + + if ( !iMessageParts.Count() && iAppUi.DownloadInfoMediator() ) + { + iAppUi.DownloadInfoMediator()->StopObserving( this ); + } + + if ( iMessage && linkContent ) + { + CFSMailMessagePart* part = iMessage->ChildPartL( aPart.iMessagePartId ); + CleanupStack::PushL( part ); + RFile contentFile = part->GetContentFileL(); + CleanupClosePushL( contentFile ); + HBufC8* content = ReadContentFromFileLC( contentFile, *part ); + linkContent->HandleResolveComplete( + part->GetContentType(), KNullDesC(), content ); + CleanupStack::PopAndDestroy( content ); + CleanupStack::PopAndDestroy( &contentFile ); + CleanupStack::PopAndDestroy( part ); + } + + if ( iMessage ) + { + LoadContentFromMailMessageL( iMessage, EFalse ); + UpdateOverlayButtons( ETrue ); + } + } + else if ( aEvent.iProgressStatus == TFSProgress::EFSStatus_RequestCancelled || + aEvent.iProgressStatus < 0 ) + { + if ( iAppUi.DownloadInfoMediator() ) + { + iAppUi.DownloadInfoMediator()->StopObserving( this, aPart.iMessageId ); + } + } + } + +// --------------------------------------------------------------------------- +// From MBrCtlLinkResolver. +// --------------------------------------------------------------------------- +// +TBool CFsEmailUiHtmlViewerContainer::ResolveEmbeddedLinkL( + const TDesC& aEmbeddedUrl, const TDesC& /*aCurrentUrl*/, + TBrCtlLoadContentType /*aLoadContentType*/, + MBrCtlLinkContent& aEmbeddedLinkContent ) + { + FUNC_LOG; + TBool linkResolved = EFalse; + + // Check if given link contains content ID + if ( aEmbeddedUrl.Left( KContentIdPrefix().Length() ).CompareF( KContentIdPrefix ) == 0 ) + { + TPtrC cid = aEmbeddedUrl.Mid( KContentIdPrefix().Length() ); + linkResolved = ResolveLinkL( cid, ETrue, aEmbeddedLinkContent ); + } + else + { + // Replace all slash character with backslash characters + HBufC* embeddedUrl = aEmbeddedUrl.AllocLC(); + TPtr ptr = embeddedUrl->Des(); + _LIT( KBackslash, "\\" ); + for ( TInt pos = ptr.Locate('/'); pos >= 0; pos = ptr.Locate('/') ) + { + ptr.Replace( pos, 1, KBackslash ); + } + + // Check whether given url refers to file in the temporary html folder + TInt pos = embeddedUrl->FindF( iTempHtmlFolderPath ); + if ( pos >= 0 ) + { + TPtrC filename = embeddedUrl->Mid( pos + iTempHtmlFolderPath.Length() ); + linkResolved = ResolveLinkL( filename, EFalse, aEmbeddedLinkContent ); + } + + CleanupStack::PopAndDestroy( embeddedUrl ); + } + + // Return whether link is resolved by host application. + return linkResolved; + } + +// --------------------------------------------------------------------------- +// From MBrCtlLinkResolver. +// --------------------------------------------------------------------------- +// +TBool CFsEmailUiHtmlViewerContainer::ResolveLinkL( const TDesC& aUrl, + const TDesC& /*aCurrentUrl*/, MBrCtlLinkContent& /*aBrCtlLinkContent*/ ) + { + FUNC_LOG; + if ( IsMessageBodyURLL(aUrl) ) + { + if ( iMessage ) + { + iView.StartFetchingMessageL(); + } + return ETrue; + } + else + { + if ( NeedToLaunchBrowserL( aUrl ) ) + { + LaunchBrowserL( aUrl ); + return ETrue; + } + else + { + return iEventHandler->HandleEventL( aUrl ); + } + } + } + +// --------------------------------------------------------------------------- +// From MBrCtlLinkResolver. +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::CancelAll() + { + FUNC_LOG; + } + +// --------------------------------------------------------------------------- +// From MBrCtlSoftkeysObserver +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::UpdateSoftkeyL( + TBrCtlKeySoftkey /*aKeySoftkey*/, const TDesC& /*aLabel*/, + TUint32 /*aCommandId*/, + TBrCtlSoftkeyChangeReason /*aBrCtlSoftkeyChangeReason*/ ) + { + FUNC_LOG; + } + +// --------------------------------------------------------------------------- +// Set HTML folder path name +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::SetHtmlFolderPathL() + { + FUNC_LOG; + iHtmlFolderPath.Copy( KCDrive ); + + TFileName privatePath; + User::LeaveIfError( iFs.PrivatePath( privatePath ) ); + iHtmlFolderPath.Append( privatePath ); + + iHtmlFolderPath.Append( KHtmlPath ); + } + +// --------------------------------------------------------------------------- +// Sets temporary HTML folder path name +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::SetTempHtmlFolderPath() + { + FUNC_LOG; + iTempHtmlFolderPath.Copy( iHtmlFolderPath ); + iTempHtmlFolderPath.Append( KTempHtmlPath ); + } + +// --------------------------------------------------------------------------- +// Remove all previously created files from temporary HTML folder +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::EmptyTempHtmlFolderL() + { + FUNC_LOG; + // Delete all files from temp folder + TFileName allFiles; + allFiles.Append( iTempHtmlFolderPath ); + allFiles.Append( KAllFiles ); + TInt err = BaflUtils::DeleteFile( iFs, allFiles ); + if ( err != KErrNotFound && err != KErrNone ) + { + User::LeaveIfError( err ); + } + } + +// --------------------------------------------------------------------------- +// Copies given read-only file to HTML file +// --------------------------------------------------------------------------- +// +// +void CFsEmailUiHtmlViewerContainer::CopyToHtmlFileL( CFSMailMessagePart& aHtmlBodyPart, const TDesC& aFileName ) + { + FUNC_LOG; + TFileName targetFileName; + targetFileName.Copy( iTempHtmlFolderPath ); + targetFileName.Append( aFileName ); + + RFile htmlFile = aHtmlBodyPart.GetContentFileL(); + CleanupClosePushL( htmlFile ); + + // Read content from given source file + HBufC8* content = ReadContentFromFileLC( htmlFile, aHtmlBodyPart ); + + // Write content to target file + WriteContentToFileL( *content, targetFileName, aHtmlBodyPart ); + + CleanupStack::PopAndDestroy( content ); + CleanupStack::PopAndDestroy( &htmlFile ); + } +// + +// --------------------------------------------------------------------------- +// Copies given buffer to HTML file +// --------------------------------------------------------------------------- +// +// +void CFsEmailUiHtmlViewerContainer::ConvertToHtmlFileL( CFSMailMessagePart& aTextBodyPart, const TDesC& aHtmlFileName ) + { + FUNC_LOG; + TFileName targetFileName; + targetFileName.Copy( iTempHtmlFolderPath ); + targetFileName.Append( aHtmlFileName ); + + TInt contentsize = aTextBodyPart.FetchedContentSize(); + + TInt limit(0); + TInt err = iViewerSettings->Repository().Get( KFreestyleMaxBodySize , limit ); + limit *= KKilo; // cenrep value is in kB, 0 means unlimited + + if ( limit == 0 || err ) + { + limit = KMaxTInt; + } + + TInt size = Min(limit,contentsize); + HBufC* content = HBufC::NewLC( size ); + TPtr contentPtr( content->Des() ); + + aTextBodyPart.GetContentToBufferL( contentPtr, 0 ); + //When we found EFSMsgFlag_BodyTruncated was set, add "--Message too long--" in the end of plain html view + if ( limit < contentsize ) + { + // Disable this is PS1 until we have translations available +// HBufC* addingText = StringLoader::LoadLC( R_FREESTYLE_EMAIL_UI_VIEW_ADDITIONAL_INFO , limit/KKilo ); +// TInt pos = contentPtr.Length() - addingText->Length(); +// contentPtr.Replace(pos,addingText->Length(),*addingText); +// CleanupStack::PopAndDestroy( addingText ); + aTextBodyPart.SetFlag(EFSMsgFlag_BodyTruncated); + } + + ConvertToHTML( *content, targetFileName, aTextBodyPart ); + CleanupStack::PopAndDestroy( content ); + } + +// --------------------------------------------------------------------------- +// Reads given file content to buffer and return pointer to it +// --------------------------------------------------------------------------- +// +HBufC8* CFsEmailUiHtmlViewerContainer::ReadContentFromFileLC( RFile& aFile, + CFSMailMessagePart& aBodyPart ) + { + FUNC_LOG; + TInt fileSize = 0; + User::LeaveIfError( aFile.Size( fileSize ) ); + + HBufC* contentType = aBodyPart.GetContentType().AllocLC(); + TInt length = contentType->Locate(';'); + if( length >= 0 ) + { + contentType->Des().SetLength( length ); + } + TBool body = KFSMailContentTypeTextPlain().CompareF( contentType->Des() ) == 0 || + KFSMailContentTypeTextHtml().CompareF( contentType->Des() ) == 0; + CleanupStack::PopAndDestroy( contentType ); + + if ( body ) + { + // limit message size if not done already by plugins + TInt limit(0); + TInt err = iViewerSettings->Repository().Get( KFreestyleMaxBodySize , limit ); + limit *= KKilo; // cenrep value is in kB, 0 means unlimited + + if ( limit == 0 || err ) + { + limit = KMaxTInt; + } + fileSize = Min( limit, fileSize ); // read no more than limit bytes.. + + TInt contentSize = aBodyPart.ContentSize(); + TInt fetchedSize = aBodyPart.FetchedContentSize(); + + if ( ( limit!=KMaxTInt && fileSize < contentSize ) + || ( fetchedSize < contentSize ) ) + { + aBodyPart.SetFlag( EFSMsgFlag_BodyTruncated ); + } + } + HBufC8* buffer = HBufC8::NewLC( fileSize ); + TPtr8 ptr = buffer->Des(); + User::LeaveIfError( aFile.Read( ptr, fileSize ) ); + return buffer; + } + +// --------------------------------------------------------------------------- +// Writes buffer content to given file +// --------------------------------------------------------------------------- +// +// +void CFsEmailUiHtmlViewerContainer::WriteContentToFileL( const TDesC8& aContent, + const TDesC& aFileName, CFSMailMessagePart& aHtmlBodyPart ) + { + FUNC_LOG; + + RBuf8 buffer; + buffer.CreateL( aContent ); + buffer.CleanupClosePushL(); + + if ( SysUtil::DiskSpaceBelowCriticalLevelL( &iFs, buffer.Size(), EDriveC ) ) + { + // Can not write the data, there's not enough free space on disk. + User::Leave( KErrDiskFull ); + } + else + { + RFile targetFile; + CleanupClosePushL( targetFile ); + + User::LeaveIfError( targetFile.Replace( iFs, aFileName, EFileWrite ) ); + + // Try to find initial html tag (both '' tag anywhere in + // the begining of file (KMaxCharsToSearch) AND there is charset + // parameter available + TBool modificationNeeded( EFalse ); + if( startTagOffset == KErrNotFound ) + { + modificationNeeded = ETrue; + } + + // Write starting metadata if needed + if ( modificationNeeded ) + { + HBufC8* charSet = GetCharacterSetL( aHtmlBodyPart ); + CleanupStack::PushL( charSet ); + + User::LeaveIfError( targetFile.Write( KHtmlHeader1 ) ); + User::LeaveIfError( targetFile.Write( *charSet ) ); + User::LeaveIfError( targetFile.Write( KHtmlHeader2 ) ); + CleanupStack::PopAndDestroy( charSet ); + } + else + { + // Charset tag not found in html body + + if ( buffer.Left( KMaxCharsToSearch ).FindF( KCharsetTag8 ) == KErrNotFound ) + { + TInt startPos(0); + if ( ( startPos = buffer.Left( KMaxCharsToSearch ).FindF( KHeadTag ) ) != KErrNotFound ) + { + + HBufC8* charSet = GetCharacterSetL( aHtmlBodyPart ); + CleanupStack::PushL( charSet ); + + HBufC8* metaBuffer = HBufC8::NewLC( charSet->Des().Length() + KHtmlHeader3().Length() ); + TPtr8 metaHeader( metaBuffer->Des() ); + metaHeader.AppendFormat( KHtmlHeader3, charSet ); + TInt maxLength = buffer.Length() + metaHeader.Length(); + buffer.ReAllocL( maxLength ); + + startPos += KHeadTag().Length(); + buffer.Insert( startPos, metaHeader ); + + CleanupStack::PopAndDestroy( metaBuffer ); + CleanupStack::PopAndDestroy( charSet ); + } + } + } + + // Write the original content + User::LeaveIfError( targetFile.Write( buffer ) ); + if( aHtmlBodyPart.GetFlags() & EFSMsgFlag_BodyTruncated ) + { + //When we found EFSMsgFlag_BodyTruncated was set, add "--- Message limited to %N kB ---" in the end of html view + TInt limit(0); + TInt err = iViewerSettings->Repository().Get( KFreestyleMaxBodySize , limit ); + limit *= KKilo; // cenrep value is in kB, 0 means unlimited + if ( limit == 0 || err ) + { + limit = KMaxTInt; + } + +// Disable this is PS1 until we have translations available +// HBufC* addingText = StringLoader::LoadLC( R_FREESTYLE_EMAIL_UI_VIEW_ADDITIONAL_INFO, limit/KKilo ); +// HBufC8* addingText8 = CnvUtfConverter::ConvertFromUnicodeToUtf8L( *addingText ); +// CleanupStack::PopAndDestroy( addingText ); +// CleanupStack::PushL( addingText8 ); +// User::LeaveIfError( targetFile.Write( *addingText8 ) ); +// CleanupStack::PopAndDestroy( addingText8 ); + } + // Write ending metadata if needed + if ( modificationNeeded || (aHtmlBodyPart.GetFlags()&EFSMsgFlag_BodyTruncated) ) + { + INFO("Add end tags"); + User::LeaveIfError( targetFile.Write( KHtmlEndTags ) ); + } + + CleanupStack::PopAndDestroy( &targetFile ); + } + CleanupStack::PopAndDestroy( &buffer ); +// + } + +// --------------------------------------------------------------------------- +// Finds the attachment from the list that matches the given content ID +// --------------------------------------------------------------------------- +// +CFSMailMessagePart* CFsEmailUiHtmlViewerContainer::MatchingAttacmentL( + const TDesC& aContentId, + const RPointerArray& aAttachments ) const + { + FUNC_LOG; + TBool contentFound = EFalse; + CFSMailMessagePart* attachment = NULL; + TInt attachmentCount = aAttachments.Count(); + + // Check whether one of the attachments has the given conten ID + for ( TInt i = 0; i < attachmentCount && !contentFound; i++ ) + { + attachment = aAttachments[i]; + const TDesC& contentId = attachment->ContentID(); + if ( contentId.Compare( aContentId ) == 0 ) + { + contentFound = ETrue; + } + } + + // If attacment with given content ID was not found, check whether + // the given content ID contains the name of one of the attachments + for ( TInt i = 0; i < attachmentCount && !contentFound; ++i ) + { + attachment = aAttachments[i]; + const TDesC& name = attachment->AttachmentNameL(); + if ( aContentId.FindF( name ) >= 0 ) + { + contentFound = ETrue; + } + } + + if ( !contentFound ) + { + attachment = NULL; + } + return attachment; + } + +// --------------------------------------------------------------------------- +// Resolves link referring to file in temporary HTML folder +// --------------------------------------------------------------------------- +// +TBool CFsEmailUiHtmlViewerContainer::ResolveLinkL( const TDesC& aLink, + TBool aContentId, MBrCtlLinkContent& aEmbeddedLinkContent ) + { + FUNC_LOG; + TBool linkResolved = EFalse; + CFSMailMessagePart* attachment = NULL; + + RPointerArray attachments; + CleanupResetAndDestroyClosePushL( attachments ); + iMessage->AttachmentListL( attachments ); + + if ( aContentId ) + { + attachment = MatchingAttacmentL( aLink, attachments ); + } + else + { + const TInt attachmentCount = attachments.Count(); + for ( TInt ii = 0; ii < attachmentCount && !attachment; ++ii ) + { + if ( aLink.CompareF( attachments[ii]->AttachmentNameL() ) == 0 ) + { + attachment = attachments[ii]; + } + } + } + + if ( attachment ) + { + DownloadAttachmentL( *attachment, aEmbeddedLinkContent ); + linkResolved = ETrue; + } + + CleanupStack::PopAndDestroy( &attachments ); + return linkResolved; + } + +// --------------------------------------------------------------------------- +// Download attachment and return the content via MBrCtlLinkContent interface +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::DownloadAttachmentL( + CFSMailMessagePart& aAttachment, MBrCtlLinkContent& aEmbeddedLinkContent ) + { + FUNC_LOG; + if ( aAttachment.FetchLoadState() == EFSFull ) + { + RFile attachmentFile = aAttachment.GetContentFileL(); + CleanupClosePushL( attachmentFile ); + HBufC8* content = ReadContentFromFileLC( attachmentFile, aAttachment ); + aEmbeddedLinkContent.HandleResolveComplete( + aAttachment.GetContentType(), KNullDesC(), content ); + CleanupStack::PopAndDestroy( content ); + CleanupStack::PopAndDestroy( &attachmentFile ); + } + else + { + TPartData partData; + if( iMessage ) + { + partData.iMailBoxId = iMessage->GetMailBoxId(); + partData.iFolderId = iMessage->GetFolderId(); + partData.iMessageId = iMessage->GetMessageId(); + + partData.iMessagePartId = aAttachment.GetPartId(); + + if ( iAppUi.DownloadInfoMediator() && + iAppUi.DownloadInfoMediator()->IsDownloadableL( partData ) ) + { + ASSERT( iLinkContents.Count() == iMessageParts.Count() ); + + // Append message part details and embedded link content interface + // to corresponding arrays so that the content can be returned + // when the download is completed. + iLinkContents.AppendL( &aEmbeddedLinkContent ); + if ( iMessageParts.Append( partData ) != KErrNone ) + { + iLinkContents.Remove( iLinkContents.Count() - 1 ); + } + + ASSERT( iLinkContents.Count() == iMessageParts.Count() ); + if(!iView.GetAsyncFetchStatus()) + { + iAppUi.DownloadInfoMediator()->AddObserver( this, aAttachment.GetMessageId() ); + iObservingDownload=ETrue; + iAppUi.DownloadInfoMediator()->DownloadL( partData, EFalse ); + } + } + } + } + } + +void CFsEmailUiHtmlViewerContainer::SetHTMLResourceFlagFullName() + { + FUNC_LOG; + iHtmlResourceFlagPath.Copy( iHtmlFolderPath ); + iHtmlResourceFlagPath.Append( KHtmlFlagFile ); + } + +void CFsEmailUiHtmlViewerContainer::EnableHTMLResourceFlagL() + { + FUNC_LOG; + RFile flag; + User::LeaveIfError( flag.Replace(iFs, iHtmlResourceFlagPath, EFileWrite) ); + flag.Close(); + } + +TBool CFsEmailUiHtmlViewerContainer::HTMLResourceFlagEnabled() + { + FUNC_LOG; + return BaflUtils::FileExists( iFs, iHtmlResourceFlagPath ); + } + +void CFsEmailUiHtmlViewerContainer::CopyHTMLResourceL() + { + FUNC_LOG; + + TPath htmlFolderPathInZ; + htmlFolderPathInZ.Copy( KZDrive ); + + TFileName privatePath; + User::LeaveIfError( iFs.PrivatePath( privatePath ) ); + htmlFolderPathInZ.Append( privatePath ); + + htmlFolderPathInZ.Append( KHtmlPath ); + + CDir* dirList; + TPath listSpec; + listSpec.Copy( htmlFolderPathInZ ); + + listSpec.Append( _L("*.*") ); + User::LeaveIfError( iFs.GetDir( listSpec, KEntryAttMaskSupported, ESortByName, dirList ) ); + CleanupStack::PushL( dirList ); + for ( TInt i=0; i < dirList->Count(); i++) + { + TPath sourceFileFullName; + sourceFileFullName.Copy( htmlFolderPathInZ ); + sourceFileFullName.Append( (*dirList)[i].iName ); + + TBool isFolder( EFalse ); + BaflUtils::IsFolder( iFs, sourceFileFullName, isFolder); + if ( isFolder ) + { + break; + } + + TPath targetFileFullName; + targetFileFullName.Copy( iHtmlFolderPath ); + targetFileFullName.Append( (*dirList)[i].iName ); + BaflUtils::DeleteFile( iFs, targetFileFullName ); + + BaflUtils::CopyFile( iFs, sourceFileFullName, targetFileFullName); + } + CleanupStack::PopAndDestroy( dirList ); + } + +void CFsEmailUiHtmlViewerContainer::EnsureHTMLResourceL() + { + FUNC_LOG; + + if ( !HTMLResourceFlagEnabled() ) + { + CopyHTMLResourceL(); + EnableHTMLResourceFlagL(); + } + } + +// --------------------------------------------------------------------------- +// Writes buffer content to given file after adding tags +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::ConvertToHTML( const TDesC& aContent, + const TDesC& aFileName, CFSMailMessagePart& /*aTextBodyPart*/ ) + { + FUNC_LOG; + + if ( SysUtil::DiskSpaceBelowCriticalLevelL( &iFs, aContent.Size(), EDriveC ) ) + { + // Can not write the data, there's not enough free space on disk. + User::Leave( KErrDiskFull ); + } + + RBuf htmlText; + CleanupClosePushL( htmlText ); + + PlainTextToHtmlConverter::PlainTextToHtmlL( aContent, htmlText ); + WriteToFileL( aFileName, htmlText ); + + CleanupStack::PopAndDestroy( &htmlText ); + } + + +TInt CFsEmailUiHtmlViewerContainer::TotalLengthOfItems( CFindItemEngine& aItemEngine ) const + { + TInt totalLength( 0 ); + CFindItemEngine::SFoundItem item; + aItemEngine.ResetPosition(); + for ( TBool available( aItemEngine.Item( item ) ); available; available = aItemEngine.NextItem( item ) ) + { + totalLength += item.iLength; + } + aItemEngine.ResetPosition(); + return totalLength; + } + +// --------------------------------------------------------------------------- +// Get Character set from CFSMailMessagePart +// --------------------------------------------------------------------------- +// +// +HBufC8* CFsEmailUiHtmlViewerContainer::GetCharacterSetL( CFSMailMessagePart& aHtmlBodyPart ) + { + FUNC_LOG; + + CDesCArray& contentTypeArray( aHtmlBodyPart.ContentTypeParameters() ); + HBufC8* charSet = KNullDesC8().AllocLC(); + + for ( TInt i = 0; i < contentTypeArray.Count(); i++ ) + { + TPtrC contentEntry( contentTypeArray.MdcaPoint( i ) ); + if ( ( contentEntry.FindF( KCharsetTag ) != KErrNotFound ) && + contentTypeArray.Count() >= ( i+1) ) + { + TPtrC value( contentTypeArray.MdcaPoint( i+1 ) ); + if ( value.Length() ) + { + CleanupStack::PopAndDestroy( charSet ); + charSet = NULL; + charSet = HBufC8::NewLC( value.Length() ); + charSet->Des().Copy( value ); + break; + } + } + i++; + } + + CleanupStack::Pop( charSet ); + return charSet; + } + +void CFsEmailUiHtmlViewerContainer::StopObserving() + { + if( iObservingDownload ) + { + if ( iMessage && iAppUi.DownloadInfoMediator() ) + { + iAppUi.DownloadInfoMediator()->StopObserving( this, iMessage->GetMessageId() ); + } + iObservingDownload=EFalse; + } + } + +void CFsEmailUiHtmlViewerContainer::CancelFetch() + { + FUNC_LOG; + if ( iBrCtlInterface ) + { + TRAP_IGNORE( iBrCtlInterface->HandleCommandL( (TInt)TBrCtlDefs::ECommandCancelFetch + (TInt)TBrCtlDefs::ECommandIdBase )); + } + } + +void CFsEmailUiHtmlViewerContainer::ClearCacheAndLoadEmptyContent() + { + FUNC_LOG; + if ( iBrCtlInterface ) + { + iBrCtlInterface->ClearCache(); + TUid uid; + uid.iUid = KCharacterSetIdentifierUtf8; + TRAP_IGNORE( iBrCtlInterface->LoadDataL(KHTMLDataScheme, KHTMLEmptyContent, _L8("text/html"), uid) ); + } + } + +void CFsEmailUiHtmlViewerContainer::HandleResourceChange( TInt aType ) + { + CCoeControl::HandleResourceChange( aType ); + if ( aType == CFsEmailUiViewBase::EScreenLayoutChanged ) + { + RefreshCurrentMailHeader(); + SetRect( iView.ContainerRect() ); + } + } + +void CFsEmailUiHtmlViewerContainer::RefreshCurrentMailHeader() + { + if ( iMessage ) + { + // Update the width in header part and reload + TPath headerHtmlFile; + headerHtmlFile.Copy( iHtmlFolderPath ); + headerHtmlFile.Append( KHeaderHtmlFile ); + + TRAP_IGNORE( CFreestyleMessageHeaderHTML::ExportL( *iMessage, iFs, + headerHtmlFile, iAppUi.ClientRect().Width(), iScrollPosition, + iViewerSettings->AutoLoadImages() || iAppUi.DisplayImagesCache().Contains(*iMessage), + iFlags ) ) + + + if(!iEventHandler->IsMenuVisible()) + { + TRAP_IGNORE( ReloadPageL() ); + } + else + { + //Load page asynchronously after dismissing menu + //this is outdated call because it cancels Action menu which is no longer used in 9.2 + // iEventHandler->DismissMenuAndReload(); + } + } + } + +void CFsEmailUiHtmlViewerContainer::ReloadPageL() + { + TRAP_IGNORE( iBrCtlInterface->HandleCommandL( ( TInt )TBrCtlDefs::ECommandIdBase + + ( TInt )TBrCtlDefs::ECommandReload ) ); + } + +void CFsEmailUiHtmlViewerContainer::ShowAttachmentDownloadStatusL( + TFSProgress::TFSProgressStatus aProgressStatus, + const TAttachmentData& aAttachmentData ) + { + TBool freshDraw = EFalse; + //If the indicator was displaying fetching body then we will be displaying a different indicator + //this is just to make sure the image is updated + if(iStatusIndicator) + { + if (iStatusIndicator->Image()) + { + if(iStatusIndicator->Image()->Handle() != iAttachmentDownloadImageHandle) + { + freshDraw = ETrue; + } + } + } + if ( !iStatusIndicator ) + { + TRect rect = CalcAttachmentStatusRect(); + iStatusIndicator = CFreestyleEmailUiAknStatusIndicator::NewL( rect, this ); + freshDraw = ETrue; + } + + if ( !iStatusIndicator->IsVisible() + || ( aAttachmentData.downloadProgress == KNone ) + || ( aProgressStatus == TFSProgress::EFSStatus_RequestCancelled ) ) + { + freshDraw = ETrue; + } + + TInt duration = KStatusIndicatorDefaultDuration; + if ( ( aAttachmentData.downloadProgress == TFSProgress::EFSStatus_RequestComplete ) + || ( aProgressStatus == TFSProgress::EFSStatus_RequestCancelled ) + || ( aAttachmentData.downloadProgress == KComplete ) ) + { + duration = KStatusIndicatorAutomaticHidingDuration; + } + + HBufC* statusText = NULL; + switch ( aProgressStatus ) + { + case TFSProgress::EFSStatus_Status: + case TFSProgress::EFSStatus_RequestComplete: + { + CDesCArray* descArray = new (ELeave) CDesCArrayFlat( 1 ); + CleanupStack::PushL( descArray ); + descArray->AppendL( aAttachmentData.fileName ); + CArrayFix* intArray = new (ELeave) CArrayFixFlat( 1 ); + CleanupStack::PushL( intArray ); + intArray->AppendL( aAttachmentData.downloadProgress ); + + statusText = StringLoader::LoadL( R_FSE_VIEWER_ATTACHMENTS_LIST_DOWNLOAD, + *descArray, + *intArray ); + CleanupStack::PopAndDestroy( intArray ); + CleanupStack::PopAndDestroy( descArray ); + CleanupStack::PushL( statusText ); + } + break; + + case TFSProgress::EFSStatus_RequestCancelled: + { + statusText = aAttachmentData.fileName.AllocLC(); + } + break; + + default: + statusText = KNullDesC().AllocLC(); + break; + } + + if ( statusText->Length() > 0 ) + { + if ( freshDraw ) + { + CFbsBitmap* image = NULL; + CFbsBitmap* imageMask = NULL; + if ( aProgressStatus == TFSProgress::EFSStatus_RequestCancelled ) + { + iAppUi.FsTextureManager()->ProvideBitmapL(EAttachmentsCancelDownload, image, imageMask ); + } + else + { + iAppUi.FsTextureManager()->ProvideBitmapL(EAttachmentsDownload, image, imageMask ); + } + if(image) + { + iAttachmentDownloadImageHandle = image->Handle(); + } + iStatusIndicator->ShowIndicatorL( image, imageMask, statusText, duration ); + } + else + { + iStatusIndicator->SetTextL( statusText ); + if ( duration > -1 ) + { + iStatusIndicator->HideIndicator( duration ); + } + } + } + + CleanupStack::Pop( statusText ); + } + +TBool CFsEmailUiHtmlViewerContainer::AttachmentDownloadStatusVisible() + { + if ( iStatusIndicator ) + { + return iStatusIndicator->IsVisible(); + } + else + { + return EFalse; + } + } +void CFsEmailUiHtmlViewerContainer::ViewerSettingsChangedL( const TUint32 aKey ) + { + FUNC_LOG; + if (aKey == KFreestyleEmailDownloadHTMLImages) + { + if (iBrCtlInterface) + { + iBrCtlInterface->SetBrowserSettingL( + TBrCtlDefs::ESettingsAutoLoadImages, + iViewerSettings->AutoLoadImages() ); + if (iViewerSettings->AutoLoadImages() && iMessage) + { + LoadContentFromMailMessageL(iMessage, EFalse); + } + } + } + } + +void CFsEmailUiHtmlViewerContainer::HideDownloadStatus() + { + if ( iStatusIndicator ) + { + iStatusIndicator->MakeVisible( EFalse ); + } + } + +TRect CFsEmailUiHtmlViewerContainer::CalcAttachmentStatusRect() + { + TRect rect( Rect() ); + TPoint topLeft = rect.iTl; + TPoint bottomRight = rect.iBr; + TPoint statusTopLeft( topLeft.iX + KStatusIndicatorXMargin, bottomRight.iY - KStatusIndicatorHeight + 1 ); + TPoint statusBottomRight( bottomRight.iX - KStatusIndicatorXMargin, bottomRight.iY ); + rect = TRect(statusTopLeft, statusBottomRight); + rect.Move(0, -KStatusIndicatorBottomMargin); + return rect; + } + +void CFsEmailUiHtmlViewerContainer::TouchFeedback() + { + iTouchFeedBack->InstantFeedback(this, ETouchFeedbackBasic); + } + +/** + * The body fetch link is cmail://body/fetch. Look for the URL separator + * and the presence of cmail and body on the url. + * @param aUrl + * return ETrue for a valid body URL + */ +TBool CFsEmailUiHtmlViewerContainer::IsMessageBodyURLL(const TDesC& aUrl) + { + TInt index = aUrl.Find(KURLSchemeSeparator); + if (index == KErrNotFound) + { + return EFalse; + } + else + { + if (aUrl.Compare(KURLLoadImages()) == 0) + { + iBrCtlInterface->HandleCommandL(TBrCtlDefs::ECommandLoadImages + TBrCtlDefs::ECommandIdBase); + return ETrue; + } + else if (aUrl.Compare(KURLDisplayImages()) == 0) + { + DisplayStatusIndicatorL(KStatusIndicatorAutomaticHidingDuration); + if( iMessage ) + { + iAppUi.DisplayImagesCache().AddMessageL(*iMessage); + } + iBrCtlInterface->HandleCommandL(TBrCtlDefs::ECommandLoadImages + TBrCtlDefs::ECommandIdBase); + return ETrue; + } + else if (aUrl.Compare(KURLCollapseHeader()) == 0) + { + TouchFeedback(); + iFlags.ClearAll(); + return ETrue; + } + else if (aUrl.Compare(KURLExpandHeader()) == 0) + { + TouchFeedback(); + iFlags.Set( CFreestyleMessageHeaderHTML::EHeaderExpanded ); + return ETrue; + } + else if ( aUrl.Find( KURLExpandItem() ) == 0 ) { + const TPtrC item( aUrl.Mid( KURLExpandItem().Length() ) ); + if ( item.Find( KURLItemTo() ) == 0 ) + { + iFlags.Assign( CFreestyleMessageHeaderHTML::EToExpanded, ETrue ); + } + else if ( item.Find( KURLItemCc() ) == 0 ) + { + iFlags.Assign( CFreestyleMessageHeaderHTML::ECcExpanded, ETrue ); + } + else if ( item.Find( KURLItemBcc() ) == 0 ) + { + iFlags.Assign( CFreestyleMessageHeaderHTML::EBccExpanded, ETrue ); + } + else if ( item.Find( KURLItemAttachments() ) == 0 ) + { + iFlags.Assign( CFreestyleMessageHeaderHTML::EAttachmentExpanded, ETrue ); + } + return ETrue; + } else if (aUrl.Left(index).CompareF(KURLSchemeCmail) == 0) + { + TInt bodyIndex = aUrl.Find(KURLTypeBody); + if (bodyIndex == KErrNotFound) + { + return EFalse; + } + else + { + TPtrC16 data= aUrl.Mid(bodyIndex); + TInt separator = data.Find(KURLSlash); + if(separator == KErrNotFound) + { + return EFalse; + } + else + { + TPtrC16 temp = data.Mid(separator+1); + TLex lex(temp); + lex.Val(iScrollPosition); + } + return ETrue; + } + + } + else + { + return EFalse; + } + } + } + +// --------------------------------------------------------------------------- +// From MBrCtlWindowObserver +// --------------------------------------------------------------------------- +// +CBrCtlInterface* CFsEmailUiHtmlViewerContainer::OpenWindowL( TDesC& /*aUrl*/, TDesC* /*aTargetName*/, + TBool /*aUserInitiated*/, TAny* /*aReserved*/ ) + { + return iBrCtlInterface; + } + +// --------------------------------------------------------------------------- +// From MBrCtlWindowObserver +// --------------------------------------------------------------------------- +// +CBrCtlInterface* CFsEmailUiHtmlViewerContainer::FindWindowL( const TDesC& /*aTargetName*/ ) const + { + return NULL; + } + +// --------------------------------------------------------------------------- +// From MBrCtlWindowObserver +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::HandleWindowCommandL( const TDesC& /*aTargetName*/, + TBrCtlWindowCommand /*aCommand*/ ) + { + + } + +// --------------------------------------------------------------------------- +// Check if a tap on the URL requires browser(standalone) to be launched +// --------------------------------------------------------------------------- +// +TBool CFsEmailUiHtmlViewerContainer::NeedToLaunchBrowserL( const TDesC& aUrl ) + { + TBool launchBrowser( ETrue ); + // look for file:/// + _LIT( KFileLink, "file:///"); + _LIT( KUrlLink, "http"); + + // This might be linking to header.html or body.html frames + // Ignore them. + if ( aUrl.Left( KFileLink().Length() ).CompareF( KFileLink ) == 0 ) + { + //Now there is a chance that this could be from HTML folder + // Replace all slash character with backslash characters + HBufC* embeddedUrl = aUrl.AllocLC(); + TPtr ptr = embeddedUrl->Des(); + + _LIT( KBackslash, "\\" ); + for ( TInt pos = ptr.Locate('/'); pos >= 0; pos = ptr.Locate('/') ) + { + ptr.Replace( pos, 1, KBackslash ); + } + + // Check whether given url refers to file in the html folder + TInt pos = embeddedUrl->FindF( iHtmlFolderPath ); + CleanupStack::PopAndDestroy( embeddedUrl ); + pos >= 0 ? launchBrowser = EFalse : ETrue; + } + // Ignore links starting with cmail:// + else if ( aUrl.Left( KURLSchemeCmail().Length() ).CompareF( KURLSchemeCmail ) == 0 ) + { + launchBrowser = EFalse; + } + // THAA-82BEAZ - show popup first + else if ( aUrl.Left(KUrlLink().Length() ).CompareF( KUrlLink ) == 0 ) + { + launchBrowser = EFalse; + } + // end THAA-82BEAZ + + return launchBrowser; + } + +// --------------------------------------------------------------------------- +// Launch the browser as a standalone app +// --------------------------------------------------------------------------- +// +void CFsEmailUiHtmlViewerContainer::LaunchBrowserL( const TDesC& aUrl ) + { + CSchemeHandler* handler = CSchemeHandler::NewL( aUrl ); + CleanupStack::PushL( handler ); + handler->HandleUrlStandaloneL(); + CleanupStack::PopAndDestroy( handler ); + } + +void CFsEmailUiHtmlViewerContainer::PrepareBodyHtmlL( const TDesC& aFileName ) + { + + if( iMessage ) + { + CFSMailMessagePart* htmlBodyPart = iMessage->HtmlBodyPartL(); + + if ( htmlBodyPart ) + { + CleanupStack::PushL( htmlBodyPart ); + // Copy html body part to email html file + CopyToHtmlFileL( *htmlBodyPart, aFileName ); + CleanupStack::PopAndDestroy( htmlBodyPart ); + } + else + { + CFSMailMessagePart* textBodyPart = iMessage->PlainTextBodyPartL(); + + if ( textBodyPart ) + { + CleanupStack::PushL( textBodyPart ); + // Copy html body part to email html file + ConvertToHtmlFileL( *textBodyPart, aFileName ); + CleanupStack::PopAndDestroy( textBodyPart ); + } + else + { + User::Leave( KErrNotFound ); + } + } + } + } + +void CFsEmailUiHtmlViewerContainer::WriteEmptyBodyHtmlL( const TDesC& aFileName ) + { + FUNC_LOG; + TFileName targetFileName; + targetFileName.Copy( iTempHtmlFolderPath ); + targetFileName.Append( aFileName ); + + RFile targetFile; + CleanupClosePushL( targetFile ); + User::LeaveIfError( targetFile.Replace( iFs, targetFileName, EFileWrite ) ); + User::LeaveIfError( targetFile.Write( KHTMLEmptyContent ) ); + CleanupStack::PopAndDestroy( &targetFile ); + } + +void CFsEmailUiHtmlViewerContainer::DisplayStatusIndicatorL(TInt aDuration) + { + FUNC_LOG; + TRect rect = CalcAttachmentStatusRect(); + if(!iStatusIndicator) + { + iStatusIndicator = CFreestyleEmailUiAknStatusIndicator::NewL( rect, this ); + } + CFbsBitmap* image = NULL; + CFbsBitmap* imageMask = NULL; + HBufC* statusText = NULL; + statusText = StringLoader::LoadL(R_FREESTYLE_EMAIL_UI_VIEWER_FETCHING_CONTENT_TEXT); + iAppUi.FsTextureManager()->ProvideBitmapL(EStatusTextureSynchronising, image, imageMask ); + iStatusIndicator->ShowIndicatorL( image, imageMask, statusText, aDuration, ETrue ); + } + +void CFsEmailUiHtmlViewerContainer::MailListModelUpdatedL() + { + FUNC_LOG; + UpdateOverlayButtons( IsVisible() ); + } + + +void CFsEmailUiHtmlViewerContainer::WriteToFileL(const TDesC& aFileName, RBuf& aHtmlText) + { + _LIT( KCharsetUtf8, "UTF-8" ); + + HBufC8* content8 = CnvUtfConverter::ConvertFromUnicodeToUtf8L( aHtmlText ); + CleanupStack::PushL( content8 ); + + RFile targetFile; + CleanupClosePushL( targetFile ); + User::LeaveIfError( targetFile.Replace( iFs, aFileName, EFileWrite ) ); + + RBuf8 messageHeader; + TInt bufSize = KHtmlHeader1().Length() + KCharsetUtf8().Length() + KHtmlHeader2().Length(); + messageHeader.CreateL( bufSize ); + messageHeader.CleanupClosePushL(); + + messageHeader.Append( KHtmlHeader1 ); + messageHeader.Append( KCharsetUtf8 ); + messageHeader.Append( KHtmlHeader2 ); + + RFileWriteStream fileStream( targetFile ); + fileStream.PushL(); + fileStream.WriteL( messageHeader.Ptr(), messageHeader.Length() ); + + TInt bufPos( 0 ); + TInt bufTotalSize = content8->Size(); + + while ( bufPos < bufTotalSize ) + { + TInt segmentLength = content8->Mid( bufPos ).Length(); + fileStream.WriteL( content8->Mid( bufPos ).Ptr(), segmentLength ); + bufPos += segmentLength; + } + + fileStream.CommitL(); + + CleanupStack::PopAndDestroy( &fileStream ); + CleanupStack::PopAndDestroy( &messageHeader ); + CleanupStack::PopAndDestroy( &targetFile ); + CleanupStack::PopAndDestroy( content8 ); + } + + + +/****************************************************************************** + * class PlainTextToHtmlConverter + ******************************************************************************/ + + + +// ----------------------------------------------------------------------------- +// PlainTextToHtmlConverter::PlainTextToHtmlL +// +// ----------------------------------------------------------------------------- +// +void PlainTextToHtmlConverter::PlainTextToHtmlL(const TDesC& aPlainText, RBuf& aHtmlText) + { + const TInt KAllocSize = 1024; + + aHtmlText.Close(); + aHtmlText.Create( aPlainText.Length() + KAllocSize ); + + const TInt searhCases( CFindItemEngine::EFindItemSearchURLBin ); + CFindItemEngine* itemEngine = CFindItemEngine::NewL( aPlainText, CFindItemEngine::TFindItemSearchCase( searhCases ) ); + CleanupStack::PushL ( itemEngine ); + + TInt currentPos = 0; + CFindItemEngine::SFoundItem item; + for ( TBool available(itemEngine->Item(item)); available; available=itemEngine->NextItem(item) ) + { + if ( item.iStartPos < currentPos ) + { + break; + } + + TPtrC textPtr = aPlainText.Mid( currentPos, item.iStartPos-currentPos ); + ConvertTextL( textPtr, aHtmlText ); + + TPtrC urlPtr = aPlainText.Mid( item.iStartPos, item.iLength ); + ConvertUrlL( urlPtr, aHtmlText); + + currentPos = item.iStartPos + item.iLength; + } + + TInt len = aPlainText.Length(); + if ( currentPos < len ) + { + TPtrC textPtr = aPlainText.Mid( currentPos ); + ConvertTextL( textPtr, aHtmlText ); + } + + CleanupStack::PopAndDestroy( itemEngine ); + } + + +// ----------------------------------------------------------------------------- +// PlainTextToHtmlConverter::ConvertTextL +// +// ----------------------------------------------------------------------------- +// +void PlainTextToHtmlConverter::ConvertTextL(const TDesC& aSource, RBuf& aTarget) + { + const TInt KAllocSize = 1024; + const TInt KEntitySize = 32; + + TInt count = aSource.Length(); + for ( TInt i=0; i= aTarget.MaxLength() ) + { + aTarget.ReAllocL( aTarget.MaxLength() + KAllocSize ); + } + + TText ch = aSource[i]; + switch( ch ) + { + case KSOH: // end of line for IMAP and POP + aTarget.Append( KHtmlLineBreakCRLF ); + break; + case KLF: // line feed + case KUnicodeNewLineCharacter: + case KUnicodeParagraphCharacter: + aTarget.Append(KHtmlLineBreak); + break; + case KQuotation: + aTarget.Append( KHtmlQuotation ); + break; + case KAmpersand: + aTarget.Append( KHtmlAmpersand ); + break; + case KGreaterThan: + aTarget.Append( KHtmlGreaterThan ); + break; + case KLessThan: + aTarget.Append( KHtmlLessThan ); + break; + default: + aTarget.Append( ch ); + break; + } + } + } + + +// ----------------------------------------------------------------------------- +// PlainTextToHtmlConverter::ConvertUrlL +// +// ----------------------------------------------------------------------------- +// +void PlainTextToHtmlConverter::ConvertUrlL(const TDesC& aSource, RBuf& aTarget) + { + _LIT( KSchemeDelimiter, "://" ); + _LIT( KUrlFormat, "%S" ); + _LIT( KUrlFormatWithHttp, "%S" ); + + TPtrC format( KUrlFormat() ); + if ( aSource.FindF( KSchemeDelimiter() ) == KErrNotFound ) + { + format.Set( KUrlFormatWithHttp() ); + } + + HBufC* formatBuffer = HBufC::NewLC( format.Length() + aSource.Length() * 2 ); + formatBuffer->Des().Format( format, &aSource, &aSource ); + + TInt len = formatBuffer->Des().Length(); + if ( aTarget.Length() + len >= aTarget.MaxLength() ) + { + aTarget.ReAllocL( aTarget.MaxLength() + len ); + } + + aTarget.Append( *formatBuffer ); + + CleanupStack::PopAndDestroy( formatBuffer ); + }