httpfilters/uaproffilter/src/uaproffilter.cpp
changeset 0 b16258d2340f
child 6 fa2fd8b2d6cc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/httpfilters/uaproffilter/src/uaproffilter.cpp	Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,671 @@
+/*
+* Copyright (c) 2003 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:  Implementation of class CHttpUAProfFilter.
+*
+*
+*/
+
+
+// INCLUDE FILES
+
+#include "uaproffilter.h"
+
+#include <e32std.h>
+#include <etelmm.h>
+#include <mmtsy_names.h>
+
+#include <http/rhttptransaction.h>
+#include <http/rhttpconnectioninfo.h>
+#include <http/rhttpheaders.h>
+#include <httperr.h>
+
+#include <BrowserUiSDKCRKeys.h>
+#include <webutilsinternalcrkeys.h>//for the profile strings
+
+#include <cuseragent.h>
+#include <featmgr.h>
+#include <bldvariant.hrh>
+
+
+// Token for IMEI/SN code in UA-header.
+_LIT8( KImeiSnToken, "SN" );
+_LIT8( KSlash, "/" );
+
+// Space character.
+LOCAL_D const TUint8 KSpaceChar = ' ';
+
+// MACROS
+
+/// OOM test helper.
+//#define __TEST_OOM_IN_INSTALL
+/// OOM test helper.
+//#define __TEST_OOM_IN_MHFRUNL
+
+// CONSTANTS
+
+/// Initial buffer size for reading from Shared Data.
+LOCAL_D const TInt KSdReadBufSize = 128;
+/// profile
+_LIT8( KProfile, "profile" );
+/// x-wap-profile
+_LIT8( KXWapProfile, "x-wap-profile" );
+#if defined( _DEBUG )
+/// Panic name for UAProf Filter.
+_LIT( KUAProfFilter, "UAProfFilter" );
+#endif
+/// Length for imei code.
+LOCAL_D const TInt KImeiLength = 15;
+
+
+#if defined( __WINS__ )
+/// Dummy IMEI value for WINS emulator.
+_LIT( KEmulatorImei, "123456789012345" );
+#endif
+
+// ================= MEMBER FUNCTIONS ==========================================
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::InstallFilterL()
+// -----------------------------------------------------------------------------
+//
+CHttpUAProfFilterInterface* CHttpUAProfFilter::InstallFilterL( TAny* aSession )
+    {
+#ifdef __TEST_OOM_IN_INSTALL
+    __UHEAP_SETFAIL( RHeap::ETrueRandom, 40 );
+#endif /* def __TEST_OOM_IN_INSTALL */
+
+    __ASSERT_DEBUG( aSession, User::Panic( KUAProfFilter, KErrArgument ) );
+    RHTTPSession* session = REINTERPRET_CAST( RHTTPSession*, aSession );
+    CHttpUAProfFilter* filter = new (ELeave) CHttpUAProfFilter( *session );
+    CleanupStack::PushL( filter );
+    filter->ConstructL();
+    CleanupStack::Pop( filter );
+    return filter;
+
+#ifdef __TEST_OOM_IN_INSTALL
+    __UHEAP_SETFAIL( RHeap::ENone, 1 );
+#endif /* def __TEST_OOM_IN_INSTALL */
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::~CHttpUAProfFilter()
+// -----------------------------------------------------------------------------
+//
+CHttpUAProfFilter::~CHttpUAProfFilter()
+    {
+    // If we've been destroyed from the cleanup stack during creation
+    // of the object, it might still be loaded. So check. (Normally the
+    // delete is initiated by the 'delete this' in MHFUnload)
+    if( iLoadCount > 0)
+        {
+        // As we're already in a destructor, MHFUnload must not delete us
+        // again. So -1 value is set.
+        iLoadCount = -1;
+        iSession.FilterCollection().RemoveFilter( StringF( HTTP::EUserAgent ) );
+        }
+    // Make sure we don't close an unopened RStringF
+    if( iUaProf3GOpen )
+        {
+        iUaProf3G.Close();
+        }
+    if( iUaProfOpen )
+        {
+        iUaProf.Close();
+        }
+    if( iUaNameOpen )
+        {
+        iUaName.Close();
+        }
+    if ( iUaNameWithImeiOpen )
+        {
+        iUaNameWithImei.Close();
+        }
+    if( iUaNameMmsOpen )
+        {
+        iUaNameMms.Close();
+        }
+    if ( iUaNameMmsWithImeiOpen )
+        {
+        iUaNameMmsWithImei.Close();
+        }
+    iMobilePhone.Close();
+    iTelServer.Close();
+
+    if ( iNotifyHandler )
+    	{
+    	iNotifyHandler->StopListening();	
+    	}
+    delete iRepositoryBrowser;
+    delete iRepositoryCommonEngine;
+    delete iNotifyHandler;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::MHFRunL()
+// -----------------------------------------------------------------------------
+//
+void CHttpUAProfFilter::MHFRunL
+( RHTTPTransaction aTransaction, const THTTPEvent& aEvent )
+    {
+#ifdef __TEST_OOM_IN_MHFRUNL
+    __UHEAP_SETFAIL( RHeap::ETrueRandom, 30 );
+#endif /* def __TEST_OOM_IN_MHFRUNL */
+
+    switch( aEvent.iStatus )
+        {
+        case THTTPEvent::ESubmit:
+            {
+            SubmitL( aTransaction );
+            break;
+            }
+
+        default:
+            {
+            break;
+            }
+        }
+
+#ifdef __TEST_OOM_IN_MHFRUNL
+    __UHEAP_SETFAIL( RHeap::ENone, 1 );
+#endif /* def __TEST_OOM_IN_MHFRUNL */
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::MHFRunError()
+// -----------------------------------------------------------------------------
+//
+TInt CHttpUAProfFilter::MHFRunError
+( TInt /*aError*/, RHTTPTransaction aTransaction, const THTTPEvent& /*aEvent*/ )
+    {
+    aTransaction.Fail();
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::MHFSessionRunL()
+// -----------------------------------------------------------------------------
+//
+void CHttpUAProfFilter::MHFSessionRunL( const THTTPSessionEvent& /*aEvent*/ )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::MHFSessionRunError()
+// -----------------------------------------------------------------------------
+//
+TInt CHttpUAProfFilter::MHFSessionRunError
+( TInt aError, const THTTPSessionEvent& /*aEvent*/ )
+    {
+    return aError;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::MHFUnload()
+// -----------------------------------------------------------------------------
+//
+void CHttpUAProfFilter::MHFUnload( RHTTPSession /*aSession*/, 
+                                   THTTPFilterHandle /*aHandle*/ )
+    {
+    // We must be only registered on one session, as we register in our
+    // ConstructL and no-one else has a pointer to us. Therefore, we
+    // know we can be deleted at this point.
+    if( --iLoadCount == 0 )
+        {
+        delete this;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::MHFLoad()
+// -----------------------------------------------------------------------------
+//
+void CHttpUAProfFilter::MHFLoad
+( RHTTPSession /*aSession*/, THTTPFilterHandle /*aHandle*/ )
+    {
+    ++iLoadCount;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::HandleNotifyInt()
+// -----------------------------------------------------------------------------
+//
+void CHttpUAProfFilter::HandleNotifyInt(TUint32 aId, TInt aValue)
+    {
+    if ( aId == KBrowserIMEINotification )
+        {
+        TInt imeiSendingOn = aValue;
+        iImeiSendingOn = (imeiSendingOn != 0);
+        }
+    #ifdef _DEBUG
+        else
+            {
+            // This notification was not requested.
+            User::Panic( KUAProfFilter, KErrGeneral );
+            }
+    #endif
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::CHttpUAProfFilter()
+// -----------------------------------------------------------------------------
+//
+CHttpUAProfFilter::CHttpUAProfFilter( RHTTPSession aSession )
+: iUaProfOpen( EFalse ),
+  iUaProf3GOpen( EFalse ),
+  iUaNameOpen( EFalse ),
+  iUaNameWithImeiOpen( EFalse ),
+  iUaNameMmsOpen( EFalse ),
+  iUaNameMmsWithImeiOpen( EFalse ),
+  iSession( aSession ),
+  iStringPool( aSession.StringPool() ),
+  iStringTable( RHTTPSession::GetTable() ),
+  iImeiFeatureEnabled( EFalse ),
+  iImeiSendingOn( EFalse )
+    { 
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::ConstructL()
+// -----------------------------------------------------------------------------
+//
+void CHttpUAProfFilter::ConstructL()
+    {
+
+    //iRepositoryCommonEngine object will be created in OpenProfileString()
+    //iRepositoryBrowser object will be SetupImeiNotifyL()
+
+    // This filter is opened only on one session, so it is safe to pre-open
+    // the strings we are going to use.
+
+    // UAProf string.
+    OpenProfileStringsL();  // Uses iSdCli.
+
+    // If 2G/3G distinction is supported, prepare querying the network type.
+    // If no such distinction is made, we don't need RMobilePhone at all.
+    if ( iUaProf3GOpen )
+        {
+        User::LeaveIfError( iTelServer.Connect() );
+        User::LeaveIfError( iTelServer.LoadPhoneModule( KMmTsyModuleName ) );
+        TInt numPhones;
+        User::LeaveIfError( iTelServer.EnumeratePhones( numPhones ) );
+        if( numPhones <= 0 )
+            {
+            // Huh???
+            User::Leave( KErrCorrupt );
+            }
+        RTelServer::TPhoneInfo phoneInfo;
+        User::LeaveIfError( iTelServer.GetPhoneInfo( 0, phoneInfo ) );
+        User::LeaveIfError( iMobilePhone.Open( iTelServer, phoneInfo.iName ) );
+        User::LeaveIfError( iMobilePhone.Initialise() );
+        }
+
+    // Setup IMEI-notify stuff, ignore any errors.
+    // Expected error: Browser's INI file may not be present.
+    TRAP_IGNORE( SetupImeiNotifyL() );
+
+    // User Agent name string.
+    OpenUserAgentNameStringsL();
+
+    // Register filter.
+    iSession.FilterCollection().AddFilterL
+        (
+        *this,
+        THTTPEvent( THTTPEvent::ESubmit ),  // submit event
+        MHTTPFilter::ETidyUp,               // priority
+        StringF( HTTP::EUserAgent )         // name
+        );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::SetupImeiNotifyL()
+// -----------------------------------------------------------------------------
+//
+void CHttpUAProfFilter::SetupImeiNotifyL()
+    {
+    // First check if this feature is enabled.
+    FeatureManager::InitializeLibL();   // Warning: no leaving...
+    iImeiFeatureEnabled = 
+        FeatureManager::FeatureSupported( KFeatureIdBrowserIMEINotification );
+    FeatureManager::UnInitializeLib();  // ... until this point!
+
+    // If feature is enabled, query value and register for notification.
+    if ( iImeiFeatureEnabled )
+        {
+        TInt imeiSendingOn( 0 );
+
+        CRepository* iRepositoryBrowser = CRepository::NewL( KCRUidBrowser );
+        iRepositoryBrowser->Get(  KBrowserIMEINotification, imeiSendingOn );
+        iImeiSendingOn = (imeiSendingOn != 0);
+        iNotifyHandler = CCenRepNotifyHandler::NewL(*this, 
+                                                 *iRepositoryBrowser, 
+                                                 CCenRepNotifyHandler::EIntKey, 
+                                                 KBrowserIMEINotification);
+        iNotifyHandler->StartListeningL();
+        }
+
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::SubmitL()
+// -----------------------------------------------------------------------------
+//
+void CHttpUAProfFilter::SubmitL( RHTTPTransaction aTransaction )
+    {
+    RHTTPHeaders headers( aTransaction.Request().GetHeaderCollection() );
+    
+    // User-Agent: protocol independent header.
+
+    // First check if client is MMS.
+    TBool uaMms( EFalse );
+    RStringF uaClient = iStringPool.OpenFStringL( KUserAgentClientId );
+    CleanupClosePushL<RStringF>( uaClient );
+    THTTPHdrVal val;
+    if ( aTransaction.PropertySet().Property( uaClient, val ) &&
+         val.Type() == THTTPHdrVal::KTIntVal &&
+         val.Int() == KUserAgentCliMMS )
+        {
+        uaMms = ETrue;
+        }
+    CleanupStack::PopAndDestroy();  // Close uaClient.
+
+    // If IMEI-notify is on (implies that feature is supported), use that.
+    RStringF hdrVal;
+    if ( uaMms )
+        {
+        hdrVal = iImeiSendingOn ? iUaNameMmsWithImei : iUaNameMms;
+        }
+    else
+        {
+        hdrVal = iImeiSendingOn ? iUaNameWithImei : iUaName;
+        }
+    AddOrReplaceHeaderL( headers, StringF( HTTP::EUserAgent ), hdrVal );
+
+    // UAProf: protocol dependent.
+    RStringF xProfile;
+    THTTPHdrVal protocol;
+    TBool protocolExists = iSession.ConnectionInfo().Property
+        ( StringF( HTTP::EProtocol ), protocol );
+    if( protocolExists &&
+        protocol.Type() == THTTPHdrVal::KStrFVal &&
+        protocol.StrF() == StringF( HTTP::EWSP ) )
+        {
+        // It's WSP - set "Profile".
+        xProfile = iStringPool.OpenFStringL( KProfile );
+        }
+    else
+        {
+        // It's HTTP - set "x-wap-profile".
+        xProfile = iStringPool.OpenFStringL( KXWapProfile );
+        }
+    CleanupClosePushL<RStringF>( xProfile );
+    // Use 3G profile if:
+    // - we have such (i.e. feature is supported); and
+    // - network is 3G.
+    hdrVal = (iUaProf3GOpen && Is3gNetworkL()) ? iUaProf3G : iUaProf;
+    AddOrReplaceHeaderL( headers, xProfile, hdrVal );
+    CleanupStack::PopAndDestroy();  // close xProfile
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::AddOrReplaceHeaderL()
+// -----------------------------------------------------------------------------
+//
+void CHttpUAProfFilter::AddOrReplaceHeaderL
+( RHTTPHeaders& aHeaders, const RStringF& aName, const RStringF& aValue )
+    {
+    // Checking whether the header field is already set or not would be waste:
+    // that is executed inside RemoveField anyway.
+    (void)aHeaders.RemoveField( aName );
+    aHeaders.SetFieldL( aName, THTTPHdrVal( aValue ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::OpenUserAgentNameStringsL()
+// -----------------------------------------------------------------------------
+//
+void CHttpUAProfFilter::OpenUserAgentNameStringsL()
+    {
+    CUserAgent* usrAgnt = CUserAgent::NewL();
+    CleanupStack::PushL( usrAgnt );//C.S: 1
+
+    HBufC8* bufUA = usrAgnt->UserAgentL();
+    CleanupStack::PushL( bufUA );//C.S 2
+    if ( !bufUA || !bufUA->Length() )
+        {
+        // Reject empty value.
+        //User::Leave( KErrCorrupt );
+        User::Panic(_L("Improper UA string"), KErrCorrupt);
+        }
+    iUaName = iStringPool.OpenFStringL( *bufUA );
+    iUaNameOpen = ETrue;
+    
+    //Read the MMS useragent string now
+    HBufC8* bufUAMMS = usrAgnt->MMSUserAgentL();
+    CleanupStack::PushL( bufUAMMS );//C.S 2
+    if ( !bufUAMMS || !bufUAMMS->Length() )
+        {
+        // Reject empty value.
+        //User::Leave( KErrCorrupt );
+        User::Panic(_L("Improper UA string"), KErrCorrupt);
+        }
+    iUaNameMms = iStringPool.OpenFStringL( *bufUAMMS );
+    iUaNameMmsOpen = ETrue;
+    
+    if ( iImeiFeatureEnabled )
+        {
+        // User Agent name string with IMEI code.
+        TBuf<KImeiLength> imei16;
+        GetImeiL( imei16 );
+        HBufC8* imei8 = ConvertL( imei16 );
+        CleanupStack::PushL( imei8 );//C.S 2
+
+        // Add IMEI string to the UA-header.
+        TPtr8 ptrUA = bufUA->Des();
+        AddImeiToUserAgentL(ptrUA, *imei8);
+        iUaNameWithImei =  iStringPool.OpenFStringL( *bufUA );
+        iUaNameWithImeiOpen = ETrue;
+
+        // Add IMEI string to the UA-MMS-header.
+        TPtr8 ptrUAMMS = bufUAMMS->Des();
+        AddImeiToUserAgentL(ptrUAMMS, *imei8);
+        iUaNameMmsWithImei =  iStringPool.OpenFStringL( *bufUAMMS );
+        iUaNameMmsWithImeiOpen = ETrue;
+        
+        CleanupStack::PopAndDestroy( imei8 );//C.S 2
+        }
+        
+        
+	CleanupStack::PopAndDestroy( bufUAMMS );
+	CleanupStack::PopAndDestroy( bufUA );
+    CleanupStack::PopAndDestroy( usrAgnt );//C.S 1 => OK
+    }
+
+void CHttpUAProfFilter::AddImeiToUserAgentL(TPtr8 &aUAStringPtr, const TDesC8& aImei)
+    {
+
+    TInt firstSpaceIndex = aUAStringPtr.Locate( TChar( KSpaceChar ) );
+
+    if ( firstSpaceIndex != KErrNotFound )
+        {
+        // Insert IMEI before first space, separated by '/'
+        aUAStringPtr.Insert( firstSpaceIndex++, KSlash);
+        aUAStringPtr.Insert( firstSpaceIndex, KImeiSnToken);
+        firstSpaceIndex += KImeiSnToken.iTypeLength;
+        aUAStringPtr.Insert( firstSpaceIndex, aImei );
+        }
+    else  
+        {
+        // If there is no spaces, add IMEI to end of ENameMMS, separated by '/'
+        aUAStringPtr.Append( KSlash );
+        aUAStringPtr.Append( KImeiSnToken );
+        aUAStringPtr.Append( aImei );
+        }
+
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::OpenProfileStringsL()
+// -----------------------------------------------------------------------------
+//
+void CHttpUAProfFilter::OpenProfileStringsL()
+    {
+    // UAProf string.
+	TRAPD(err1,iRepositoryCommonEngine = CRepository::NewL( KCRUidWebUtils ));
+	
+	if(KErrNone != err1)
+		User::Panic( _L("CHttpUAProfFilter"), err1 );
+
+    HBufC* buf16;
+
+    User::LeaveIfError( ReadSdString( KWebUtilsUaProf , buf16 ) );
+
+    CleanupStack::PushL( buf16 );
+    if ( !buf16 || !buf16->Length() )
+        {
+        // Reject empty value.
+        User::Leave( KErrCorrupt );
+        }
+    HBufC8* buf8 = ConvertL( *buf16 );
+    CleanupStack::PushL( buf8 );    
+    iUaProf = iStringPool.OpenFStringL( *buf8 );
+    iUaProfOpen = ETrue;
+    CleanupStack::PopAndDestroy( 2, buf16 );    // buf8, buf16
+
+    // UAProf3G string. If missing/empty, not opened - this indicates that
+    // the 2G/3G distinction feature is not supported.
+    TInt err = ReadSdString( KWebUtilsUaProf3G, buf16 );
+
+    CleanupStack::PushL( buf16 );
+    if ( err && err != KErrNotFound )
+        {
+        // Error other than KErrNotFound, leave. KErrNotFound is OK, indicates
+        // that this key is missing -> feature is not supported.
+        User::Leave( err );
+        }
+    if ( buf16 && buf16->Length() )
+        {
+        buf8 = ConvertL( *buf16 );
+        CleanupStack::PushL( buf8 );
+        iUaProf3G = iStringPool.OpenFStringL( *buf8 );
+        iUaProf3GOpen = ETrue;  // Also indicates that feature is supported.
+        CleanupStack::PopAndDestroy( buf8 );
+        }
+
+    CleanupStack::PopAndDestroy( buf16 );
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::ConvertL()
+// -----------------------------------------------------------------------------
+//
+HBufC8* CHttpUAProfFilter::ConvertL( const TDesC16& aSrc )
+    {
+    HBufC8* buf = HBufC8::NewL( aSrc.Length() );
+    buf->Des().Copy( aSrc );
+    return buf;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::ReadSdString()
+// -----------------------------------------------------------------------------
+//
+TInt CHttpUAProfFilter::ReadSdString( const TUint32 aKey, HBufC*& aBuf )
+    {
+    // We don't know the size of the string we are going to read (and Shared
+    // data can't tell it). A trial-and-error method is used: we start with
+    // a fixed size buffer and retry with increasing buffer size until success.
+    TInt err( KErrTooBig );
+    TInt round = 0;
+    HBufC* buf = NULL;
+
+    while( err == KErrTooBig )
+        {
+        // Increase buffer size until returned data can fit.
+        delete buf;
+        ++round;
+        buf = HBufC::New( KSdReadBufSize * round );
+        if( buf )
+            {
+            TPtr bufP( buf->Des() );
+                err = iRepositoryCommonEngine->Get( aKey, bufP );
+            }
+        else
+            {
+            err = KErrNoMemory;
+            }
+        }
+
+    if( err )
+        {
+        delete buf;
+        buf = NULL; // Make lint happy.
+        }
+
+    aBuf = buf;
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::GetImeiL()
+// -----------------------------------------------------------------------------
+//
+void CHttpUAProfFilter::GetImeiL( TDes& aBuf ) const
+    {
+    aBuf.Zero();  
+
+    // Read IMEI on HW, use dummy under WINS
+#if !defined( __WINS__ )
+	TUint32 identityCaps;
+	User::LeaveIfError(iMobilePhone.GetIdentityCaps(identityCaps));
+	TBuf<RMobilePhone::KPhoneSerialNumberSize> serNumber;
+
+if (identityCaps & RMobilePhone::KCapsGetSerialNumber)
+    {
+    TRequestStatus status;
+    RMobilePhone::TMobilePhoneIdentityV1 mobilePhoneIdentity;
+    iMobilePhone.GetPhoneId(status, mobilePhoneIdentity);
+    User::WaitForRequest(status);
+    User::LeaveIfError(status.Int());
+    serNumber = mobilePhoneIdentity.iSerialNumber;
+	aBuf.Copy(serNumber);
+    }
+#else
+    aBuf.Copy( KEmulatorImei);
+#endif
+}
+
+// -----------------------------------------------------------------------------
+// CHttpUAProfFilter::Is3gNetworkL()
+// -----------------------------------------------------------------------------
+//
+TBool CHttpUAProfFilter::Is3gNetworkL() const
+    {
+    // This method must not be called if 2G/3G distinction is not supported;
+    // the RMobilePhone-related classes are not open in that case.
+    __ASSERT_DEBUG( iUaProf3GOpen, \
+        User::Panic( KUAProfFilter, KErrNotReady ) );
+    TBool is3g( EFalse );
+#if !defined( __WINS__ )
+    RMobilePhone::TMobilePhoneNetworkMode networkMode;
+    User::LeaveIfError( iMobilePhone.GetCurrentMode( networkMode ) );
+    if( networkMode == RMobilePhone::ENetworkModeCdma2000 ||
+        networkMode == RMobilePhone::ENetworkModeWcdma )
+        {
+        is3g = ETrue;
+        }
+#endif
+    return is3g;
+    }