connectionmonitoring/connmon/dataconnectionlogger/src/dcl.cpp
changeset 0 5a93021fdf25
child 61 8b0c979bbe8c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/connectionmonitoring/connmon/dataconnectionlogger/src/dcl.cpp	Thu Dec 17 08:55:21 2009 +0200
@@ -0,0 +1,1851 @@
+/*
+* Copyright (c) 2003-2004 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:  Data Connection Logger.
+*
+*/
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <logengdurations.h>
+#include <logwraplimits.h>
+#include <logengevents.h>
+#endif
+#include <cdbcols.h>
+#include <bldvariant.hrh> // Feature IDs
+#include <featmgr.h>
+#include <utf.h>
+
+#include <centralrepository.h>
+#include "DclPrivateCRKeys.h"
+
+#include "dcl.h"
+#include "dcl_log.h"
+
+// --------------------------------------------------------------------------
+// CEngine::CEngine
+// Constructor
+// --------------------------------------------------------------------------
+//
+CEngine::CEngine()
+        :
+        CActive( EPriorityStandard ),
+        iLogClient( NULL ),
+        iTimerInterval( KTimerInterval )
+    {
+    CActiveScheduler::Add( this );
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::NewLC
+// 1st phase constructor - for stack pointers to object
+// --------------------------------------------------------------------------
+//
+CEngine* CEngine::NewLC( )
+    {
+    CEngine* self = new( ELeave ) CEngine();
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::NewL
+// 1st phase constructor - for heap pointers to object
+// --------------------------------------------------------------------------
+//
+CEngine* CEngine::NewL( )
+    {
+    CEngine* self = NewLC();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::ConstructL
+// 2nd phase constructor
+// --------------------------------------------------------------------------
+//
+void CEngine::ConstructL()
+    {
+    LOGENTRFN("CEngine::ConstructL()")
+    // Renaming the thread with the real process name helps debugging panics.
+    RThread::RenameMe( KDCLName );
+
+    FeatureManager::InitializeLibL();
+
+    iConnectionMonitor.ConnectL();
+
+    User::LeaveIfError( iFsEventLog.Connect() );
+
+    iLogWrap = CLogWrapper::NewL( iFsEventLog, CActive::EPriorityStandard );
+    iLogEventQueue = new( ELeave ) CArrayPtrFlat<CEvent>( KEventStateMaxCount );
+    iLogEventQueue->Reset();
+
+    iConnections = new( ELeave ) CArrayPtrFlat<CEvent>( KEventStateMaxCount );
+    iConnections->Reset();
+
+    iCurrentLogEvent = CLogEvent::NewL();
+
+    iLogClient = CLogClient::NewL( iFsEventLog );
+
+    // Connect to ETel server
+    // The RTelServer::Connect() might not always work with the first trial,
+    // because of a coding error related to using semaphores in the method.
+
+    TInt err( KErrNotReady );
+    TInt a = 0;
+    while( a < KPhoneRetryCount && err != KErrNone )
+        {
+        if ( a )
+            {
+            User::After( KPhoneRetryTimeout ); // Don't wait on first try
+            }
+        err = iTelServer.Connect();
+        LOGIT1("Connecting to ETel server <%d>", err)
+        a++;
+        }
+    User::LeaveIfError( err );
+
+    // Try to load phone.tsy
+    TBuf<KCommsDbSvrMaxColumnNameLength> tsyName;
+    tsyName.Copy( KMmTsyModuleName );
+    err = iTelServer.LoadPhoneModule( tsyName );
+
+    if ( err == KErrNone )
+        {
+        iTSYLoaded = 1;
+        // Phone info can be retrieved with value 0 if there is only 1 phone
+        RTelServer::TPhoneInfo info;
+        User::LeaveIfError( iTelServer.GetPhoneInfo( 0, info ) );
+        User::LeaveIfError( iMobilePhone.Open( iTelServer, info.iName ) );
+
+        // Open packet service
+        err = iPacketService.Open( iMobilePhone );
+        if ( err == KErrNone )
+            {
+            iPacketServLoaded = 1;
+            }
+        }
+    if ( FeatureManager::FeatureSupported( KFeatureIdLoggerGprs ) )
+        {
+        LOGIT0("LoggerGprs supported")
+
+        // Get the Attach Mode setting from CommDb and set ETel to use that
+        // value. Must not leave if an error occurs.
+        TRAPD( leaveCode, SetAttachModeL() );
+        LOGIT1("SetAttachModeL() result: <%d>", leaveCode)
+
+        // Get the default APN from CommDb and set ETel to use that APN.
+        // Must not leave if an error occurs.
+        TRAP( leaveCode, SetAPNL() );
+        LOGIT1("SetAPNL() result: <%d>", leaveCode)
+        }
+    // Adds the event type Wlan. Otherwise the LogClient
+    // will not understand this type of event.
+    AddEventTypeL();
+
+    // Read ini file settings
+    ReadIniFile();
+
+    // Create timer mode AO
+    iDclTimerAO = new( ELeave ) CDclTimerAO ( this, iTimerInterval );
+    iDclTimerAO->ConstructL();
+
+    // Create saeObserver for updating P&S variables
+    iSaeObserver = CSaeObserver::NewL( iConnectionMonitor );
+    LOGEXITFN("CEngine::ConstructL()")
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::~CEngine
+// Destructor
+// Frees reserved resources.
+// --------------------------------------------------------------------------
+//
+CEngine::~CEngine()
+    {
+    LOGENTRFN("CEngine::~CEngine()")
+    FeatureManager::UnInitializeLib();
+
+    delete iSaeObserver;
+    iSaeObserver = NULL;
+
+    // Disconnect from CM server.
+    iConnectionMonitor.Close();
+
+    Cancel();
+    // The queue could be not empty if the active object
+    // is aborted and destructed.
+    if ( iLogEventQueue != 0 )
+        {
+        iLogEventQueue->ResetAndDestroy();
+        }
+
+    if ( iConnections != 0 )
+        {
+        iConnections->ResetAndDestroy();
+        }
+
+    delete iLogWrap;
+    iLogWrap = NULL;
+
+    delete iLogEventQueue;
+    iLogEventQueue = NULL;
+
+    delete iConnections;
+    iConnections = NULL;
+
+    delete iCurrentLogEvent;
+    iCurrentLogEvent = NULL;
+
+    delete iLogEventType;
+    iLogEventType = NULL;
+
+    delete iLogClient;
+    iLogClient = NULL;
+
+    iFsEventLog.Close();
+
+    // Close "global" ETEL objects
+    if ( iPacketServLoaded == 1 )
+        {
+        iPacketService.Close();
+        }
+
+    iMobilePhone.Close();
+    iTelServer.Close();
+
+    delete iDclTimerAO;
+    iDclTimerAO = NULL;
+    LOGEXITFN("CEngine::~CEngine()")
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::NotifyL
+// Request Connection Monitor server to send notifications of events.
+// --------------------------------------------------------------------------
+//
+void CEngine::NotifyL()
+    {
+    iConnectionMonitor.NotifyEventL( *this );
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::EventL
+// Receives notifications of events from Connection Monitor server.
+// --------------------------------------------------------------------------
+//
+void CEngine::EventL( const CConnMonEventBase& aConnMonEvent )
+    {
+    //LOGENTRFN("CEngine::EventL()")
+    LOGIT1("-> CEngine::EventL() entered, event type (%d)", aConnMonEvent.EventType())
+    TInt err( KErrNone );
+    TUint connectionId( 0 );
+
+    // Update P&S variables first
+    if ( iSaeObserver )
+        {
+        iSaeObserver->EventL( aConnMonEvent );
+        }
+
+    switch ( aConnMonEvent.EventType() )
+        {
+        case EConnMonCreateConnection:
+            {
+            TInt bearer( 0 );
+            TRequestStatus status( KErrNotReady );
+
+            const CConnMonCreateConnection* eventCreate;
+            eventCreate  = static_cast<const CConnMonCreateConnection*>( &aConnMonEvent );
+            connectionId = eventCreate->ConnectionId();
+
+            LOGIT1("*** EConnMonCreateConnection event, id %d ***", connectionId)
+
+            // Get the bearer info from CM server.
+            err = KErrNotReady;
+            TInt a = 0;
+            while( a < KPhoneRetryCount && err != KErrNone )
+                {
+                // ConnMon might not be able to provide KBearer with the first trial.
+                if ( a )
+                    {
+                    User::After( KPhoneRetryTimeout ); // Don't wait on first try
+                    }
+                iConnectionMonitor.GetIntAttribute(
+                        connectionId,
+                        KSubConnectionId,
+                        KBearer,
+                        bearer,
+                        status );
+                User::WaitForRequest( status );
+                err = status.Int();
+                LOGIT2("Got bearer %d from ConnMon <%d>", bearer, err)
+                a++;
+                }
+            if ( err != KErrNone )
+                {
+                LOGIT1("FAILED to get KBearer from ConnMon <%d>", err)
+                break;
+                }
+
+            // Check that it is GPRS or WCDMA.
+            if ( bearer == EBearerGPRS     ||
+                 bearer == EBearerEdgeGPRS ||
+                 bearer == EBearerWCDMA )
+                {
+                LOGIT0("New internal connection")
+                // Set the uplink and downlink thresholds for this particular connection.
+                TUint threshold( iGPRSThreshold );
+                if ( bearer == EBearerWCDMA )
+                    {
+                    threshold = iWCDMAThreshold;
+                    }
+
+                err = iConnectionMonitor.SetUintAttribute(
+                        connectionId,
+                        KSubConnectionId,
+                        KDownlinkDataThreshold,
+                        threshold );
+                if ( err != KErrNone )
+                    {
+                    LOGIT1("FAILED to set KDownlinkDataThreshold to ConnMon <%d>", err)
+                    }
+
+                err = iConnectionMonitor.SetUintAttribute(
+                        connectionId,
+                        KSubConnectionId,
+                        KUplinkDataThreshold,
+                        threshold );
+                if ( err != KErrNone )
+                    {
+                    LOGIT1("FAILED to set KUplinkDataThreshold to ConnMon <%d>", err)
+                    }
+
+                TName iapName;
+                iapName.FillZ();
+                iapName.Zero();
+
+                // Get String Attribute -> KIAPName.
+                // Get IAP name from CM server.
+                err = KErrNotReady;
+                a = 0;
+                while( a < KPhoneRetryCount && err != KErrNone )
+                    {
+                    // ConnMon might not be able to provide KIAPName with the first trial.
+                    if ( a )
+                        {
+                        User::After( KPhoneRetryTimeout ); // Don't wait on first try
+                        }
+                    iConnectionMonitor.GetStringAttribute(
+                            connectionId,
+                            KSubConnectionId,
+                            KIAPName,
+                            iapName,
+                            status );
+                    User::WaitForRequest( status );
+                    err = status.Int();
+                    LOG( TBuf<KMaxName+1> iapName2( iapName ); )
+                    LOGIT2("Got KIAPName from ConnMon <%s>, <%d>", iapName2.PtrZ(), err)
+                    a++;
+                    }
+
+                if ( err == KErrNone )
+                    {
+                    LogDataAddEventL(
+                            connectionId,
+                            R_LOG_CON_CONNECTED,
+                            iapName,
+                            R_LOG_DIR_OUT,
+                            KNullDesC,
+                            KLogPacketDataEventTypeUid );
+                    }
+                else
+                    {
+                    LOGIT1("FAILED to get KIAPName from ConnMon <%d>", err)
+                    }
+                }
+            else if ( bearer == EBearerWLAN )
+                // Add EBearerExternalWLAN in order to enable DCL to log
+                // external WLAN connections, i.e. then the mobile phone
+                // functions as a WLAN modem
+                {
+                LOGIT0("New WLAN connection")
+
+                // Set the uplink and downlink thresholds for this particular connection.
+                err = iConnectionMonitor.SetUintAttribute(
+                        connectionId,
+                        KSubConnectionId,
+                        KDownlinkDataThreshold,
+                        iWLANThreshold );
+                if ( err != KErrNone )
+                    {
+                    LOGIT1("FAILED to set KDownlinkDataThreshold to ConnMon <%d>", err)
+                    }
+
+                // Even if KDownlinkDataThreshold and KUplinkDataThreshold
+                // are used here ( 4096 bytes ), the Connection Monitor
+                // server actually sets the threshold to 20480 bytes =
+                // 20 kilobytes.
+                err = iConnectionMonitor.SetUintAttribute(
+                        connectionId,
+                        KSubConnectionId,
+                        KUplinkDataThreshold,
+                        iWLANThreshold );
+                if ( err != KErrNone )
+                    {
+                    LOGIT1("FAILED to set KUplinkDataThreshold to ConnMon <%d>", err)
+                    }
+
+                TName iapName;
+                iapName.FillZ();
+                iapName.Zero();
+                // Get Uint Attribute -> KIAPId.
+                // Get IAP id from CM server.
+                err = KErrNotReady;
+                a = 0;
+                TUint iapId( 0 );
+                while( a < KPhoneRetryCount && err != KErrNone )
+                    {
+                    // ConnMon might not be able to provide KIAPId with the first trial.
+                    if ( a )
+                        {
+                        User::After( KPhoneRetryTimeout ); // Don't wait on first try
+                        }
+                    iConnectionMonitor.GetUintAttribute(
+                            connectionId,
+                            KSubConnectionId,
+                            KIAPId,
+                            iapId,
+                            status );
+                    User::WaitForRequest( status );
+                    err = status.Int();
+                    LOGIT2("Got IAP ID %d from ConnMon <%d>", iapId, err)
+                    a++;
+                    }
+                // For each new WLAN connection, we need to check the used IAP.
+                // For a normal IAP, the IAP name is used for logging, but when
+                // customer is using the 'Search for WLAN' functionality and
+                // chooses a WLAN network that is not found in any current IAP,
+                // the Easy WLAN IAP is used instead. This IAP has some internal
+                // name, e.g. 'Easy WLAN', that should not be visible anywhere
+                // in the UI. So SSID of used network is used in logging instead.
+                //
+                if ( err == KErrNone )
+                    {
+                    // Create a session with the latest version CommsDat
+                    CMDBSession* db = CMDBSession::NewLC( CMDBSession::LatestVersion() );
+                    db->SetAttributeMask( ECDProtectedWrite );
+
+                    // Load IAP record
+                    CCDIAPRecord* iapRecord = static_cast<CCDIAPRecord*>(
+                            CCDRecordBase::RecordFactoryL( KCDTIdIAPRecord ) );
+                    CleanupStack::PushL( iapRecord );
+                    iapRecord->SetRecordId( iapId );
+                    iapRecord->LoadL( *db );
+                    LOGIT0("Read IAP record from CommsDat")
+
+                    // Load wlan service record
+                    CCDWlanServiceRecord* wlanRecord = new( ELeave )CCDWlanServiceRecord(
+                            CCDWlanServiceRecord::TableIdL( *db ) );
+                    CleanupStack::PushL( wlanRecord );
+                    wlanRecord->iWlanServiceId = iapRecord->iService;
+
+                    if ( wlanRecord->FindL( *db ) )
+                        {
+                        wlanRecord->LoadL( *db );
+                        LOGIT0("Read WLAN record from CommsDat")
+
+                        if ( wlanRecord->iWLanSSID.IsNull() )
+                            {
+                            // Used IAP is the special 'Easy WLAN' IAP, so we need to
+                            // log the used WLAN network SSID instead of 'Easy WLAN'.
+                            // This can be read from the 'iWLanUsedSSID'-field.
+                            if ( !( wlanRecord->iWLanUsedSSID.IsNull() ) )
+                                {
+                                iapName = wlanRecord->iWLanUsedSSID.GetL();
+                                LOGIT1("Easy WLAN detected, got SSID <%s> from CommsDat", &iapName)
+                                }
+                            else
+                                {
+                                LOGIT0("Error, Easy WLAN detected but no SSID found from CommsDat")
+                                }
+                            }
+                        else
+                            {
+                            // A noraml WLAN IAP, read IAP name and use it for logging
+                            iapName = iapRecord->iRecordName.GetL();
+                            LOGIT1("Got IAP name <%s> from CommsDat", &iapName)
+                            }
+                        }
+                    else
+                        {
+                        LOGIT0("Error, WLAN record not found from CommsDat")
+                        }
+                    LogDataAddEventL(
+                            connectionId,
+                            R_LOG_CON_CONNECTED,
+                            iapName,
+                            R_LOG_DIR_OUT,
+                            KNullDesC,
+                            KLogWlanDataEventTypeUid );
+
+                    CleanupStack::PopAndDestroy( wlanRecord );
+                    CleanupStack::PopAndDestroy( iapRecord );
+                    CleanupStack::PopAndDestroy( db );
+                    }
+                else
+                    {
+                    LOGIT1("FAILED to get KIAPId from ConnMon", err)
+                    }
+                }
+            // Check if it is EXTERNAL GPRS or WCDMA.
+            else if ( bearer == EBearerExternalGPRS     ||
+                      bearer == EBearerExternalEdgeGPRS ||
+                      bearer == EBearerExternalWCDMA )
+                {
+                LOGIT0("New external connection")
+
+                TName apName;
+                apName.FillZ();
+                apName.Zero();
+
+                err = KErrNotReady;
+                a = 0;
+                // We loop until the retry count is reached or
+                // we get a name with length > 0
+                // This is because the connection monitor asks the PSD Fax
+                // for the name and PSD fax sometines returns an empty string
+                // without returning an error code (KErrNone is returned)
+                // However if no name for the APN has been defined this will
+                // loop for KPhoneRetryCount times for vain, but it's better than
+                // to use an empty name if one has been defined...
+                while( a < KPhoneRetryCount &&
+                        ( ( err != KErrNone ) || ( apName.Length() == 0 ) ) )
+                    {
+                    // ConnMon might not be able to provide KAccessPointName with first trial.
+                    if ( a )
+                        {
+                        User::After( KPhoneRetryTimeout ); // Don't wait on first try
+                        }
+                    // Get String Attribute -> KAccessPointName.
+                    // Get APN from CM server.
+                    iConnectionMonitor.GetStringAttribute(
+                            connectionId,
+                            KSubConnectionId,
+                            KAccessPointName,
+                            apName,
+                            status );
+                    User::WaitForRequest( status );
+                    err = status.Int();
+                    LOG( TBuf<KMaxName+1> apName2( apName ); )
+                    LOGIT2("Got KAccessPointName from ConnMon <%s>, <%d>", apName2.PtrZ(), err)
+                    a++;
+                    }
+                if ( err == KErrNone )
+                    {
+                    LogDataAddEventL(
+                            connectionId,
+                            R_LOG_CON_CONNECTED,
+                            apName,
+                            R_LOG_DIR_OUT,
+                            KNullDesC,
+                            KLogPacketDataEventTypeUid );
+                    }
+                else
+                    {
+                    LOGIT1("FAILED to get KAccessPointName from ConnMon <%d>", err)
+                    }
+                }
+            else
+                {
+                LOGIT0("Bearer neither GPRS nor WCDMA nor WLAN, ignored")
+                break;
+                }
+            break;
+            }
+
+        case EConnMonConnectionStatusChange:
+            {
+            TInt bearer( 0 );
+            TRequestStatus status( KErrNotReady );
+
+            const CConnMonConnectionStatusChange* eventStatus;
+            eventStatus  = static_cast<const CConnMonConnectionStatusChange*>( &aConnMonEvent );
+            connectionId = eventStatus->ConnectionId();
+
+            LOGIT2("*** EConnMonConnectionStatusChange event, id %d, status %d ***",
+                    connectionId, eventStatus->ConnectionStatus())
+
+            if ( eventStatus->ConnectionStatus() == KPsdFinishedActivation )
+                {
+                // Get the bearer info from CM server.
+                iConnectionMonitor.GetIntAttribute(
+                        connectionId,
+                        KSubConnectionId,
+                        KBearer,
+                        bearer,
+                        status );
+                User::WaitForRequest( status );
+                err = status.Int();
+                if ( err != KErrNone )
+                    {
+                    LOGIT1("FAILED to get bearer from ConnMon <%d>", err)
+                    break;
+                    }
+
+                // Check that it is external GPRS or WCDMA.
+                if ( bearer == EBearerExternalGPRS      ||
+                     bearer == EBearerExternalEdgeGPRS  ||
+                     bearer == EBearerExternalWCDMA )
+                    // Add EBearerLAN in order to enable debugging in wins.
+                    {
+                    LOGIT1("Status: KPsdFinishedActivation, bearer: %d (valid external), updating AP name", bearer)
+                    TName apName;
+                    apName.FillZ();
+                    apName.Zero();
+
+                    err = KErrNotReady;
+                    TInt a = 0;
+                    // We loop until the retry count is reached or
+                    // we get a name with length > 0
+                    // This is because the connection monitor asks the PSD Fax
+                    // for the name and PSD fax sometines returns an empty string
+                    // without returning an error code (KErrNone is returned)
+                    // However if no name for the APN has been defined this will
+                    // loop for KPhoneRetryCount times for vain, but it's better than
+                    // to use an empty name if one has been defined...
+                    while( a < KPhoneRetryCount &&  (
+                            ( err != KErrNone ) ||
+                            ( apName.Length() == 0 )
+                            ) )
+                        {
+                        // ConnMon might not be able to provide KAccessPointName with first trial.
+                        if ( a )
+                            {
+                            User::After( KPhoneRetryTimeout ); // Don't wait on first try
+                            }
+                        // Get String Attribute -> KAccessPointName.
+                        // Get APN from CM server.
+                        iConnectionMonitor.GetStringAttribute(
+                                connectionId,
+                                KSubConnectionId,
+                                KAccessPointName,
+                                apName,
+                                status );
+                        User::WaitForRequest( status );
+                        err = status.Int();
+                        LOG( TBuf<KMaxName+1> apName2( apName ); )
+                        LOGIT2("Got KAccessPointName from ConnMon <%s>, <%d>", apName2.PtrZ(), err)
+                        a++;
+                        }
+
+                    if ( err == KErrNone )
+                        {
+                        // We want only to change the existing entry in the log,
+                        // not add a new one, thus LogDataChangeEventL instead of
+                        // LogDataAddEventL
+                        LogDataChangeEventL( connectionId, apName );
+                        }
+                    else
+                        {
+                        LOGIT1("FAILED to get KAccessPointName from ConnMon <%d>", err)
+                        }
+                    }
+                else
+                    {
+                    LOGIT1("Status: KPsdFinishedActivation, bearer: %d (not valid external)", bearer)
+                    }
+                }
+            }
+            break;
+
+        case EConnMonDeleteConnection:
+            {
+            const CConnMonDeleteConnection* eventDelete;
+            eventDelete  = static_cast<const CConnMonDeleteConnection*>( &aConnMonEvent );
+            connectionId = eventDelete->ConnectionId();
+
+            LOGIT1("*** EConnMonDeleteConnection event, id %d ***", connectionId)
+            LOGIT1("sent: %d bytes", eventDelete->UplinkData())
+            LOGIT1("recv: %d bytes", eventDelete->DownlinkData())
+
+            // First update SharedData downlink and uplink data
+            UpdateSharedDataL(
+                    connectionId,
+                    eventDelete->UplinkData(),
+                    eventDelete->DownlinkData() );
+
+            // Then update connection specific downlink and uplink data
+            err = LogDataUpdateEventL(
+                    connectionId,
+                    R_LOG_CON_DISCONNECTED,
+                    TUid::Null(),
+                    eventDelete->UplinkData(),
+                    eventDelete->DownlinkData() );
+            if ( err != KErrNone )
+                {
+                LOGIT1("FAILED to log connection deletion <%d>", err)
+                }
+
+            // Stop timer mode for this connection.
+            // It is ok to call this even if the connection was not in timer mode.
+            iDclTimerAO->Remove( connectionId );
+
+            }
+            break;
+
+        case EConnMonDownlinkDataThreshold:
+            {
+            TInt oldDuration( 0 );
+            TInt newDuration( 0 );
+
+            const CConnMonDownlinkDataThreshold* down;
+            down = static_cast<const CConnMonDownlinkDataThreshold*>( &aConnMonEvent );
+            connectionId = down->ConnectionId();
+
+            LOGIT1("*** EConnMonDownlinkDataThreshold event, id %d ***", connectionId)
+
+            if ( !GetDuration( connectionId, oldDuration ) )
+                {
+                return;
+                }
+
+            // First update SharedData downlink data
+            UpdateSharedDataL( connectionId, 0, down->DownlinkData() );
+
+            // Then update connection specific downlink data
+            // Also uplink data has to be updated at the same time,
+            // since CEventLog function SetDataL requires both values.
+            TRequestStatus status;
+            TUint uplinkData( 0 );
+            // Get the amount uplink data from CM server
+            iConnectionMonitor.GetUintAttribute(
+                    connectionId,
+                    KSubConnectionId,
+                    KUplinkData,
+                    uplinkData,
+                    status );
+            User::WaitForRequest( status );
+            if ( status.Int() != KErrNone )
+                {
+                LOGIT1("FAILED to get KUplinkData from ConnMon <%d>", err)
+                }
+
+            // The actual status of connection is R_LOG_CON_CONNECTED, but
+            // due to the performance reasons KConnectionStatusIdNotAvailable
+            // is used here. There is no need to read LOGWRAP.RSC every time.
+            err = LogDataUpdateEventL(
+                    connectionId,
+                    KConnectionStatusIdNotAvailable,
+                    TUid::Null(),
+                    uplinkData,
+                    down->DownlinkData() );
+            if ( err != KErrNone )
+                {
+                LOGIT1("FAILED to update log event <%d>", err)
+                }
+
+            // Switch to timer if we are updating log too often
+            if ( GetDuration( connectionId, newDuration ) )
+                {
+                if ( ( newDuration - oldDuration ) < iTimerInterval )
+                    {
+                    SwitchToTimerMode( connectionId );
+                    }
+                }
+            }
+            break;
+
+        case EConnMonUplinkDataThreshold:
+            {
+            TInt oldDuration( 0 );
+            TInt newDuration( 0 );
+
+            const CConnMonUplinkDataThreshold* up;
+            up = static_cast<const CConnMonUplinkDataThreshold*>( &aConnMonEvent );
+            connectionId = up->ConnectionId();
+
+            LOGIT1("*** EConnMonUplinkDataThreshold event, id %d ***", connectionId)
+
+            if ( !GetDuration( connectionId, oldDuration ) )
+                {
+                return;
+                }
+
+            // First update SharedData uplink data
+            UpdateSharedDataL( connectionId, up->UplinkData(), 0 );
+
+            // Then update connection specific uplink data
+            // Also downlink data has to be updated at the same time,
+            // since CEventLog function SetDataL requires both values.
+            TRequestStatus status;
+            TUint downlinkData( 0 );
+
+            // Get the amount of downlink data from CM server
+            iConnectionMonitor.GetUintAttribute(
+                    connectionId,
+                    KSubConnectionId,
+                    KDownlinkData,
+                    downlinkData,
+                    status );
+            User::WaitForRequest( status );
+            if ( status.Int() != KErrNone )
+                {
+                LOGIT1("FAILED to get KDownlinkData from ConnMon <%d>", err)
+                }
+
+            // The actual status of connection is R_LOG_CON_CONNECTED, but
+            // due to the performance reasons KConnectionStatusIdNotAvailable
+            // is used here. There is no need to read LOGWRAP.RSC every time.
+            err = LogDataUpdateEventL(
+                    connectionId,
+                    KConnectionStatusIdNotAvailable,
+                    TUid::Null(),
+                    up->UplinkData(),
+                    downlinkData );
+            if ( err != KErrNone )
+                {
+                LOGIT1("FAILED to update log event <%d>", err)
+                }
+
+            // Switch to timer if we are updating log too often
+            if ( GetDuration( connectionId, newDuration ) )
+                {
+                if ( ( newDuration - oldDuration ) < iTimerInterval )
+                    {
+                    SwitchToTimerMode( connectionId );
+                    }
+                }
+            }
+            break;
+
+        default:
+            /*
+             *  By default Connection Monitor server sends all the events to
+             *  all the clients, which have subscribed to reveive events. It
+             *  is not possible to subscribe to only selected events.
+             *
+             *  Therefore these events are not written to log.
+             */
+            break;
+        }
+    LOGEXITFN("CEngine::EventL()")
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::LogDataAddEventL
+// Adds log events.
+//
+// Handles also multiple data connections.
+// --------------------------------------------------------------------------
+//
+void CEngine::LogDataAddEventL(
+        TLogId       aConnectionId,
+        TInt         aRConnectionStatusId,
+        const TDesC& aRemote,
+        TInt         aLogDir,
+        const TDesC& aTelNum,
+        const TUid&  aDataEventType )
+    {
+    LOGENTRFN("CEngine::LogDataAddEventL()")
+    // It is possible to add a new logevent with a new log id for the same
+    // connection (reconnect case) assuming that all the next updates will
+    // be for the new event and not the old one.
+    TTime time;
+    time.UniversalTime();
+    TBuf<KLogMaxStatusLength> logStatusBuf;
+    TBuf<KLogMaxDirectionLength> logDirBuf;
+
+    // Set the parameters for CEvent
+    CEvent* eventUpdate = CEvent::NewL();
+    CleanupStack::PushL( eventUpdate );
+    eventUpdate->iConnectionId = aConnectionId;
+    eventUpdate->iLogWrapEvent->SetId( KGenconnLogWaitingForLogId );
+    eventUpdate->iLogWrapEvent->SetTime( time );
+    // Ignore error - string blank on error which is ok.
+    iLogWrap->Log().GetString( logStatusBuf, aRConnectionStatusId );
+    eventUpdate->iLogWrapEvent->SetStatus( logStatusBuf );
+    eventUpdate->iLogWrapEvent->SetRemoteParty( aRemote );
+    // Ignore error - string blank on error which is ok.
+    iLogWrap->Log().GetString( logDirBuf, aLogDir );
+    eventUpdate->iLogWrapEvent->SetDirection( logDirBuf );
+    eventUpdate->iLogWrapEvent->SetNumber( aTelNum );
+    eventUpdate->iLogWrapEvent->SetEventType( *CONST_CAST( TUid*, &aDataEventType ) );
+    eventUpdate->iLogWrapEvent->SetDurationType( KLogDurationValid );
+
+    // If there are no requests in the queue, then write to log immediately.
+    if ( !IsActive() && ( iLogEventQueue->Count() == 0 ) )
+        {
+        iConnections->AppendL( eventUpdate );
+        iStatus = KRequestPending;
+        iLogWrap->Log().AddEvent( *eventUpdate->iLogWrapEvent, iStatus );
+        SetActive();
+        }
+    else
+        {
+        LOGIT0("Adding event to eventqueue")
+        // Add the request to the queue, it will be processed ASAP.
+        iLogEventQueue->AppendL( eventUpdate );
+        }
+    CleanupStack::Pop( eventUpdate );
+    LOGEXITFN("CEngine::LogDataAddEventL()")
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::LogDataChangeEventL
+// Changes log events. Used to update the access point name of the
+// external GPRS ie. dial-up connections.
+//
+// Handles also multiple data connections.
+// --------------------------------------------------------------------------
+//
+void CEngine::LogDataChangeEventL( TLogId aConnectionId, const TDesC& aRemote )
+    {
+    LOGENTRFN("CEngine::LogDataChangeEventL()")
+
+    // Check event queue first, if a match is found, the connection hasn't been
+    // added to iConnections array yet. Update event in queue with correct
+    // access point name.
+    for ( TInt index = 0; index < iLogEventQueue->Count(); index++ )
+        {
+        LOGIT2("Checking event queue index %d, id %d", index, iLogEventQueue->At( index )->iConnectionId)
+        if ( iLogEventQueue->At( index )->iConnectionId == aConnectionId )
+            {
+            LOGIT0("Match found, merging updated apn to queued event")
+            iLogEventQueue->At( index )->iLogWrapEvent->SetRemoteParty( aRemote );
+            LOGEXITFN("CEngine::LogDataChangeEventL()")
+            return;
+            }
+        }
+
+    // Most likely event queue was empty, so next we need to find the relevant
+    // connection from iConnections array.
+    for ( TInt index = 0; index < iConnections->Count(); index++ )
+        {
+        LOGIT2("Checking connections index %d, id %d", index, iConnections->At( index )->iConnectionId)
+
+        if ( iConnections->At( index )->iConnectionId == aConnectionId )
+            {
+            // Can update now, or need add to queue
+            if ( !IsActive() && ( iLogEventQueue->Count() == 0 ) )
+                {
+                LOGIT0("Match found, updating apn immediately")
+
+                // Update apn and initiate LogWrapper update.
+                iConnections->At( index )->iLogWrapEvent->SetRemoteParty( aRemote );
+                iStatus = KRequestPending;
+                iLogWrap->Log().ChangeEvent( *iConnections->At( index )->iLogWrapEvent, iStatus );
+                SetActive();
+                }
+            else
+                {
+                LOGIT0("Match found, adding apn update event to queue")
+
+                // Make a copy of the CLogEvent, update apn and add the updated
+                // copy to event queue.
+                CEvent* eventUpdate = CEvent::NewL();
+                CleanupStack::PushL( eventUpdate );
+
+                eventUpdate->iConnectionId = aConnectionId;
+                eventUpdate->iLogWrapEvent->CopyL( *iConnections->At( index )->iLogWrapEvent );
+                eventUpdate->iLogWrapEvent->SetRemoteParty( aRemote );
+                iLogEventQueue->AppendL( eventUpdate );
+
+                CleanupStack::Pop( eventUpdate );
+                }
+            }
+        break; // for
+        }
+    LOGEXITFN("CEngine::LogDataChangeEventL()")
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::LogDataUpdateEventL
+// Updates log events.
+//
+// Handles also multiple data connections.
+// --------------------------------------------------------------------------
+//
+TInt CEngine::LogDataUpdateEventL(
+        TLogId        aConnectionId,
+        TInt          aRConnectionStatusId,
+        const TUid&   aDataEventType,
+        const TInt64& aBytesSent,
+        const TInt64& aBytesReceived )
+    {
+    LOGENTRFN("CEngine::LogDataUpdateEventL()")
+    TInt ret = KErrNone;
+    TLogId connectionId;
+
+    for ( TInt index = 0; index < iConnections->Count(); index++ )
+        {
+        connectionId = iConnections->At( index )->iConnectionId;
+
+        if ( connectionId == aConnectionId )
+            {
+            // Check if there is no request pending, then start it. Otherwise
+            // wait until the previous request is finished and keep going on.
+            if ( !IsActive() && ( iLogEventQueue->Count() == 0 ) )
+                {
+                // Request update straight on.
+                UpdateLogEventParamL(
+                        aConnectionId,
+                        *iConnections->At( index )->iLogWrapEvent,
+                        aRConnectionStatusId,
+                        aDataEventType,
+                        aBytesSent,
+                        aBytesReceived );
+
+                iConnections->At( index )->iPrevDuration =
+                        iConnections->At( index )->iLogWrapEvent->Duration();
+
+                iLogWrap->Log().ChangeEvent( *iConnections->At( index )->iLogWrapEvent, iStatus );
+                SetActive();
+                }
+            else
+                {
+                LOGIT0("Adding event update to queue")
+                // Add the request to the queue, it will be processed ASAP.
+                CEvent* eventUpdate = CEvent::NewL();
+                CleanupStack::PushL( eventUpdate );
+                eventUpdate->iConnectionId = aConnectionId;
+                eventUpdate->iLogWrapEvent->CopyL( *iConnections->At( index )->iLogWrapEvent );
+                ret = UpdateLogEventParamL(
+                        aConnectionId,
+                        *eventUpdate->iLogWrapEvent,
+                        aRConnectionStatusId,
+                        aDataEventType,
+                        aBytesSent,
+                        aBytesReceived );
+
+                iConnections->At( index )->iPrevDuration =
+                        eventUpdate->iLogWrapEvent->Duration();
+
+                // Add to the queue.
+                iLogEventQueue->AppendL( eventUpdate );
+                CleanupStack::Pop( eventUpdate );
+                }
+            }
+        }
+    LOGEXITFN1("CEngine::LogDataUpdateEventL()", ret)
+    return ret;
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::UpdateLogEventParamL
+// Updates log event parameters.
+// --------------------------------------------------------------------------
+//
+TInt CEngine::UpdateLogEventParamL(
+        TLogId        /*aConnectionId*/,
+        CLogEvent&    aLogEvent,
+        TInt          aRConnectionStatusId,
+        const TUid&   aDataEventType,
+        const TInt64& aBytesSent,
+        const TInt64& aBytesReceived )
+    {
+    LOGENTRFN("CEngine::UpdateLogEventParamL()")
+    TInt ret( KErrNone );
+    TTime now;
+    TTimeIntervalSeconds seconds( 0 );
+    now.UniversalTime();
+
+    if ( now.SecondsFrom( aLogEvent.Time(), seconds ) != KErrNone )
+        {
+        seconds = 0; // No duration available -> error.
+        }
+    aLogEvent.SetDuration( seconds.Int() );
+
+    if ( KConnectionStatusIdNotAvailable != aRConnectionStatusId )
+        {
+        // Status needs to be updated.
+        TBuf<KLogMaxStatusLength> logStatusBuf;
+        // Ignore error - string blank on error which is ok.
+        iLogWrap->Log().GetString( logStatusBuf, aRConnectionStatusId );
+        aLogEvent.SetStatus( logStatusBuf );
+        }
+    if ( aDataEventType != TUid::Null() )
+        {
+        aLogEvent.SetEventType( *CONST_CAST( TUid*, &aDataEventType ) );
+        }
+    // Check if data metrics need to be updated.
+    TInt64 byteInfoNotAvailable( KBytesInfoNotAvailable );
+    if ( ( aBytesReceived != byteInfoNotAvailable ) &&
+         ( aBytesSent     != byteInfoNotAvailable ) )
+        {
+        TBuf8<KDatabufferSize> dataBuffer;
+        dataBuffer.Num( aBytesSent );
+        dataBuffer.Append( TChar(',') );
+        dataBuffer.AppendNum( aBytesReceived );
+        TRAP( ret, aLogEvent.SetDataL( dataBuffer ) );
+        }
+    LOGEXITFN1("CEngine::UpdateLogEventParamL()", ret)
+    return ret;
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::UpdateSharedDataL
+// Updates cumulative counters of SharedData.
+// --------------------------------------------------------------------------
+//
+void CEngine::UpdateSharedDataL(
+        TLogId aConnectionId,
+        const TInt64& aBytesSent,
+        const TInt64& aBytesReceived )
+    {
+    LOGENTRFN("CEngine::UpdateSharedDataL()")
+    TInt64   sent( 0 );
+    TInt64   received( 0 );
+    TInt64   increment( 0 );
+    TLogId   connId;
+    TBuf<50> receivedBuf,  sentBuf;
+    TBuf<50> receivedBuf2, sentBuf2;
+    TUid     dataEventType = KLogPacketDataEventTypeUid;
+    TInt     err, index;
+
+    // First find out the data event type (GPRS or WLAN)
+    for ( index = 0; index < iConnections->Count(); index++ )
+        {
+        connId = iConnections->At( index )->iConnectionId;
+        if ( connId == aConnectionId )
+            {
+            dataEventType = iConnections->At( index )->iLogWrapEvent->EventType();
+
+            if ( aBytesSent == 0 && aBytesReceived == 0 )
+                {
+                break;
+                }
+
+            CRepository* repository = NULL;
+            repository = CRepository::NewL( KCRUidDCLLogs );
+            if ( repository )
+                {
+                err = repository->StartTransaction( CRepository::EConcurrentReadWriteTransaction );
+                if ( err )
+                    {
+                    LOGIT1("UpdateSharedDataL: StartTransaction() returned error: %d", err)
+                    delete repository;
+                    break;
+                    }
+
+                if ( aBytesReceived != 0 )
+                    {
+                    // Read current value.
+                    if ( dataEventType == KLogPacketDataEventTypeUid )
+                        {
+                        err = repository->Get( KLogsGPRSReceivedCounter, receivedBuf );
+                        }
+                    else
+                        {
+                        err = repository->Get( KLogsWLANReceivedCounter, receivedBuf );
+                        }
+                    if ( err == KErrNone )
+                        {
+                        TLex lex( receivedBuf );
+                        lex.Val( received );
+                        }
+                    else
+                        {
+                        LOGIT1("UpdateSharedDataL: aBytesReceived: Get() returned error: %d", err)
+                        repository->CancelTransaction();
+                        delete repository;
+                        break;
+                        }
+
+                    // Calculate the increment
+                    increment = aBytesReceived - iConnections->At( index )->iPrevDownValue;
+                    // And add _only_ the increment
+                    received += increment;
+                    // Update the previous downlink value
+                    iConnections->At( index )->iPrevDownValue = aBytesReceived;
+                    receivedBuf2.Num( received );
+
+                    // Store updated value.
+                    if ( dataEventType == KLogPacketDataEventTypeUid )
+                        {
+                        err = repository->Set( KLogsGPRSReceivedCounter, receivedBuf2 );
+                        }
+                    else
+                        {
+                        err = repository->Set( KLogsWLANReceivedCounter, receivedBuf2 );
+                        }
+                    if ( err != KErrNone )
+                        {
+                        LOGIT1("UpdateSharedDataL: aBytesReceived: Set() returned error: %d", err)
+                        repository->CancelTransaction();
+                        delete repository;
+                        break;
+                        }
+                    }
+                if ( aBytesSent != 0 )
+                    {
+                    // Read current value.
+                    if ( dataEventType == KLogPacketDataEventTypeUid )
+                        {
+                        err = repository->Get( KLogsGPRSSentCounter, sentBuf );
+                        }
+                    else
+                        {
+                        err = repository->Get( KLogsWLANSentCounter, sentBuf );
+                        }
+                    if ( err == KErrNone )
+                        {
+                        TLex lex( sentBuf );
+                        lex.Val( sent );
+                        }
+                    else
+                        {
+                        LOGIT1("UpdateSharedDataL: aBytesSent: Get() returned error: %d", err)
+                        repository->CancelTransaction();
+                        delete repository;
+                        break;
+                        }
+
+                    // Calculate the increment
+                    increment = aBytesSent - iConnections->At( index )->iPrevUpValue;
+                    // And add _only_ the increment
+                    sent += increment;
+                    // Update the previous uplink value
+                    iConnections->At( index )->iPrevUpValue = aBytesSent;
+                    sentBuf2.Num( sent );
+
+                    // Store updated value.
+                    if ( dataEventType == KLogPacketDataEventTypeUid )
+                        {
+                        err = repository->Set( KLogsGPRSSentCounter, sentBuf2 );
+                        }
+                    else
+                        {
+                        err = repository->Set( KLogsWLANSentCounter, sentBuf2 );
+                        }
+                    if ( err != KErrNone )
+                        {
+                        LOGIT1("UpdateSharedDataL: aBytesSent: Set() returned error: %d", err)
+                        repository->CancelTransaction();
+                        delete repository;
+                        break;
+                        }
+                    }
+                TUint32 keyInfo;
+                err = repository->CommitTransaction( keyInfo );
+                if ( err != KErrNone )
+                    {
+                    LOGIT2("UpdateSharedDataL: repository->CommitTransaction returned error: %d, %d", err, keyInfo)
+                    repository->CancelTransaction();
+                    delete repository;
+                    break;
+                    }
+                }
+            delete repository;
+            break;
+            }
+        } // for
+    LOGEXITFN("CEngine::UpdateSharedDataL()")
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::RunL
+// Handles the completion of an asynchronous request.
+// This function is defined as pure virtual in CActive and any class derived
+// from CActive must define and implement it.
+// --------------------------------------------------------------------------
+//
+void CEngine::RunL()
+    {
+    LOGENTRFN("CEngine::RunL()")
+
+    // Request has completed.
+    // Delete the disconnected element of iConnections, if it has already been
+    // logged and the connection has been disconnected
+    if ( iConnections->Count() > 0 )
+        {
+        LOGIT1("RunL: iConnections->Count() = %d (>0), clearing old connections", iConnections->Count())
+
+        // Ignore error - string blank on error which is ok.
+        TBuf<KLogMaxStatusLength> logStatusBuf;
+        iLogWrap->Log().GetString( logStatusBuf, R_LOG_CON_DISCONNECTED );
+
+        for ( TInt i = iConnections->Count()-1; i >= 0; i-- )
+            {
+            CEvent* elemPtr = iConnections->At( i );
+
+            __ASSERT_DEBUG( ( elemPtr != NULL ), User::Panic( KDCLName, KErrNotReady ) );
+            LOGIT2("Checking index %d, connection id %d", i, elemPtr->iConnectionId)
+            if ( logStatusBuf == elemPtr->iLogWrapEvent->Status() )
+                {
+                LOGIT0("Status: disconnected, removing")
+
+                // Remove the pointer from the queue.
+                iConnections->Delete( i );
+                // Delete the completed CEvent
+                delete elemPtr;
+                }
+            }
+        }
+
+    // Delete completed event and check if there is a next event pending.
+    // If LogEng is not supported, a dummy logeng just returns error straight
+    // on, but we carry on doing all the requests.
+    if ( iLogEventQueue->Count() > 0 )
+        {
+        LOGIT1("RunL: iLogEventQueue->Count() = %d (>0), processing next event", iLogEventQueue->Count())
+
+        CEvent* nextEventPtr = iLogEventQueue->At( 0 );
+        __ASSERT_DEBUG( ( nextEventPtr != NULL ), User::Panic( KDCLName, KErrNotReady ) );
+        // In general, before the elements of this kind of array are deleted,
+        // the CBase derived objects to which those elements point should be
+        // destroyed. If they are not destroyed, then a separate copy of
+        // those elements (i.e. the pointers), must be taken to avoid
+        // orphaning the CBase derived objects on the heap.
+        iCurrentLogEvent->CopyL( *nextEventPtr->iLogWrapEvent );
+        iLogWrap->Log().ChangeEvent( *iCurrentLogEvent, iStatus );
+        SetActive();
+        // Remove the pointer from the queue.
+        iLogEventQueue->Delete( 0 );
+        // Delete the completed CEvent
+        delete nextEventPtr;
+        }
+    LOGEXITFN("CEngine::RunL()")
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::DoCancel
+// Handles a cancel request to the service provider.
+// This function is defined as pure virtual in CActive and any class derived
+// from CActive must define and implement it.
+// --------------------------------------------------------------------------
+//
+void CEngine::DoCancel()
+    {
+    if ( iLogWrap )
+        {
+        iLogWrap->Log().Cancel();
+        }
+    // Usually you do not need to cancel an update on events, just let them
+    // go and be removed from the queue when update is done.
+    // If we cancel the logger, most likely the whole Logger Object will be
+    // destroyed.
+}
+
+// --------------------------------------------------------------------------
+// CEngine::SetAttachModeL
+// Gets the Attach Mode setting from CommDb and sets ETel to use that value.
+// --------------------------------------------------------------------------
+//
+void CEngine::SetAttachModeL() const
+    {
+    LOGENTRFN("CEngine::SetAttachModeL()")
+
+    TUint32 commdbAM = RPacketService::EAttachWhenNeeded;
+    TRequestStatus status;
+    RPacketService::TAttachMode etelAM;
+    CCommsDatabase* commDb = NULL;
+
+    if ( iPacketServLoaded != 1 )
+        {
+        LOGIT0("RPacketService not loaded")
+        return;
+        }
+
+    commDb = CCommsDatabase::NewL();
+
+    // Get the Attach Mode setting from CommDb
+    TRAPD( error, commDb->GetGlobalSettingL( TPtrC( GPRS_ATTACH_MODE ), commdbAM ) );
+    switch ( error )
+        {
+        case KErrNone:
+            // Attach Mode setting found in CommDb
+            break;
+        case KErrNotFound:
+            {
+            // Attach Mode setting not found in CommDb, it is set as EAttachWhenNeeded
+            TRAPD( leaveCode, commDb->SetGlobalSettingL( TPtrC( GPRS_ATTACH_MODE ), commdbAM ) );
+            if ( leaveCode )
+                {
+                LOGIT1("FAILED SetGlobalSettingL() <%d>", leaveCode)
+                }
+            }
+            break;
+        default:
+            {
+            LOGIT1("FAILED to get attach mode from CommDb <%d>", error)
+            }
+            break;
+        }
+
+    // And set ETel to use the Attach Mode value from CommDb
+    etelAM = STATIC_CAST( RPacketService::TAttachMode, commdbAM );
+
+    TInt err( KErrNotReady );
+    TInt a = 0;
+    while ( a < KPhoneRetryCount && err != KErrNone )
+        {
+        if ( a )
+            {
+            User::After( KPhoneRetryTimeout ); // Don't wait on first try
+            }
+        iPacketService.SetAttachMode( status, etelAM );
+        User::WaitForRequest( status );
+        err = status.Int();
+        LOGIT1("Set attach Mode to ETel <%d>", err)
+        a++;
+        }
+    if ( err != KErrNone )
+        {
+        LOGIT1("FAILED to set attach mode to ETel <%d>", err)
+        }
+    delete commDb;
+    LOGEXITFN("CEngine::SetAttachModeL()")
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::SetAPNL
+// Gets the default Access Point Name from CommDb and
+// sets ETel to use that APN.
+// --------------------------------------------------------------------------
+//
+void CEngine::SetAPNL() const
+    {
+    LOGENTRFN("CEngine::SetAPNL()")
+
+    TBuf<KMaxAPName> apName;
+    TRequestStatus status( KErrNotReady );
+    CCommsDatabase* commDb = NULL;
+
+    if ( iPacketServLoaded != 1 )
+        {
+        LOGIT0("RPacketService not loaded")
+        return;
+        }
+
+    commDb = CCommsDatabase::NewL();
+    CleanupStack::PushL( commDb );
+
+    // Get the default Access Point Name from CommDb
+    CCommsDbTableView* table = commDb->OpenTableLC( TPtrC( DEFAULT_GPRS ) );
+
+    table->GotoFirstRecord();
+
+    //If APN is not initialized, ReadTextL will leave
+    apName.SetLength( 0 );
+
+    table->ReadTextL( TPtrC( DEFAULT_GPRS_APN ), apName );
+
+    CleanupStack::PopAndDestroy( table );
+
+    // Get DefaultContextParams from ETel
+    RPacketContext::TContextConfigGPRS* getParams = NULL;
+    getParams = new( ELeave ) RPacketContext::TContextConfigGPRS();
+
+    TPckg<RPacketContext::TContextConfigGPRS> getParamsPckg( *getParams );
+
+    TInt err( KErrNotReady );
+    TInt a = 0;
+    while ( a < KPhoneRetryCount && err != KErrNone )
+        {
+        // The RPacketService::GetDefaultContextParams() does not always work
+        // with the first trial, it might return KErrNotReady.
+        if ( a )
+            {
+            User::After( KPhoneRetryTimeout ); // Don't wait on first try
+            }
+        iPacketService.GetDefaultContextParams( status, getParamsPckg );
+        User::WaitForRequest( status );
+        err = status.Int();
+        LOGIT1("Got DefaultContextParams from ETel <%d>", err)
+        a++;
+        }
+
+    if ( err != KErrNone )
+        {
+        LOGIT1("FAILED to get DefaultContextParams from ETel <%d>", err)
+        }
+
+    // Replace ETel APN with CommDb APN
+    ReplaceAPN( getParams->iAccessPointName, apName );
+
+    // Set DefaultContextParams to ETel
+    iPacketService.SetDefaultContextParams( status, getParamsPckg );
+    User::WaitForRequest( status );
+
+    err = status.Int();
+    if ( err != KErrNone )
+        {
+        LOGIT1("FAILED to set DefaultContextParams to ETel <%d>", err)
+        }
+
+    delete getParams;
+    CleanupStack::PopAndDestroy( commDb );
+    LOGEXITFN("CEngine::SetAPNL()")
+    }
+
+// --------------------------------------------------------------------------
+// CEngine::AddEventTypeL
+// Adds the event type Wlan. Otherwise the LogClient
+// will not understand this type of event.
+// --------------------------------------------------------------------------
+//
+void CEngine::AddEventTypeL()
+    {
+    iLogEventType = CLogEventType::NewL();
+    iLogEventType->SetUid( KLogWlanDataEventTypeUid );
+    iLogEventType->SetDescription( _L("Wlan") );
+    iLogEventType->SetLoggingEnabled( ETrue );
+
+    iStatus = KRequestPending;
+    iLogClient->AddEventType( *iLogEventType, iStatus );
+
+    SetActive();
+    }
+
+// -----------------------------------------------------------------------------
+// CEngine::ReplaceAPN
+// This method will be used in platforms where ETel APN (aResult) is UNICODE.
+// -----------------------------------------------------------------------------
+//
+void CEngine::ReplaceAPN( TDes& aResult, const TDesC& aName ) const
+    {
+    aResult = aName;
+    }
+
+// -----------------------------------------------------------------------------
+// CEngine::ReplaceAPN
+// This method will be used in platforms where ETel APN (aResult) is UTF8.
+// -----------------------------------------------------------------------------
+//
+void CEngine::ReplaceAPN( TDes8& aResult, const TDesC& aName ) const
+    {
+    CnvUtfConverter::ConvertFromUnicodeToUtf8( aResult, aName );
+    }
+
+// -----------------------------------------------------------------------------
+// CEngine::LogDataInTimerModeL
+// -----------------------------------------------------------------------------
+//
+TInt CEngine::LogDataInTimerModeL( const TUint aConnectionId )
+    {
+    LOGENTRFN("CEngine::LogDataInTimerModeL()")
+    TInt index( 0 );
+    TInt64 prevDown( 0 );
+    TInt64 prevUp( 0 );
+
+    TInt count( iConnections->Count() );
+
+    LOGIT1("LogDataInTimerMode, id %d", aConnectionId)
+
+    // Does the connection still exist
+    for ( index = 0; index < count; index++ )
+        {
+        TUint connId( iConnections->At( index )->iConnectionId );
+
+        if ( connId == aConnectionId )
+            {
+            prevDown = iConnections->At(index)->iPrevDownValue;
+            prevUp = iConnections->At(index)->iPrevUpValue;
+            break;
+            }
+        }
+
+    if ( index == count )
+        {
+        return KErrNotFound;
+        }
+
+    // Read data volumes
+    TRequestStatus status;
+    TUint uplinkData( 0 );
+    TUint downlinkData( 0 );
+
+    // Get the amount uplink data from CM server
+    iConnectionMonitor.GetUintAttribute(
+            aConnectionId,
+            KSubConnectionId,
+            KUplinkData,
+            uplinkData,
+            status );
+    User::WaitForRequest( status );
+
+    if ( status.Int() != KErrNone )
+        {
+        LOGIT1("FAILED to get KUplinkData from ConnMon <%d>", status.Int())
+        }
+
+    // Get the amount of downlink data from CM server
+    iConnectionMonitor.GetUintAttribute(
+            aConnectionId,
+            KSubConnectionId,
+            KDownlinkData,
+            downlinkData,
+            status );
+    User::WaitForRequest( status );
+
+    if ( status.Int() != KErrNone )
+        {
+        LOGIT1("FAILED to get KDownlinkData from ConnMon <%d>", status.Int())
+        }
+
+    // Update SharedData downlink and uplink data
+    UpdateSharedDataL( aConnectionId, uplinkData, downlinkData );
+
+    TInt ret = KErrNone;
+    // The actual status of connection is R_LOG_CON_CONNECTED, but
+    // due to the performance reasons KConnectionStatusIdNotAvailable
+    // is used here. There is no need to read LOGWRAP.RSC every time.
+    ret = LogDataUpdateEventL(
+            aConnectionId,
+            KConnectionStatusIdNotAvailable,
+            TUid::Null(),
+            uplinkData,
+            downlinkData );
+    if ( ret != KErrNone )
+        {
+        LOGIT1("FAILED to update log data (timer mode) <%d>", ret)
+        }
+
+    // Check data volumes
+    TUint threshold( iGPRSThreshold );
+
+    ret = GetDefaultThreshold( aConnectionId, threshold );
+
+    if ( ret != KErrNotFound )
+        {
+        // If the increase both in uplink and downlink data volume is less than threshold/2
+        // switch the connection back to the threshold mode.
+        if ( ( ( iConnections->At(index)->iPrevDownValue - prevDown ) < threshold/2 )
+               &&
+               ( ( iConnections->At(index)->iPrevUpValue - prevUp ) < threshold/2 ))
+            {
+            SwitchToThresholdMode( aConnectionId, threshold );
+
+            // Return an error to stop the timer mode for this connection
+            ret = KErrCancel;
+            }
+        else
+            {
+            ret = KErrNone;
+            }
+        }
+    LOGEXITFN1("CEngine::LogDataInTimerModeL()", ret)
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CEngine::SwitchToThresholdMode
+// -----------------------------------------------------------------------------
+//
+void CEngine::SwitchToThresholdMode( const TUint aConnectionId, const TUint aThreshold  )
+    {
+    LOGENTRFN("CEngine::SwitchToThresholdMode()")
+    // Set thresholds to start the threshold mode
+    TUint threshold( aThreshold );
+
+    if ( threshold == 0 )
+        {
+        TInt ret = GetDefaultThreshold( aConnectionId, threshold );
+
+        if ( ret == KErrNotFound )
+            {
+            // Connection has closed
+            return;
+            }
+        }
+
+    iConnectionMonitor.SetUintAttribute(
+            aConnectionId,
+            KSubConnectionId,
+            KDownlinkDataThreshold,
+            threshold );
+
+    iConnectionMonitor.SetUintAttribute(
+            aConnectionId,
+            KSubConnectionId,
+            KUplinkDataThreshold,
+            threshold );
+
+    LOGIT1("Switched to threshold mode, id %d", aConnectionId)
+
+    LOGEXITFN("CEngine::SwitchToThresholdMode()")
+    }
+
+// -----------------------------------------------------------------------------
+// CEngine::SwitchToTimerMode
+// -----------------------------------------------------------------------------
+//
+void CEngine::SwitchToTimerMode( const TUint aConnectionId )
+    {
+    LOGENTRFN("CEngine::SwitchToTimerMode()")
+    if ( iDclTimerAO != 0 )
+        {
+        // Set thresholds to zero.
+        iConnectionMonitor.SetUintAttribute(
+                aConnectionId,
+                KSubConnectionId,
+                KDownlinkDataThreshold,
+                0 );
+
+        iConnectionMonitor.SetUintAttribute(
+                aConnectionId,
+                KSubConnectionId,
+                KUplinkDataThreshold,
+                0 );
+
+        iDclTimerAO->Add( aConnectionId );
+
+        LOGIT1("Switched to timer mode, id %d", aConnectionId)
+        }
+    LOGEXITFN("CEngine::SwitchToTimerMode()")
+    }
+
+// -----------------------------------------------------------------------------
+// CEngine::GetDuration
+// Retrieves iPrevDuration from connection in connection table with matching id.
+// -----------------------------------------------------------------------------
+//
+TBool CEngine::GetDuration( const TUint aConnectionId, TInt& aDuration )
+    {
+    TInt index( 0 );
+
+    for ( index = 0; index < iConnections->Count(); index++ )
+        {
+        TUint connId( iConnections->At( index )->iConnectionId );
+
+        if ( aConnectionId == connId )
+            {
+            aDuration = iConnections->At( index )->iPrevDuration;
+            return ETrue;
+            }
+        }
+
+    LOGIT1("FAILED to get duration for connection id %d", aConnectionId)
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CEngine::GetDefaultThreshold
+// -----------------------------------------------------------------------------
+//
+TInt CEngine::GetDefaultThreshold( const TUint aConnectionId, TUint& aThreshold )
+    {
+    LOGENTRFN("CEngine::GetDefaultThreshold()")
+    TInt bearer( 0 );
+    TRequestStatus status( 0 );
+
+    // Initialize to the smallest value
+    aThreshold = iGPRSThreshold;
+
+    iConnectionMonitor.GetIntAttribute(
+            aConnectionId,
+            KSubConnectionId,
+            KBearer,
+            bearer,
+            status );
+    User::WaitForRequest( status );
+
+    if ( status.Int() != KErrNotFound )
+        {
+        if ( bearer == EBearerWCDMA || bearer == EBearerExternalWCDMA )
+            {
+            aThreshold = iWCDMAThreshold;
+            }
+        else if ( bearer == EBearerWLAN || bearer == EBearerExternalWLAN )
+            {
+            aThreshold = iWLANThreshold;
+            }
+        else
+            {
+            aThreshold = iGPRSThreshold;
+            }
+        }
+
+    LOGEXITFN1("CEngine::GetDefaultThreshold()", status.Int())
+    return status.Int();
+    }
+
+// -----------------------------------------------------------------------------
+// CEngine::ReadIniFile
+// -----------------------------------------------------------------------------
+//
+void CEngine::ReadIniFile()
+    {
+    LOGENTRFN("CEngine::ReadIniFile()")
+    TInt err( KErrNone );
+    TInt value( 0 );
+
+    // Initialize parameters to defaults because they might not be in SharedData.
+    iTimerInterval  = KTimerInterval;
+    iGPRSThreshold  = KGPRSDataThreshold;
+    iWCDMAThreshold = KWCDMADataThreshold;
+    iWLANThreshold  = KWLANDataThreshold;
+
+    // Connecting and initialization:
+    CRepository* repository = NULL;
+
+    TRAPD( leaveCode, repository = CRepository::NewL( KCRUidDCL ) );
+
+    if ( leaveCode )
+        {
+        LOGIT1("CRepository::NewL() FAILED: %d", leaveCode)
+        // Go on using defaults
+        return;
+        }
+
+    err = repository->Get( KDCLGprsThreshold, value );
+
+    if ( err == KErrNone )
+        {
+        iGPRSThreshold = value;
+        }
+    else
+        {
+        LOGIT1("Reading KDCLGprsThreshold from CRepository  FAILED: %d", err)
+        }
+
+    err = repository->Get( KDCLWcdmaThreshold, value );
+
+    if ( err == KErrNone )
+        {
+        iWCDMAThreshold = value;
+        }
+     else
+        {
+        LOGIT1("Reading KDCLWcdmaThreshold from CRepository  FAILED: %d", err)
+        }
+
+    err = repository->Get( KDCLWlanThreshold, value );
+
+    if ( err == KErrNone )
+        {
+        iWLANThreshold = value;
+        }
+    else
+        {
+        LOGIT1("Reading KDCLWlanThreshold from CRepository  FAILED: %d", err)
+        }
+
+    err = repository->Get( KDCLTimerInterval, value );
+
+    if ( err == KErrNone )
+        {
+        iTimerInterval = value;
+        }
+    else
+        {
+        LOGIT1("Reading KDCLTimerInterval from CRepository  FAILED: %d", err)
+        }
+
+    // Closing connection:
+    delete repository;
+    LOGEXITFN("CEngine::ReadIniFile()")
+    }
+
+// End of file