/*
* 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 <AknsDrawUtils.h>
#include <coemain.h>
#include <commdbconnpref.h>
#include <bautils.h>
#include <biditext.h>
#include <StringLoader.h>
#include <e32base.h>
#include <badesca.h>
#include <utf.h>
#include <finditemengine.h>
//<cmail>
#include "cfsmailmessage.h"
//</cmail>
#include <brctlinterface.h>
#include <sysutil.h>
#include <schemehandler.h>
#include <FreestyleEmailUi.rsg>
#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, "<html" );
_LIT8( KHeadTag, "<head>");
_LIT8( KHtmlHeader1, "<html><head><title></title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=");
_LIT8( KHtmlHeader2, "\"/></head><body bgcolor=\"#ECECEC\">\xD\xA");
_LIT8( KHtmlHeader3, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%S\">\n");
_LIT8( KHtmlEndTags, "\xD\xA</body></html>\xD\xA");
_LIT8( KCharsetTag8, "charset");
_LIT( KCharsetTag, "charset");
_LIT8( KHTMLEmptyContent, "<html><body></body></html>");
_LIT( KHTMLDataScheme, "data:0");
_LIT( KHtmlLineBreak, "<br>" );
_LIT( KHtmlLineBreakCRLF, "<br>\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<TUint>* 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<TUint>* 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<CFsEmailUiHtmlViewerContainer*>( 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<TInt>(&iConnection);
*aSockSvrHandle = iSocketServer.Handle();
}
// ---------------------------------------------------------------------------
// From MBrCtlSpecialLoadObserver.
// ---------------------------------------------------------------------------
//
TBool CFsEmailUiHtmlViewerContainer::HandleRequestL(
RArray<TUint>* /*aTypeArray*/, CDesCArrayFlat* /*aDesArray*/ )
{
FUNC_LOG;
// Let browser control handle these
return EFalse;
}
// ---------------------------------------------------------------------------
// From MBrCtlSpecialLoadObserver.
// ---------------------------------------------------------------------------
//
TBool CFsEmailUiHtmlViewerContainer::HandleDownloadL(
RArray<TUint>* /*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
// ---------------------------------------------------------------------------
//
// <cmail>
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 );
}
// </cmail>
// ---------------------------------------------------------------------------
// Copies given buffer to HTML file
// ---------------------------------------------------------------------------
//
// <cmail>
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
// ---------------------------------------------------------------------------
//
// <cmail>
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 '<html' and '<HTML' versions are searched)
TInt startTagOffset = buffer.Left( KMaxCharsToSearch ).FindF( KStartTag );
// Modifying text/html atta IF there's no '<html>' 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 );
// </cmail>
}
// ---------------------------------------------------------------------------
// Finds the attachment from the list that matches the given content ID
// ---------------------------------------------------------------------------
//
CFSMailMessagePart* CFsEmailUiHtmlViewerContainer::MatchingAttacmentL(
const TDesC& aContentId,
const RPointerArray<CFSMailMessagePart>& 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<CFSMailMessagePart> 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
// ---------------------------------------------------------------------------
//
// <cmail>
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<TInt>* intArray = new (ELeave) CArrayFixFlat<TInt>( 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<count; i++ )
{
if ( aTarget.Length() + KEntitySize >= 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, "<a href=\"%S\">%S</a>" );
_LIT( KUrlFormatWithHttp, "<a href=\"http://%S\">%S</a>" );
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 );
}