connectionmonitoring/connmon/connectionmonitor/src/ConnMonIAP.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 03 May 2010 12:53:07 +0300
changeset 20 9c97ad6591ae
parent 18 fcbbe021d614
child 44 a0c4ceac30d0
child 53 4af712113915
permissions -rw-r--r--
Revision: 201015 Kit: 201018

/*
* Copyright (c) 2002-2009 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:  Core functionality for ConnMon.
*
*/

#include <mmtsy_names.h>
#include <featmgr.h>
#include <rmmcustomapi.h>
#include <utf.h>
#include <es_sock_partner.h>

#include "ConnMonServ.h"
#include "ConnMonSess.h"
#include "CEventQueue.h"
#include "CCsdFax.h"
#include "CPsdFax.h"
#include "ConnMonIAP.h"
#include "ConnMonNoti.h"
#include "CDataVolume.h"
#include "connmondtmnoti.h"
#include "connmontelnoti.h"
#include "ConnMonBearerNotifier.h"
#include "log.h"
#include "cellulardatausagekeyupdater.h"

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// TConnInfo::TConnInfo
// -----------------------------------------------------------------------------
//
TConnInfo::TConnInfo(
        TInt aIapId,
        TInt aNetId,
        TUint aConnectionId,
        TInt aBearer,
        TBearerInfo aBearerInfo )
        :
        iIapId( aIapId ),
        iNetId( aNetId ),
        iConnectionId( aConnectionId ),
        iBearer( aBearer ),
        iConnAttach( 0 ),
        iProgressNotifier( 0 ),
        iDLDataNotifier( 0 ),
        iULDataNotifier( 0 ),
        iDataVolumeAO( 0 ),
        iConnDownNotifier( 0 ),
        iActivityNotifier( 0 ),
        iActivity( 0 ),
        iBearerInfo( aBearerInfo ),
        iBearerNotifier( 0 )
    {
    }

// -----------------------------------------------------------------------------
// TConnInfo::Reset
// -----------------------------------------------------------------------------
//
void TConnInfo::Reset()
    {
    // Only call this function to initialize a newly created TConnInfo-object.
    // (There is no cleanup)
    iIapId            = 0;
    iNetId            = 0;
    iConnectionId     = 0;
    iBearer           = EBearerUnknown;
    iBearerInfo.iBearer = EBearerInfoUnknown;
    iBearerInfo.iInternal = ETrue;
    iProgressNotifier = 0;
    iDLDataNotifier   = 0;
    iULDataNotifier   = 0;
    iDataVolumeAO     = 0;
    iConnAttach       = 0;
    iConnDownNotifier = 0;
    iActivityNotifier = 0;
    iActivity         = 0;
    iBearerNotifier   = 0;
    }

// -----------------------------------------------------------------------------
// TConnInfo::Compare
// Compares two TConnInfo items (by connection id).
// -----------------------------------------------------------------------------
//
TInt TConnInfo::Compare( const TConnInfo& aFirst, const TConnInfo& aSecond )
    {
    if ( aFirst.iConnectionId < aSecond.iConnectionId )
        {
        return -1;
        }

    if ( aFirst.iConnectionId > aSecond.iConnectionId )
        {
        return 1;
        }
    return 0;
    }

// -----------------------------------------------------------------------------
// TConnInfo::MatchId
// Finds TConnInfo item matching by connection Id.
// -----------------------------------------------------------------------------
//
TBool TConnInfo::MatchId( const TConnInfo& aFirst, const TConnInfo& aSecond )
    {
    if ( aFirst.iConnectionId == aSecond.iConnectionId )
        {
        return ETrue;
        }
    return EFalse;
    }

// -----------------------------------------------------------------------------
// TConnInfo::MatchIap
// Finds TConnInfo item matching by iap id and net id.
// -----------------------------------------------------------------------------
//
TBool TConnInfo::MatchIap( const TConnInfo& aFirst, const TConnInfo& aSecond )
    {
    // Only internal bearers can be matched by IapId and NetId
    if ( ( aFirst.iIapId == aSecond.iIapId ) && ( aFirst.iNetId == aSecond.iNetId ) &&
         ( aFirst.iBearer < EBearerExternalCSD ) && ( aSecond.iBearer < EBearerExternalCSD ) &&
         ( aFirst.iBearerInfo.iInternal ) && ( aSecond.iBearerInfo.iInternal ) )
        {
        return ETrue;
        }

    return EFalse;
    }

// -----------------------------------------------------------------------------
// TConnInfo::MatchBearer
// Finds TConnInfo item matching by bearer.
// -----------------------------------------------------------------------------
//
TBool TConnInfo::MatchBearer( const TConnInfo& aFirst, const TConnInfo& aSecond )
    {
    // External CSD bearers (there is no event availabe for bearer change)
    if ( ( aFirst.iBearer == EBearerExternalCSD || aFirst.iBearer == EBearerExternalHSCSD ||
           aFirst.iBearer == EBearerExternalWcdmaCSD )
         &&
         ( aSecond.iBearer == EBearerExternalCSD || aSecond.iBearer == EBearerExternalHSCSD ||
           aSecond.iBearer == EBearerExternalWcdmaCSD ) )
        {
        return ETrue;
        }

    // External PSD bearers (there is not always an event availabe for bearer change)
    else if ( ( aFirst.iBearer == EBearerExternalGPRS     ||
                aFirst.iBearer == EBearerExternalEdgeGPRS ||
                aFirst.iBearer == EBearerExternalWCDMA    ||
                aFirst.iBearer == EBearerExternalCDMA2000 ||
                ( !aFirst.iBearerInfo.iInternal &&
                  ( aFirst.iBearerInfo.iBearer == EBearerInfoHSDPA ||
                    aFirst.iBearerInfo.iBearer == EBearerInfoHSUPA ||
                    aFirst.iBearerInfo.iBearer == EBearerInfoHSxPA ) ) )
              &&
              ( aSecond.iBearer == EBearerExternalGPRS     ||
                aSecond.iBearer == EBearerExternalEdgeGPRS ||
                aSecond.iBearer == EBearerExternalWCDMA    ||
                aSecond.iBearer == EBearerExternalCDMA2000 ||
                ( !aSecond.iBearerInfo.iInternal &&
                  ( aSecond.iBearerInfo.iBearer == EBearerInfoHSDPA ||
                    aSecond.iBearerInfo.iBearer == EBearerInfoHSUPA ||
                    aSecond.iBearerInfo.iBearer == EBearerInfoHSxPA ) ) ) )

        {
        return ETrue;
        }

    // Other bearers
    else if ( aFirst.iBearer == aSecond.iBearer &&
            aFirst.iBearerInfo.iBearer == aSecond.iBearerInfo.iBearer )
        {
        return ETrue;
        }
    else
        {
        return EFalse;
        }
    }

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CConnMonIAP::CConnMonIAP
// -----------------------------------------------------------------------------
//
CConnMonIAP::CConnMonIAP( CConnMonServer* aServer )
        :
        iServer( aServer ),
        iEndUserNetIds( KNullDesC8 )
    {
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::ConstructL
// -----------------------------------------------------------------------------
//
void CConnMonIAP::ConstructL()
    {
    LOGENTRFN("CConnMonIAP::ConstructL()")
    TInt err( KErrNone );

    // Connect to socket server and use system global pool (-1) for message slots.
    User::LeaveIfError( iSocketServer.Connect( static_cast<TUint>( -1 ) ) );
    LOGIT("(01/11) Loaded OK: ESock")

    // Open RConnection. This object is not attached to any connection
    User::LeaveIfError( iConnection.Open( iSocketServer ) );
    LOGIT("(02/11) Opened OK: RConnection")

    // Connect to ETel server
    TBuf<KCommsDbSvrMaxColumnNameLength> tsyName;
    tsyName.Copy( KMmTsyModuleName );

    // The RTelServer::Connect() might not always work with the first trial,
    // because of a coding error related to using semaphores in the method.
    for ( TInt a = 0; a < KPhoneRetryCount; a++ )
        {
        err = iTelServer.Connect();
        if ( KErrNone == err )
            {
            break;
            }
        User::After( KPhoneRetryTimeout );
        LOGIT("RTelServer::Connect() failed, trying again.")
        }
    User::LeaveIfError( err );
    LOGIT("(03/11) Loaded OK: ETel")

    // Initialize FeatureManager
    FeatureManager::InitializeLibL();
    LOGIT("(04/11) Loaded OK: FeatureManager")

    // Try to load tsy
    err = iTelServer.LoadPhoneModule( tsyName );
    if ( KErrNone == err )
        {
        LOGIT("(05/11) Loaded OK: TSY")
        iTSYLoaded = 1;

        // Phone info can be retrieved with value 0 if there is only one phone
        RTelServer::TPhoneInfo info;
        User::LeaveIfError( iTelServer.GetPhoneInfo( 0, info ) );
        LOGIT("(06/11) Loaded OK: Phone info")

        User::LeaveIfError( iMobilePhone.Open( iTelServer, info.iName ) );
        LOGIT("(07/11) Opened OK: RMobilePhone")

        // Open packet service
        err = iPacketService.Open( iMobilePhone );
        if ( KErrNone == err )
            {
            LOGIT("(08/11) Loaded OK: Packet service")
            iPacketServLoaded = 1;

            // CDMA network does not support external connections. PSD Fax handler module
            // should not be created when in CDMA network. The code below works OK as long
            // as there is no phone that supports both CDMA and GSM at the same time.
            if ( !FeatureManager::FeatureSupported( KFeatureIdProtocolCdma ) )
                {
                // Create PSD Fax handler module
                iPsdFax = new( ELeave ) CPsdFax(
                        iServer,
                        &iTelServer,
                        &iMobilePhone,
                        &iPacketService );
                iPsdFax->ConstructL();
                LOGIT("(09/11) Loaded OK: PSD module")
                }
            else
                {
                LOGIT("(09/11) Nosupport: PSD module not loaded, no PSD support in CDMA networks.")
                }
            }
        else
            {
            LOGIT1("(08/11) Loaderror: Packet service failed with code <%d>", err)
            }

        // CDMA network does not support external connections. CSD Fax handler module
        // should not be created when in CDMA network. The code below works OK as long
        // as there is no phone that supports both CDMA and GSM at the same time.
        if ( !FeatureManager::FeatureSupported( KFeatureIdProtocolCdma ) )
            {
            // Create CSD Fax handler module
            iCsdFax = new( ELeave ) CCsdFax( iServer, &iTelServer, &iMobilePhone );
            iCsdFax->ConstructL();
            LOGIT("(10/11) Loaded OK: CSD module")
            }
        else
            {
            LOGIT("(10/11) Nosupport: CSD module not loaded, no CSD support in CDMA networks")
            }
        }
    else
        {
        LOGIT1("(05/11) Loaderror: TSY failed with code <%d>", err)
        }

    // Open WLAN Management service
    if ( FeatureManager::FeatureSupported( KFeatureIdProtocolWlan ) )
        {
        TRAPD( leaveCode, iWlanSupport = CWlanSupport::NewL( iServer ) );
        if ( KErrNone != leaveCode )
            {
            LOGIT1("(11/11) Loaderror: WLAN module failed with code <%d>", leaveCode)
            }
        else
            {
            LOGIT("(11/11) Loaded OK: WLAN module")
            }
        }
    else
        {
        LOGIT("(11/11) Nosupport: WLAN module not loaded, no WLAN support detected")
        }

    LOGEXITFN("CConnMonIAP::ConstructL()")
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::~CConnMonIAP
// -----------------------------------------------------------------------------
//
// Destructor
CConnMonIAP::~CConnMonIAP()
    {
    LOGENTRFN("CConnMonIAP::~CConnMonIAP()")
    // Delele dial up modules.
    delete iCsdFax;
    iCsdFax = NULL;

    delete iPsdFax;
    iPsdFax = NULL;

    // Delete global notifications. This must be called before
    // services are closed or destroyed below.
    DeleteNotifications();

    // Delete connection up/down notification.
    if ( iConnUpDownNotifier != 0 )
        {
        iConnUpDownNotifier->Cancel();
        delete iConnUpDownNotifier;
        }

    // Close all attached connections
    TInt count = iConnInfos.Count();

    for ( TInt i = 0; i < count; i++ )
        {
        if ( iConnInfos[i].iConnAttach != 0 )
            {
            iConnInfos[i].iConnAttach->Close();
            delete iConnInfos[i].iConnAttach;
            }
        }

    // Note. all sessions have closed by now.
    // There is no need to delete connection parameters
    // because session destructors have already done that.
    iConnInfos.Close();

    // Close "global" ESOCK objects
    iConnection.Close();
    iSocketServer.Close();

    // Close "global" ETEL objects
    if ( iPacketServLoaded == 1 )
        {
        iPacketService.Close();
        }

    iMobilePhone.Close();
    iTelServer.Close();

    // Unload FeatureManager
    FeatureManager::UnInitializeLib();

    // Destroy WLAN service
    delete iWlanSupport;
    iWlanSupport = NULL;

    // Reset global pointers
    iServer                        = NULL;
    iPsdNetwStatusNotifier         = NULL;
    iNetwRegistrationNotifier      = NULL;
    iEdgeNotifier                  = NULL;
    iWcdmaNotifier                 = NULL;
    iModeNotifier                  = NULL;
    iGSMSignalNotifier             = NULL;
    iGSMBearerAvailabilityNotifier = NULL;

    // Clean up all ECom sessions
    // More info about it: TSW EGUO-64LD36
    REComSession::FinalClose();
    LOGEXITFN("CConnMonIAP::~CConnMonIAP()")
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::EnumerateConnections
// Enumerates active connections using RConnection API.
// Refreshes iConnInfos array (server view) with the latest information.
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::EnumerateConnections( TUint& aCount )
    {
    // Server must be 'blocked' while updating the connection table.
    TConnectionInfoBuf connInfoBuf;
    TBearerInfo bearerInfo;
    TConnInfo connInfo( 0, 0, 0, 0, bearerInfo );
    TInt err( KErrNone );

    aCount = 0;
    RArray<TConnInfo> tempArray;

    // Get existing external (fax) CSD connections
    // These can't be enumerated from ETEL at the moment
    if ( iCsdFax )
        {
        // In practise there can be only ONE fax connection of this type
        connInfo.Reset();
        connInfo.iBearer = EBearerExternalCSD; // This will match any ext-CSD
        connInfo.iBearerInfo.iBearer = EBearerInfoCSD;
        connInfo.iBearerInfo.iInternal = EFalse;

        TInt index = iConnInfos.Find( connInfo, TConnInfo::MatchBearer );
        if ( ( KErrNotFound != index ) && iCsdFax->IsValid() )
            {
            // Add to temp array
            tempArray.Append( iConnInfos[index] );
            aCount++;
            }
        else if ( !iConnUpDownNotifier )
            {
            // Try to find out about external CSD connections
            // that were alive before CM server started.
            // The code below will be executed only when
            // this method is called for the first time.
            err = iCsdFax->FindCall();
            if ( KErrNone == err )
                {
                iCsdFax->GetBearer( connInfo.iBearer, connInfo.iBearerInfo );
                connInfo.iConnectionId = NewConnectionId(); // New unique Id
                iCsdFax->SetConnectionId( connInfo.iConnectionId );
                tempArray.Append( connInfo );
                aCount++;
                }
            }
        }

    // Get existing external (fax) PSD connections
    // These connections can't be enumerated from ETEL at the moment
    // Only notification of a new connection is available from ETEL.
    if ( iPsdFax )
        {
        connInfo.Reset();
        connInfo.iBearer = EBearerExternalGPRS; // This will match any ext-PSD
        connInfo.iBearerInfo.iBearer = EBearerInfoGPRS;
        connInfo.iBearerInfo.iInternal = EFalse;

        // Check all external PSD connections
        for ( TUint index = 0; index < iConnInfos.Count(); index++ )
            {
            // Check that connection bearer is external PSD
            if ( iConnInfos[index].iBearer == EBearerExternalGPRS       ||
                 iConnInfos[index].iBearer == EBearerExternalEdgeGPRS   ||
                 iConnInfos[index].iBearer == EBearerExternalWCDMA      ||
                 iConnInfos[index].iBearer == EBearerExternalCDMA2000   ||
                 ( !iConnInfos[index].iBearerInfo.iInternal &&
                   ( iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSDPA ||
                     iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSUPA ||
                     iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSxPA ) ) )
                {
                // Check if connection is still valid
                if ( iPsdFax->IsValid( iConnInfos[index].iConnectionId ) )
                    {
                    // Add to temp array
                    tempArray.Append( iConnInfos[index] );
                    aCount++;
                    }
                }
            }

        if ( !iConnUpDownNotifier )
            {
            for( TUint index = 0; index < KMaxPsdConnectionCount; index++ )
                {
                // Try to find out about external PSD connections
                // that were alive before CM server started.
                // The code below will be executed only when
                // this method is called for the first time.
                TBuf<KMaxName> tempName( KExternalName );

                // Add connection number to string if index is > 1
                if ( index > 0 )
                    {
                    tempName.AppendNum( index+1 );
                    }

                // Try to open connection context
                err = iPsdFax->OpenContext( index, tempName );
                if ( KErrNone == err )
                    {
                    iPsdFax->GetBearer( connInfo.iBearer, connInfo.iBearerInfo );
                    connInfo.iConnectionId = NewConnectionId(); // New unique Id
                    err = iPsdFax->SetConnectionId( index, connInfo.iConnectionId );
                    if ( KErrNone == err )
                        {
                        tempArray.Append( connInfo );
                        aCount++;
                        }
                    }
                }
            }
        }

    const TUint initialCount = iConnInfos.Count();
    __ASSERT_DEBUG( ( aCount == static_cast<TUint>( tempArray.Count() ) ),
            PanicServer( EIapArrayError ) );

    TUint k( 0 );
    // Remove resources owned by obsolete connections
    for ( k = 0; k < initialCount; k++ )
        {
        TInt index( KErrNotFound );

        if ( iConnInfos[k].iBearer < EBearerExternalCSD )
            {
            index = tempArray.Find( iConnInfos[k], TConnInfo::MatchIap ); // Internal
            }
        else
            {
            index = tempArray.Find( iConnInfos[k], TConnInfo::MatchBearer ); // External
            }

        if ( KErrNotFound == index )
            {
            TBool deleteSent( ETrue );

            if ( iConnInfos[k].iConnDownNotifier != 0 )
                {
                deleteSent = iConnInfos[k].iConnDownNotifier->DeleteSent();
                }

            TInt connStatus( 0 );
            TInt ret = GetConnectionStatus( k, connStatus );

            if ( ( ( KErrNone != ret ) || ( connStatus == 0 ) ) && deleteSent )
                {
                LOGIT3("Removing old connection, index %d, id %d, bearer %d",
                        k, iConnInfos[k].iConnectionId, iConnInfos[k].iBearer)
                iServer->RemoveConnSettingsFromSessions( iConnInfos[k].iConnectionId );
                DeleteConnNotifications( k );

                // Close attached connection
                if ( iConnInfos[k].iConnAttach != 0 )
                    {
                    iConnInfos[k].iConnAttach->Close();
                    delete iConnInfos[k].iConnAttach;
                    }
                }
            else
                {
                // Add connection to temp array because connection status is valid.
                tempArray.Append( iConnInfos[k] );
                aCount++;
                }
            }
        }

    // Replace old iConnInfos array with tempArray
    // Reserve enough room
    for ( TUint i = initialCount; i < aCount; i++ )
        {
        TInt error = iConnInfos.Append( tempArray[0] );
        if ( error )
            {
            // Rollback reserved entries
            for ( TUint j = i; j > initialCount; j-- )
                {
                iConnInfos.Remove( j-1 );
                }
            tempArray.Reset();
            tempArray.Close();
            return error;
            }
        }

    // Safe from leaves from here. Copy over new contents
    iConnInfos.Reset();
    for ( k = 0; k < aCount; k++ )
        {
        iConnInfos.Append( tempArray[k] );
        }

    // Print connection info array to log
    #ifdef _DEBUG
    LOGIT("EnumerateConnections: Connection info array:")
    for ( TInt m = 0; m < iConnInfos.Count(); m++ )
        {
        LOGIT4("    id %d, bearer %d, iapId %d, netId %d", iConnInfos[m].iConnectionId,
                iConnInfos[m].iBearer, iConnInfos[m].iIapId, iConnInfos[m].iNetId)
        }
    #endif // _DEBUG

    tempArray.Reset();
    tempArray.Close();

    err = KErrNone;
    // Start connection up/down notifier if not already running
    if ( !iConnUpDownNotifier )
        {
        // Leave left out intentionally, check for NULL instead
        iConnUpDownNotifier = new CConnUpDownNotifier( iServer ); // No (ELeave)
        if ( !iConnUpDownNotifier )
            {
            err = KErrNoMemory;
            }
        else
            {
            iConnUpDownNotifier->Construct();
            }
        }
    if ( KErrNone == err )
        {
        if ( !iConnUpDownNotifier->IsActive() )
            {
            iConnUpDownNotifier->Receive(); // (re)start listening
            }
        // Add event watchers for the new connections. Old connections already have
        // notifications on and AddConnNotificationsL() will only restart the event
        // watchers if they have stopped (because of an error situation).
        if ( iCountListeners > 0 )
            {
            TRAP( err,
                    {
                    for ( k = 0; k < aCount; k++ )
                        {
                        AddConnNotificationsL( k );
                        }
                    } );
            }
        }
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::EnumerateConnectionsL
// Enumerates active connections using RConnection API.
// Refreshes iConnInfos array (server view) with the latest information.
// Fills aEnumInfo array (client view) with the newly enumerated connection ids.
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::EnumerateConnectionsL( TUint& aCount, CArrayFixFlat<TUint>& aEnumInfo )
    {
    LOGENTRFN("CConnMonIAP::EnumerateConnectionsL()")
    TInt err( KErrNone );

    err = EnumerateConnections( aCount );
    if ( KErrNone == err )
        {
        // Fill in table (connection ids) owned by the session
        // Client needs this table when querying connection info index by index.
        aEnumInfo.Reset();

        if ( aCount > 0 )
            {
            for ( TUint k = 0; k < aCount; k++ )
                {
                // Sometimes there is a delay after the DELETE event has arrived and
                // before the closed connection is removed from Esock. Hide these closing
                // connections from clients.
                TBool deleteSent( EFalse );

                if ( iConnInfos[k].iConnDownNotifier != 0 )
                    {
                    deleteSent = iConnInfos[k].iConnDownNotifier->DeleteSent();
                    }

                if ( !deleteSent )
                    {
                    aEnumInfo.AppendL( iConnInfos[k].iConnectionId );
                    }
                }
            aCount = aEnumInfo.Count();
            }
        }

    LOGEXITFN1("CConnMonIAP::EnumerateConnectionsL()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::ConnectionExists
// Checks if given connection id is valid
// -----------------------------------------------------------------------------
//
TBool CConnMonIAP::ConnectionExists( const TUint& aConnectionId )
    {
    LOGENTRFN("CConnMonIAP::ConnectionExists()")
    TBool res( EFalse );

    if ( aConnectionId == 0 || aConnectionId >= KMaxConnectionId )
        {
        res = EFalse;
        }
    else
        {
        TInt index = Index( aConnectionId );
        if ( index < 0 )
            {
            res = EFalse;
            }
        else
            {
            res = ETrue;
            }
        }

    LOGEXITFN1("CConnMonIAP::ConnectionExists()", res)
    return res;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetConnectionInfo
// Returns the number of subconnections in aSubConnectionCount
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetConnectionInfo(
        const TUint& aConnectionId,
        TUint& aSubConnectionCount )
    {
    LOGENTRFN("CConnMonIAP::GetConnectionInfo()")
    TInt err( KErrNone );

    // Find connection matching the given Id
    TInt index = Index( aConnectionId );
    if ( index < 0  )
        {
        err = KErrNotFound;
        }
    else
        {
        // Get the number of subconnections
        if ( iConnInfos[index].iBearer < EBearerExternalCSD )
            {
            // Internal connections
            aSubConnectionCount = 1;
            err = iConnInfos[index].iConnAttach->EnumerateSubConnections(
                    aSubConnectionCount );
            if ( KErrNotReady == err )
                {
                err = KErrNone;
                }
            }
        else
            {
            // External connections
            aSubConnectionCount = 1;
            }
        }

    LOGEXITFN1("CConnMonIAP::GetConnectionInfo()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetIntAttributeL
// Returns the integer attribute in aValue
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetIntAttributeL( const RMessage2& aMessage, TInt& aValue )
    {
    LOGENTRFN("CConnMonIAP::GetIntAttributeL()")
    TInt ret( KErrNone );
    TUint connectionId( aMessage.Int0() );
    TUint attribute( aMessage.Int2() );

    LOGIT2("SERVER: CConnMonIAP::GetIntAttributeL(): connId %d, attribute %d", connectionId, attribute)

    if ( KBearerInfo == attribute )
        {
        LOGIT("SERVER: CConnMonIAP::GetIntAttributeL(): KBearerInfo")
        TBearerInfo bearerInfo;
        ret = GetBearerInfo( connectionId, bearerInfo );
        if ( KErrNone == ret )
            {
            aValue = bearerInfo.iBearer;
            }
        return ret;
        }

    if ( KWlanScanCacheLifetime == attribute )
        {
        // Check WLAN support for the given id
        ret = WlanSupportCheck( connectionId );
        if ( KErrNone == ret )
            {
            ret = iWlanSupport->GetIntAttributeL( aMessage, aValue );
            }
        return ret;
        }

    // Handle requests that use a bearer specific connection IDs
    if ( ( connectionId == EBearerIdGPRS || connectionId == EBearerIdWCDMA ) &&
         ( attribute == KNetworkStatus ) )
        {
        return ( GetPsdNetworkStatus( aValue ) );
        }
    else if ( ( connectionId == EBearerIdGPRS || connectionId == EBearerIdWCDMA ||
                connectionId == EBearerIdCSD || connectionId == EBearerIdGSM ||
                connectionId == EBearerIdWcdmaCSD )
                && ( attribute == KNetworkRegistration ) )
        {
        return ( GetNetworkRegistration( aValue ) );
        }
    else if ( ( connectionId == EBearerIdGPRS || connectionId == EBearerIdWCDMA ||
                connectionId == EBearerIdCSD || connectionId == EBearerIdGSM ||
                connectionId == EBearerIdWcdmaCSD )
                && ( attribute == KNetworkRegistration_v2 ) )
        {
        return ( GetNetworkRegistration_v2( aValue ) );
        }
    else if ( ( connectionId == EBearerIdGPRS || connectionId == EBearerIdWCDMA ||
                connectionId == EBearerIdCSD || connectionId == EBearerIdGSM ||
                connectionId == EBearerIdWcdmaCSD )
                && ( attribute == KSignalStrength ) )
        {
        return ( GetGSMSignalStrength( aValue ) );
        }
    else if ( connectionId == EBearerIdWLAN && attribute == KSignalStrength )
        {
        if ( iWlanSupport )
            {
            ret = iWlanSupport->GetSignalStrengthL( aMessage, aValue );
            }
        else
            {
            ret = KErrNotSupported;
            }
        return ret;
        }
    else if ( ( connectionId == EBearerIdGPRS ) && ( attribute == KBearer ) )
        {
        // Check which is the bearer of the GPRS cell.
        if ( IsEdgeCell() )
            {
            aValue = EBearerEdgeGPRS;
            }
        else
            {
            aValue = EBearerGPRS;
            }
        return KErrNone;
        }

    // Find connection matching the given Id
    TInt index = Index( connectionId );
    if ( index < 0  )
        {
        return KErrNotFound;
        }

    LOGIT1("SERVER: CConnMonIAP::GetIntAttributeL(): index %d", index)

    // Find out bearer if not already set.
    if ( iConnInfos[index].iBearer == EBearerUnknown )
        {
        ret = GetBearer(
                connectionId,
                iConnInfos[index].iBearer,
                iConnInfos[index].iBearerInfo );

        if ( ret != KErrNone )
            {
            LOGIT1("SERVER: CConnMonIAP::GetIntAttributeL(): Error getting bearer info for connection <%d>", ret)
            return ret;
            }
        LOGIT1("SERVER: CConnMonIAP::GetIntAttributeL(): bearer was unknown, now %d", iConnInfos[index].iBearer)
        }

    switch ( attribute )
        {
        case KBearer:
            {
            // BEARER
            LOGIT1("SERVER: CConnMonIAP::GetIntAttributeL(): case KBearer, bearer %d", iConnInfos[index].iBearer)
            // Bearer is never unknown for the external connections
            // but sometimes it is not valid (e.g. CSD/HSCSD) until
            // connection reaches certain status.
            if ( ( iConnInfos[index].iBearer == EBearerExternalCSD ) ||
                 ( iConnInfos[index].iBearer == EBearerExternalHSCSD ) ||
                 ( iConnInfos[index].iBearer == EBearerExternalWcdmaCSD ) )
                {
                if ( iCsdFax )
                    {
                    iCsdFax->GetBearer( iConnInfos[index].iBearer, iConnInfos[index].iBearerInfo );
                    }
                }
            else if ( ( iConnInfos[index].iBearer == EBearerExternalGPRS ) ||
                      ( iConnInfos[index].iBearer == EBearerExternalEdgeGPRS ) ||
                      ( iConnInfos[index].iBearer == EBearerExternalWCDMA ) )
                {
                if ( iPsdFax )
                    {
                    iPsdFax->GetBearer( iConnInfos[index].iBearer, iConnInfos[index].iBearerInfo );
                    }
                }
            else if ( iConnInfos[index].iBearer < EBearerExternalCSD )
                {
                // CSD/HSCSD info could change after the first query
                // also GPRS/EdgeGPRS/WCDMA info can change
                TInt bearer( EBearerUnknown );
                TBearerInfo bearerInfo;

                ret = GetBearer( connectionId, bearer, bearerInfo );
                if ( iConnInfos[index].iBearer != bearer )
                    {
                    LOGIT4("Bearer changed: id %d, iapId %d, old bearer %d, new bearer %d",
                            iConnInfos[index].iConnectionId, iConnInfos[index].iIapId,
                            iConnInfos[index].iBearer, bearer)
                    }

                if ( ( bearer != EBearerUnknown && bearerInfo.iBearer != EBearerInfoUnknown )
                     && ( ret == KErrNone ) )
                    {
                    iConnInfos[index].iBearer = bearer;
                    iConnInfos[index].iBearerInfo = bearerInfo;
                    }
                }
            aValue = iConnInfos[index].iBearer;
            }
            break;

        case KNetworkStatus:
            {
            // NETWORK STATUS
            if ( iConnInfos[index].iBearer == EBearerGPRS ||
                 iConnInfos[index].iBearer == EBearerEdgeGPRS ||
                 iConnInfos[index].iBearer == EBearerWCDMA ||
                 iConnInfos[index].iBearer == EBearerCDMA2000 ||
                 iConnInfos[index].iBearer == EBearerExternalGPRS ||
                 iConnInfos[index].iBearer == EBearerExternalEdgeGPRS ||
                 iConnInfos[index].iBearer == EBearerExternalWCDMA ||
                 iConnInfos[index].iBearer == EBearerExternalCDMA2000 )
                {
                // psd
                ret = GetPsdNetworkStatus( aValue );
                }
            else if ( iConnInfos[index].iBearer == EBearerUnknown )
                {
                 // GetBearer() : iMobilePhone.GetCurrentMode()
                 // is not always working for PSD when starting the first
                 // connection. So this must be some PSD...
                ret = GetPsdNetworkStatus( aValue );
                }
            else
                {
                // Others not supported at the moment
                aValue = EConnMonStatusNotAvailable;
                ret = KErrNone;
                }
            }
            break;

        case KConnectionStatus:
            {
            // CONNECTION STATUS
            if ( iConnInfos[index].iBearer < EBearerExternalCSD )
                {
                // Internal connections
                ret = GetConnectionStatus( index, aValue );
                }
            else if ( iConnInfos[index].iBearer == EBearerExternalCSD ||
                      iConnInfos[index].iBearer == EBearerExternalHSCSD ||
                      iConnInfos[index].iBearer == EBearerExternalWcdmaCSD )
                {
                // External csd
                if ( iCsdFax )
                    {
                    ret = iCsdFax->GetStatus( aValue );
                    }
                else
                    {
                    ret = KErrNotFound;
                    }
                }
            else
                {
                // External psd
                if ( iPsdFax )
                    {
                    ret = iPsdFax->GetStatus( connectionId, aValue );
                    }
                else
                    {
                    ret = KErrNotFound;
                    }
                }
            }
            break;

        case KProtocolType:
            {
            // PROTOCOL TYPE
            if ( iConnInfos[index].iBearer == EBearerGPRS ||
                 iConnInfos[index].iBearer == EBearerEdgeGPRS ||
                 iConnInfos[index].iBearer == EBearerWCDMA )
                {
                ret = GetProtocolTypeL( connectionId, aValue );
                }
            else if ( iConnInfos[index].iBearer == EBearerExternalGPRS ||
                      iConnInfos[index].iBearer == EBearerExternalEdgeGPRS ||
                      iConnInfos[index].iBearer == EBearerExternalWCDMA )
                {
                if ( iPsdFax )
                    {
                    ret = iPsdFax->GetProtocolType( connectionId, aValue );
                    }
                else
                    {
                    ret = KErrNotFound;
                    }
                }
            else
                {
                aValue = EProtocolTypeUnknown;
                }
            }
            break;

        case KNetworkRegistration:
            {
            // NETWORK REGISTRATION STATUS
            if ( iConnInfos[index].iBearer == EBearerGPRS ||
                 iConnInfos[index].iBearer == EBearerEdgeGPRS ||
                 iConnInfos[index].iBearer == EBearerWCDMA ||
                 iConnInfos[index].iBearer == EBearerCSD ||
                 iConnInfos[index].iBearer == EBearerHSCSD ||
                 iConnInfos[index].iBearer == EBearerWcdmaCSD ||
                 iConnInfos[index].iBearer == EBearerExternalGPRS ||
                 iConnInfos[index].iBearer == EBearerExternalEdgeGPRS ||
                 iConnInfos[index].iBearer == EBearerExternalWCDMA ||
                 iConnInfos[index].iBearer == EBearerExternalCSD ||
                 iConnInfos[index].iBearer == EBearerExternalHSCSD ||
                 iConnInfos[index].iBearer == EBearerExternalWcdmaCSD )
                {
                ret = GetNetworkRegistration( aValue );
                }
            else
                {
                aValue = ENetworkRegistrationNotAvailable;
                ret = KErrNone;
                }
            }
            break;
        case KNetworkRegistration_v2:
            {
            // NETWORK REGISTRATION STATUS
            if ( iConnInfos[index].iBearer == EBearerGPRS ||
                 iConnInfos[index].iBearer == EBearerEdgeGPRS ||
                 iConnInfos[index].iBearer == EBearerWCDMA ||
                 iConnInfos[index].iBearer == EBearerCSD ||
                 iConnInfos[index].iBearer == EBearerHSCSD ||
                 iConnInfos[index].iBearer == EBearerWcdmaCSD ||
                 iConnInfos[index].iBearer == EBearerExternalGPRS ||
                 iConnInfos[index].iBearer == EBearerExternalEdgeGPRS ||
                 iConnInfos[index].iBearer == EBearerExternalWCDMA ||
                 iConnInfos[index].iBearer == EBearerExternalCSD ||
                 iConnInfos[index].iBearer == EBearerExternalHSCSD ||
                 iConnInfos[index].iBearer == EBearerExternalWcdmaCSD )
                {
                ret = GetNetworkRegistration_v2( aValue );
                }
            else
                {
                aValue = ENetworkRegistrationNotAvailable;
                ret = KErrNone;
                }
            }
            break;
        case KSignalStrength:
            {
            // SIGNAL STRENGTH
            ret = KErrNotSupported;
            if ( iConnInfos[index].iBearer == EBearerGPRS ||
                 iConnInfos[index].iBearer == EBearerEdgeGPRS ||
                 iConnInfos[index].iBearer == EBearerWCDMA ||
                 iConnInfos[index].iBearer == EBearerCSD ||
                 iConnInfos[index].iBearer == EBearerHSCSD ||
                 iConnInfos[index].iBearer == EBearerWcdmaCSD ||
                 iConnInfos[index].iBearer == EBearerExternalGPRS ||
                 iConnInfos[index].iBearer == EBearerExternalEdgeGPRS ||
                 iConnInfos[index].iBearer == EBearerExternalWCDMA ||
                 iConnInfos[index].iBearer == EBearerExternalCSD ||
                 iConnInfos[index].iBearer == EBearerExternalHSCSD ||
                 iConnInfos[index].iBearer == EBearerExternalWcdmaCSD )
                {
                ret = GetGSMSignalStrength( aValue );
                }
            else if ( iConnInfos[index].iBearer == EBearerWLAN )
                {
                if ( iWlanSupport )
                    {
                    ret = iWlanSupport->GetSignalStrengthL( aMessage, aValue );
                    }
                }
            }
            break;

        case KNetworkMode:
            // NETWORK MODE
            ret = KErrNotSupported;
            if ( iConnInfos[index].iBearer == EBearerWLAN )
                {
                if ( iWlanSupport )
                    {
                    ret = iWlanSupport->GetConnectionMode( aValue );
                    }
                }
            break;

        case KSecurityMode:
            // SECURITY MODE
            ret = KErrNotSupported;
            if ( iConnInfos[index].iBearer == EBearerWLAN )
                {
                if ( iWlanSupport )
                    {
                    TInt secModeV2( EConnMonSecurityV2Open );
                    ret = iWlanSupport->GetConnectionSecurity( secModeV2 );
                    aValue = iWlanSupport->ConvertConMonSecModeV2ToConnMonSecMode( secModeV2 );
                    }
                }
            break;

        case KSecurityMode_v2:
            // SECURITY MODE V2
            ret = KErrNotSupported;
            if ( iConnInfos[index].iBearer == EBearerWLAN )
                {
                if ( iWlanSupport )
                    {
                    ret = iWlanSupport->GetConnectionSecurity( aValue );
                    }
                }
            break;

        case KTrafficClass:
            ret = KErrNotSupported;
            break;
        case KDeliveryOrder:
            ret = KErrNotSupported;
            break;
        case KErroneousSDUDelivery:
            ret = KErrNotSupported;
            break;
        case KResidualBitErrorRatio:
            ret = KErrNotSupported;
            break;
        case KSDUErrorRatio:
            ret = KErrNotSupported;
            break;
        default:
            ret = KErrArgument;
            break;
        }

    LOGEXITFN1("CConnMonIAP::GetIntAttributeL()", ret)
    return ret;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetBearerInfo
// Returns the integer attribute in aValue
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetBearerInfo( const TUint aConnectionId, TBearerInfo& aBearerInfo )
    {
    LOGENTRFN("CConnMonIAP::GetBearerInfo()")
    TInt err( KErrNone );
    TBool getBearerCalled( EFalse );

    // Find connection matching the given Id
    TInt index = Index( aConnectionId );
    if ( index < 0  )
        {
        err = KErrNotFound;
        }
    else
        {
        // Find out bearer if not already set. This can be only with internal
        // connections.
        if ( iConnInfos[index].iBearerInfo.iBearer == EBearerInfoUnknown )
            {
            LOGIT("GetBearerInfo: EBearerInfoUnknown")
            err = GetBearer(
                    aConnectionId,
                    iConnInfos[index].iBearer,
                    iConnInfos[index].iBearerInfo );
            getBearerCalled = ETrue;
            }
        if ( KErrNone == err )
            {
            // Bearer is never unknown for the external connections but
            // sometimes it is not valid (e.g. CSD/HSCSD) until connection
            // reaches certain status.
            if ( !iConnInfos[index].iBearerInfo.iInternal &&
                    ( iConnInfos[index].iBearerInfo.iBearer == EBearerInfoCSD ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSCSD ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoWcdmaCSD ) )
                {
                if ( iCsdFax )
                    {
                    LOGIT("GetBearerInfo: case iCsdFax")
                    err = iCsdFax->GetBearer(
                            iConnInfos[index].iBearer,
                            iConnInfos[index].iBearerInfo );
                    }
                }
            else if ( !iConnInfos[index].iBearerInfo.iInternal &&
                    ( iConnInfos[index].iBearerInfo.iBearer == EBearerInfoGPRS ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoEdgeGPRS ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoWCDMA ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSDPA ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSUPA ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSxPA ) )
                {
                if ( iPsdFax )
                    {
                    LOGIT("GetBearerInfo: case iPsdFax")
                    err = iPsdFax->GetBearer(
                            iConnInfos[index].iBearer,
                            iConnInfos[index].iBearerInfo );
                    }
                }
            else if ( iConnInfos[index].iBearerInfo.iInternal &&
                    ( iConnInfos[index].iBearerInfo.iBearer == EBearerInfoCSD ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSCSD ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoGPRS ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoEdgeGPRS ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoWCDMA ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSDPA ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSUPA ||
                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSxPA ) )
                {
                // If GetBearer() was just called, no need to do it again.
                if ( !getBearerCalled )
                    {
                    // CSD/HSCSD info could change after the first query also
                    // GPRS/EdgeGPRS/WCDMA info can change.
                    TInt bearer( EBearerUnknown );
                    TBearerInfo bearerInfo;

                    LOGIT("GetBearerInfo: GetBearer() 2nd query")
                    err = GetBearer( aConnectionId, bearer, bearerInfo );
                    if ( ( KErrNone == err ) && ( bearerInfo.iBearer != EBearerInfoUnknown ) )
                        {
                        iConnInfos[index].iBearer = bearer;
                        iConnInfos[index].iBearerInfo = bearerInfo;
                        }
                    }
                }
            }
        if ( KErrNone == err )
            {
            aBearerInfo.iBearer = iConnInfos[index].iBearerInfo.iBearer;
            aBearerInfo.iInternal = iConnInfos[index].iBearerInfo.iInternal;
            LOGIT2("GetBearerInfo: result: bearer %d, internal %d", aBearerInfo.iBearer, aBearerInfo.iInternal)
            }
        }

    LOGEXITFN1("CConnMonIAP::GetBearerInfo()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetUintAttributeL
// Returns the unsigned integer attribute in aValue
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetUintAttributeL( const RMessage2& aMessage, TUint& aValue )
    {
    LOGENTRFN("CConnMonIAP::GetUintAttributeL()")
    TInt err( KErrNone );
    TUint connectionId( aMessage.Int0() );
    TUint attribute( aMessage.Int2() );

    LOGIT2("SERVER: CConnMonIAP::GetUintAttributeL: connId %d, attribute %d", connectionId, attribute)

    // Find connection matching the given ID
    TInt index = Index( connectionId );
    if ( index < 0 )
        {
        LOGEXITFN1("CConnMonIAP::GetUintAttributeL()", KErrNotFound)
        return KErrNotFound;
        }

    switch ( attribute )
        {
        case KIAPId:
            {
            err = KErrNotSupported;
            if ( iConnInfos[index].iBearer < EBearerExternalCSD &&
                    iConnInfos[index].iBearerInfo.iInternal )
                {
                err = KErrNone;
                aValue = iConnInfos[index].iIapId;
                LOGIT1("GetUintAttributeL: iap id %d", aValue)
                }
            }
            break;

        case KNetworkIdentifier:
            {
            err = KErrNotSupported;
            if ( iConnInfos[index].iBearer < EBearerExternalCSD &&
                    iConnInfos[index].iBearerInfo.iInternal )
                {
                err = KErrNone;
                aValue = iConnInfos[index].iNetId;
                LOGIT1("GetUintAttributeL: net id %d", aValue)
                }
            }
            break;

        case KDownlinkData:
        case KUplinkData:
            {
            if ( iConnInfos[index].iBearer < EBearerExternalCSD &&
                    iConnInfos[index].iBearerInfo.iInternal )
                {
                // INTERNAL
                // Query data volumes asyncronously
                if ( !iConnInfos[index].iDataVolumeAO )
                    {
                    // Create an active object and add it to scheduler
                    iConnInfos[index].iDataVolumeAO = new( ELeave ) CDataVolume(
                            iServer,
                            iConnInfos[index].iConnAttach,
                            iConnInfos[index].iConnectionId );

                    iConnInfos[index].iDataVolumeAO->Construct();
                    }
                if ( !iConnInfos[index].iDataVolumeAO->IsActive() )
                    {
                    iConnInfos[index].iDataVolumeAO->Receive(); // start a new request
                    }
                // Don't complete this request yet
                err = KRequestPending;
                }

            else if ( iConnInfos[index].iBearer == EBearerExternalGPRS     ||
                      iConnInfos[index].iBearer == EBearerExternalEdgeGPRS ||
                      iConnInfos[index].iBearer == EBearerExternalWCDMA    ||
                      iConnInfos[index].iBearer == EBearerExternalCDMA2000 ||
                      ( !iConnInfos[index].iBearerInfo.iInternal &&
                        ( iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSDPA ||
                          iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSUPA ||
                          iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSxPA ) ) )
                {
                // EXTERNAL PSD
                if ( iPsdFax )
                    {
                    TUint down( 0 );
                    TUint up( 0 );
                    err = iPsdFax->GetDataVolumes( connectionId, down, up );
                    if ( KErrNone == err )
                        {
                        if ( attribute == KDownlinkData )
                            {
                            aValue = down;
                            }
                        else
                            {
                            aValue = up;
                            }
                        }
                    }
                else
                    {
                    err = KErrNotFound;
                    }
                }

            else
                {
                // EXTERNAL CSD
                err = KErrNotSupported;
                }
            }
            break;

        case KTransmitPower:
            {
            err = KErrNotSupported;
            if ( iConnInfos[index].iBearer == EBearerWLAN && iWlanSupport )
                {
                err = iWlanSupport->GetTransmitPower( aValue );
                LOGIT1("GetUintAttributeL: transmit power %d", aValue)
                }
            }
            break;

        case KMaximumBitrateDownlink:
        case KMaximumBitrateUplink:
        case KMaximumSDUSize:
        case KTransferDelay:
        case KGuaranteedBitrateDownlink:
        case KGuaranteedBitrateUplink:
        case KTrafficHandlingPriority:
            err = KErrNotSupported;
            break;

        default:
            err = KErrArgument;
            break;
        }

    LOGEXITFN1("CConnMonIAP::GetUintAttributeL()", err)
    return err;
    }


// -----------------------------------------------------------------------------
// CConnMonIAP::GetBoolAttributeL
// Returns the TBool attribute in aValue
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetBoolAttributeL( const RMessage2& aMessage, TBool& aValue )
    {
    LOGENTRFN("CConnMonIAP::GetBoolAttributeL()")
    TInt err( KErrNone );
    TUint connectionId( aMessage.Int0() );
    TUint attribute( aMessage.Int2() );

    switch ( attribute )
        {
        case KConnectionActive:
            {
            // Find connection matching the given ID
            TInt index = Index( connectionId );
            if ( index < 0  )
                {
                LOGIT("GetBoolAttributeL: connection id not found")
                err = KErrNotFound;
                break;
                }
            if ( iConnInfos[index].iBearer < EBearerExternalCSD &&
                    iConnInfos[index].iBearerInfo.iInternal )
                {
                TInt connectionStatus( 0 );
                GetConnectionStatus( index, connectionStatus );
                LOGIT1("GetBoolAttributeL: connection status %d", connectionStatus)

                if ( connectionStatus != KLinkLayerOpen )
                    {
                    aValue = EFalse;
                    break;
                    }
                if ( ( iCountListeners > 0 ) && ( iConnInfos[index].iActivityNotifier != 0 ) )
                    {
                    if ( iConnInfos[index].iActivityNotifier->IsActive() )
                        {
                        // Notifications are ON and are updating the activity info.
                        // Return the info immediately from internal table
                        if ( iConnInfos[index].iActivity == 0 )
                            {
                            aValue = EFalse;
                            }
                        else
                            {
                            aValue = ETrue;
                            }
                        }
                    else
                        {
                        GetActivityOneShotL( index );
                        err = KRequestPending;
                        }
                    }
                else
                    {
                    // Notifications are OFF
                    GetActivityOneShotL( index );
                    err = KRequestPending;
                    }
                }
            else
                {
                err = KErrNotSupported;
                }
            }
            break;

        case KBearerAvailability:
            {
            TUint bearer( EBearerIdAll );
            err = BearerIdForBearerAvailability( connectionId, bearer );
            if ( KErrNone == err )
                {
                if ( bearer == EBearerIdWLAN )
                    {
                    if ( iWlanSupport )
                        {
                        err = iWlanSupport->GetBearerAvailabilityL( aMessage, aValue );
                        }
                    else
                        {
                        err = KErrNotSupported;
                        }
                    }
                else
                    {
                    TBool byCell( EFalse );
                    TBool byPhone( EFalse );
                    err = GetBearerSupportInfo( bearer, byCell, byPhone );
                    if ( byCell && byPhone )
                        {
                        aValue = ETrue;
                        }
                    else
                        {
                        aValue = EFalse;
                        }
                    }
                }
            }
            break;

        case KPacketDataAvailability:
            {
            if ( connectionId != EBearerIdGPRS && connectionId != EBearerIdWCDMA )
                {
                err = KErrNotSupported;
                }
            else
                {
                // When not in dual mode and call is active, gprs and wcdma bearers are unavailable
                // Note that even the WCDMA can be unavailable, if the phone doesn't support DTM
                if ( iTelephonyNotifier && iDualTransferModeNotifier &&
                        iTelephonyNotifier->IsCallActive() &&
                        !iDualTransferModeNotifier->IsInDualMode() )
                    {
                    LOGIT("SERVER: Packet data UNAVAILABLE (2G&3G), no DTM and call is active")
                    aValue = EFalse;
                    }
                // If DTM status says available, lets check the availability of the bearer.
                // This is done because the DTM status remains as it was if the psd link is broken.
                // So there might be a situation where the notifier says we are in dual mode even
                // though the whole bearer is unavailable
                else
                    {
                    TBool byPhone( EFalse );
                    TBool byCell( EFalse );
                    err = GetBearerSupportInfo( connectionId, byCell, byPhone );
                    LOGIT4("Bearer support: bearer %d, byCell %d, byPhone %d, err <%d>", connectionId, byCell, byPhone, err)
                    aValue = ETrue;
                    if ( KErrNone == err )
                        {
                        if ( byCell && byPhone )
                            {
                            LOGIT("SERVER: Packet data AVAILABLE, DTM or no call is active")
                            }
                        else
                            {
                            LOGIT("SERVER: Packet data UNAVAILABLE, no bearer")
                            aValue = EFalse;
                            }
                        }
                    }
                }
            }
            break;

        default:
            // Unknown attribute
            err = KErrArgument;
            break;
        }

    LOGEXITFN1("CConnMonIAP::GetBoolAttributeL()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetStringAttribute
// Returns the TDes attribute in aValue
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetStringAttribute( const RMessage2& aMessage, TDes& aValue )
    {
    LOGENTRFN("CConnMonIAP::GetStringAttribute()")
    TInt err( KErrNone );
    TUint connectionId( aMessage.Int0() );
    TUint attribute( aMessage.Int2() );

    // Find connection matching the given ID
    TInt index = Index( connectionId );
    if ( index < 0  )
        {
        LOGEXITFN1("CConnMonIAP::GetStringAttribute()", KErrNotFound)
        return KErrNotFound;
        }

    // Find out bearer if not already set
    if ( iConnInfos[index].iBearer == EBearerUnknown )
        {
        err = GetBearer( connectionId, iConnInfos[index].iBearer, iConnInfos[index].iBearerInfo );
        if ( KErrNone != err )
            {
            LOGEXITFN1("CConnMonIAP::GetStringAttribute()", err)
            return err;
            }
        }

    switch ( attribute )
        {
        case KIAPName:
            {
            // From RConnection
            if ( iConnInfos[index].iBearer >= EBearerExternalCSD &&
                    !iConnInfos[index].iBearerInfo.iInternal )
                {
                err = KErrNotSupported;
                }
            else
                {
                TBuf<KCommsDbSvrMaxFieldLength> settingName;
                settingName.Copy( TPtrC( IAP ) );
                settingName.Append( TChar( '\\' ) );
                settingName.Append( TPtrC( COMMDB_NAME ) );
                // IAP name max. length in commsdat should be 50
                err = iConnInfos[index].iConnAttach->GetDesSetting( TPtrC( settingName ), aValue );
                }
            }
            break;

        case KAccessPointName:
            {
            if ( iConnInfos[index].iBearer < EBearerExternalCSD )
                {
                err = GetAccessPointName( iConnInfos[index].iConnectionId, aValue );
                }
            else if ( iConnInfos[index].iBearer == EBearerExternalGPRS ||
                    iConnInfos[index].iBearer == EBearerExternalEdgeGPRS ||
                    iConnInfos[index].iBearer == EBearerExternalWCDMA ||
                    ( !iConnInfos[index].iBearerInfo.iInternal &&
                            ( iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSDPA ||
                                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSUPA ||
                                    iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSxPA ) ) )
                {
                if ( iPsdFax )
                    {
                    err = iPsdFax->GetApn( connectionId, aValue );
                    }
                else
                    {
                    err = KErrNotFound;
                    }
                }
            else
                {
                err = KErrNotSupported;
                }
            }
            break;

        case KTelNumber:
            {
            if ( iConnInfos[index].iBearer < EBearerExternalCSD )
                {
                err = GetTelNumber( iConnInfos[index].iConnectionId, aValue );
                }
            else if ( iConnInfos[index].iBearer == EBearerExternalCSD ||
                    iConnInfos[index].iBearer == EBearerExternalHSCSD ||
                    iConnInfos[index].iBearer == EBearerExternalWcdmaCSD )
                {
                if ( iCsdFax )
                    {
                    err = iCsdFax->GetTelNumber( aValue );
                    }
                else
                    {
                    err = KErrNotFound;
                    }
                }
            else
                {
                err = KErrNotSupported;
                }
            }
            break;

        case KNetworkName:
            {
            err = KErrNotSupported;
            if ( iConnInfos[index].iBearer == EBearerWLAN )
                {
                if ( iWlanSupport )
                    {
                    // Max SSID length is 32
                    err = iWlanSupport->GetConnectionSsid( aValue );
                    }
                }
            }
            break;

        default:
            err = KErrArgument;
            break;
        }

    LOGEXITFN1("CConnMonIAP::GetStringAttribute()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetUids
// RConnection::EnumerateConnections() must be called to get the right
// RConnection index for the connection (iConnInfos can't be trusted because
// connections are added by events, too).
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetUids(
        const TUint aConnectionId,
        TConnMonClientEnum& aClientEnum )
    {
    TInt                     err( KErrNone );
    TConnEnumArgBuf          enumArgBuf;
    TConnGetClientInfoArgBuf clientInfoBuf;
    TUint                    count( 0 );
    TConnectionInfoBuf       connInfoBuf;
    TUint                    j;

    // Find connection matching the given Id
    TInt index = Index( aConnectionId );

    if ( index < 0  )
        {
        return KErrNotFound;
        }

    // Uids are not available for external connections
    if ( iConnInfos[index].iBearer >= EBearerExternalCSD &&
         !iConnInfos[index].iBearerInfo.iInternal )
        {
        return KErrNotSupported;
        }

    // Get RConnection index for the connection
    err = iConnection.EnumerateConnections( count );

    if ( err != KErrNone )
        {
        return( err );
        }

    for ( j = 1; j <= count; j++ )
        {
        err = iConnection.GetConnectionInfo( j, connInfoBuf );

        if ( err != KErrNone )
            {
            return( err );
            }

        if ( ( iConnInfos[index].iIapId == connInfoBuf().iIapId ) &&
                ( iConnInfos[index].iNetId == connInfoBuf().iNetId ) )
            {
            break;
            }
        }

    // If connection does not exist anymore
    if ( j > count )
        {
        return KErrNotFound;
        }

    enumArgBuf().iIndex = j;

    // Get the number of clients
    err = iConnection.Control( KCOLConnection, KCoEnumerateConnectionClients, enumArgBuf );

    if ( err != KErrNone )
        {
        return err;
        }

    aClientEnum.iCount = enumArgBuf().iCount;

    // Count connection monitor OUT of the number of clients
    if ( aClientEnum.iCount > 0 )
        {
        --aClientEnum.iCount;
        }

    // Get client uids one by one
    // Note. in WINS uids are zero.
    TInt k( 0 );

    for ( TUint i = 1; i <= enumArgBuf().iCount; i++ )
        {
        clientInfoBuf().iIndex = i;

        err = iConnection.Control( KCOLConnection, KCoGetConnectionClientInfo, clientInfoBuf );

        if ( err != KErrNone )
            {
            return err;
            }

        // Exclude Connection Monitor UID
        if ( ( clientInfoBuf().iClientInfo.iUid.iUid != KConnMonDllUid.iUid ) &&
             ( clientInfoBuf().iClientInfo.iUid.iUid != KGenericDllUid.iUid ) &&
             ( clientInfoBuf().iClientInfo.iUid.iUid != KConnMonServerUid.iUid ) &&
             ( clientInfoBuf().iClientInfo.iUid.iUid != 0 ) )
            {
            TInt m( 0 );

            // Look for duplicates
            for ( m = 0; m < k; m++ )
                {
                if ( aClientEnum.iUid[m].iUid == clientInfoBuf().iClientInfo.iUid.iUid )
                    {
                    break;
                    }
                }

            if ( m == k )
                {
                // This is a new unique ID
                aClientEnum.iUid[k].iUid = clientInfoBuf().iClientInfo.iUid.iUid;
                k++;
                }
            else
                {
                // Duplicate
                --aClientEnum.iCount;
                }
            }
        }

    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::SetUintAttribute
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::SetUintAttribute(
        const RMessage2& /*aMessage*/,
        const TUint /*aValue*/ )
    {
    return KErrNotSupported;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::SetBoolAttributeL
// Used for stopping the connections.
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::SetBoolAttribute( const RMessage2& aMessage )
    {
    LOGENTRFN("CConnMonIAP::SetBoolAttribute()")
    TInt err( KErrNone );
    TUint attribute( aMessage.Int2() );
    TBool value( aMessage.Int3() );

    switch ( attribute )
        {
        case KConnectionStop:
            if ( value )
                {
                // Find connection matching the given Id
                TInt index = Index( aMessage.Int0() );
                if ( index < 0  )
                    {
                    err = KErrNotFound;
                    }
                else
                    {
                    err = StopConnection( index );
                    if ( KErrCouldNotConnect == err )
                        {
                        err = KErrNotFound;
                        }
                    }
                }
            break;

        case KConnectionStopAll:
            if ( value )
                {
                TUint i( 0 );
                TUint count( 0 );
                TUint newCount( 0 );

                // Refresh array
                err = EnumerateConnections( count );
                LOGIT2("SetBoolAttribute: KConnectionStopAll: Enumerated all connections, count %d <%d>", count, err)
                if ( KErrNone == err )
                    {
                    while ( count > 0 && i < count )
                        {
                        // Stop (and remove if up/down event watcher is dead) the connection
                        err = StopConnection( i );
                        if ( KErrNone != err )
                            {
                            LOGIT2("SetBoolAttribute: KConnectionStopAll: Error stopping connection %d <%d>", i, err)
                            return err;
                            }
                        newCount = iConnInfos.Count();
                        if ( count > newCount )
                            {
                            count = newCount; // Connection has been removed
                            }
                        else
                            {
                            i++; // Cconnection has not been removed, increment index to next connection
                            }
                        }
                    }
                }
            break;

        default:
            err = KErrArgument;
            break;
        }

    LOGEXITFN1("CConnMonIAP::SetBoolAttribute()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::SetStringAttributeL
//
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::SetStringAttributeL(
        const RMessage2& /*aMessage*/,
        const TDes& /*aValue*/ )
    {
    return KErrNotSupported;
    }


// -----------------------------------------------------------------------------
// CConnMonIAP::ListenL
// Starts event watchers.
// -----------------------------------------------------------------------------
//
void CConnMonIAP::ListenL()
    {
    LOGIT(".")
    LOGENTRFN("CConnMonIAP::ListenL()")
    iCountListeners++;

    // GLOBAL notifiers

    // Connection Up/Down events
    if ( iConnUpDownNotifier == 0 )
        {
        iConnUpDownNotifier = new( ELeave ) CConnUpDownNotifier( iServer );
        iConnUpDownNotifier->Construct();
        }
    if ( !iConnUpDownNotifier->IsActive() )
        {
        iConnUpDownNotifier->Receive(); // (re)start listening
        }

    if ( iTSYLoaded && iPacketServLoaded )
        {
        // PSD network status events
        if ( iPsdNetwStatusNotifier == 0 )
            {
            iPsdNetwStatusNotifier = CNetwStatusNotifier::NewL( iServer );
            }
        if ( !iPsdNetwStatusNotifier->IsActive() )
            {
            iPsdNetwStatusNotifier->Receive(); // (re)start listening
            }

        // GPRS bearer availability changed events
        if ( iGSMBearerAvailabilityNotifier == 0 )
            {
            iGSMBearerAvailabilityNotifier = CBearerAvailabilityNotifier::NewL( iServer );
            }
        if ( !iGSMBearerAvailabilityNotifier->IsActive() )
            {
            iGSMBearerAvailabilityNotifier->Receive(); // (re)start listening
            }
        }

    if ( iTSYLoaded )
        {
        // Mode change events
        if ( iModeNotifier == 0 )
            {
            iModeNotifier = CModeNotifier::NewL( iServer, iMobilePhone );
            }
        if ( !iModeNotifier->IsActive() )
            {
            iModeNotifier->Receive(); // (re)start listening
            }

        // Network registration status events
        if ( iNetwRegistrationNotifier == 0 )
            {
            iNetwRegistrationNotifier = CNetwRegistrationNotifier::NewL( iServer, iMobilePhone );
            }
        if ( !iNetwRegistrationNotifier->IsActive() )
            {            
            iNetwRegistrationNotifier->Receive(); // (re)start listening
            
            // We might have missed the network registration notification before 
            // we started listening for notifications here. Update the 
            // network registration information.            
            TInt registration( ENetworkRegistrationExtNotAvailable );                
            User::LeaveIfError( GetNetworkRegistration_v2( registration ) );
            iServer->CellularDataUsageKeyUpdater()->UpdateKeyL( registration );            
            }

        // Bearer change (GPRS/Edge GPRS) status events
        if ( FeatureManager::FeatureSupported( KFeatureIdEdgeKnowledge ) )
            {
            if ( iEdgeNotifier == 0 )
                {
                iEdgeNotifier = new( ELeave ) CBearerNotifier( iServer, iMobilePhone );
                TRAPD( ret, iEdgeNotifier->ConstructL() );
                if ( ret != KErrNone )
                    {
                    // Construction (=opening ETel CustomAPI) failed
                    delete iEdgeNotifier;
                    iEdgeNotifier = 0;
                    }
                }
            if ( iEdgeNotifier != 0 )
                {
                if ( !iEdgeNotifier->IsActive() )
                    {
                    iEdgeNotifier->Receive(); // (re)start listening
                    }
                }
            }

        if ( !iWcdmaNotifier )
            {
            iWcdmaNotifier = CWcdmaBearerNotifier::NewL( iServer, iTelServer );
            if ( iWcdmaNotifier )
                {
                iWcdmaNotifier->Receive();
                }
            }

        if (  FeatureManager::FeatureSupported( KFeatureIdConnMonExtension ) )
            {
            // GSM signal strength change events
            if ( iGSMSignalNotifier == 0 )
                {
                iGSMSignalNotifier = CGsmSignalNotifier::NewL( iServer, iMobilePhone );
                }
            if ( !iGSMSignalNotifier->IsActive() )
                {
                iGSMSignalNotifier->Receive(); // (re)start listening
                }
            }
        }

    if ( !iTelephonyNotifier )
        {
        iTelephonyNotifier = CConnMonTelNotifier::NewL( *this, &iMobilePhone );
        iTelephonyNotifier->Receive();
        }

    if ( !iDualTransferModeNotifier && iPacketServLoaded )
        {
        iDualTransferModeNotifier = CConnMonDtmNotifier::NewL( iPacketService, *this );
        iDualTransferModeNotifier->Receive();
        }

    if ( iWlanSupport )
        {
        iWlanSupport->EnableEventsToClients();
        }

    // Notifiers owned by the connections
    // (connection status, data volumes, connection activity, subconnection up/down)
    TInt count = iConnInfos.Count();

    for ( TInt i = 0; i < count; i++ )
        {
        AddConnNotificationsL( i );
        }
    LOGEXITFN("CConnMonIAP::ListenL()")
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::CancelListen
// Stops and deletes event watchers.
// -----------------------------------------------------------------------------
//
void CConnMonIAP::CancelListen()
    {
    iCountListeners--;
    LOGIT1("CancelListen() remaining listeners: %d", iCountListeners)

    if ( iCountListeners == 0 )
        {
        DeleteNotifications();
        }
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::AddConnectionL
// Adds a new connection to the iConnInfos array. Starts event watchers for the
// connection if there are clients that want events.
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::AddConnectionL( TConnInfo& aConnection )
    {
    TInt err( KErrNone );
    TInt index( KErrNotFound );
    TUint8 internal( 0 );

    if ( aConnection.iBearer < EBearerExternalCSD )
        {
        internal = 1;
        }

    if ( internal )
        {
        index = iConnInfos.Find( aConnection, TConnInfo::MatchIap );
        }
    /*
    else
        {
        index = iConnInfos.Find( aConnection, TConnInfo::MatchBearer );
        }
    */

    if ( KErrNotFound != index )
        {
        LOGIT("AddConnectionL: New connection occured with same IAP id, remove old")
        // To remove the connection we have to complete the
        // connection by sending the notifications needed by clients.
        CompleteConnectionClosing( index );
        }

    // Add to connection table
    aConnection.iConnectionId = NewConnectionId();

    if ( internal )
        {
        err = OpenAndAttachTo( aConnection );
        if ( err != KErrNone )
            {
            LOGIT1("AddConnectionL: ERROR attach failed <%d>", err)
            return err;
            }
        }

    err = iConnInfos.Append( aConnection );

    if ( ( KErrNone == err ) && internal )
        {
        index = iConnInfos.Find( aConnection, TConnInfo::MatchIap );
        if ( ( index != KErrNotFound ) && ( iCountListeners > 0 ) )
            {
            TRAPD( ret, AddConnNotificationsL( index ) );
            if ( ret != KErrNone )
                {
                // Close attached connection
                if ( iConnInfos[ index ].iConnAttach != 0 )
                    {
                    iConnInfos[ index ].iConnAttach->Close();
                    delete iConnInfos[ index ].iConnAttach;
                    }

                // Remove
                iConnInfos.Remove( index );

                // Leave
                User::Leave( ret );
                }
            }
        }

    // Print connection info array to log
    #ifdef _DEBUG
    LOGIT("AddConnectionL: Connection info array:")
    for ( TInt m = 0; m < iConnInfos.Count(); m++ )
        {
        LOGIT4("  id %d, bearer %d, iapId %d, netId %d", iConnInfos[m].iConnectionId,
                iConnInfos[m].iBearer, iConnInfos[m].iIapId, iConnInfos[m].iNetId)
        }
    #endif // _DEBUG

    return err;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::CompleteConnectionClosing
// -----------------------------------------------------------------------------------
//
void CConnMonIAP::CompleteConnectionClosing( TInt& aIndex )
    {
    LOGENTRFN("CConnMonIAP::CompleteConnectionClosing()")

    if ( iConnInfos[aIndex].iBearerNotifier->Listening() )
        {
        iConnInfos[aIndex].iBearerNotifier->CancelListen();
        }

    if ( iConnInfos[aIndex].iProgressNotifier->IsActive() )
        {
        // Progress notification request is still active --> Cancel it
        iConnInfos[aIndex].iProgressNotifier->Cancel();
        }
    // Send KLinkLayerClosed event
    LOGIT("CompleteConnectionClosing: ProgressNotifier->SendClosedEvent()")
    iConnInfos[aIndex].iProgressNotifier->SendClosedEvent();

    if ( iConnInfos[aIndex].iConnDownNotifier->IsActive() )
        {
        // Allinterface notification request is still active --> Cancel it
        iConnInfos[aIndex].iConnDownNotifier->Cancel();
        }

    if ( !iConnInfos[aIndex].iConnDownNotifier->DeleteSent() )
        {
        // After SetInterfaceClosed() call SendDeletedEvent() removes
        // the connection
        iConnInfos[aIndex].iConnDownNotifier->SetInterfaceClosed();
        iConnInfos[aIndex].iConnDownNotifier->SendDeletedEvent();
        }
    else
        {
        // Delete has already been sent (shouldn't be possible) so
        // connection has to be removed
        LOGIT("CompleteConnectionClosing: Delete already sent, removing connection")
        RemoveConnection( iConnInfos[aIndex] );
        }

    LOGEXITFN("CConnMonIAP::CompleteConnectionClosing()")
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::RemoveConnection
// Removes connection settings from sessions, stops and deletes event watchers and
// removes the connection info from the iConnInfos array.
// Connection is deleted by an event (or by calling RConnection::Stop()).
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::RemoveConnection( TConnInfo& aConnection )
    {
    LOGENTRFN("CConnMonIAP::RemoveConnection()")

    TInt index( KErrNotFound );
    // Check if bearer is external CSD
    if ( aConnection.iBearer == EBearerExternalCSD ||
            aConnection.iBearer == EBearerExternalHSCSD ||
            aConnection.iBearer == EBearerExternalWcdmaCSD )
        {
        index = iConnInfos.Find( aConnection, TConnInfo::MatchBearer );
        }
    else if ( aConnection.iConnectionId > 0 )
        {
        index = iConnInfos.Find( aConnection, TConnInfo::MatchId );
        }
    else
        {
        index = iConnInfos.Find( aConnection, TConnInfo::MatchIap );
        }

    TInt err( KErrNotFound );
    if ( index >= 0 )
        {
        // Set connection id for passing it back to the caller (client event)
        aConnection.iConnectionId = iConnInfos[index].iConnectionId;

        // Remove threshold settings from the client tables
        iServer->RemoveConnSettingsFromSessions( aConnection.iConnectionId );

        // Stop notifications (data volume, connection status, etc.)
        DeleteConnNotifications( index );

        // Close attached connection
        if ( iConnInfos[index].iConnAttach != 0 )
            {
            iConnInfos[index].iConnAttach->Close();
            delete iConnInfos[index].iConnAttach;
            iConnInfos[index].iConnAttach = NULL;
            }

        iConnInfos.Remove( index );
        err = KErrNone;
        }

    // Print connection info array to log
    #ifdef _DEBUG
    LOGIT("RemoveConnection: Connection info array:")
    for ( TInt m = 0; m < iConnInfos.Count(); m++ )
        {
        LOGIT4("  id %d, bearer %d, iapId %d, netId %d", iConnInfos[m].iConnectionId,
                iConnInfos[m].iBearer, iConnInfos[m].iIapId, iConnInfos[m].iNetId)
        }
    #endif // _DEBUG

    LOGEXITFN1("CConnMonIAP::RemoveConnection()", err)
    return err;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::CalculateNetworkStatus
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::CalculateNetworkStatus( const RPacketService::TStatus& aPacketStatus ) const
    {
    switch ( aPacketStatus )
        {
        case ( RPacketService::EStatusUnattached ):
            return EConnMonStatusUnattached;

        case ( RPacketService::EStatusAttached ):
            return EConnMonStatusAttached;

        case ( RPacketService::EStatusActive ):
            return EConnMonStatusActive;

        case ( RPacketService::EStatusSuspended ):
            return EConnMonStatusSuspended;

        default:
            break;
        }
    return aPacketStatus;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::CalculateNetworkRegistration
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::CalculateNetworkRegistration(
        const RMobilePhone::TMobilePhoneRegistrationStatus&
        aRegistration ) const
    {
    switch ( aRegistration )
        {
        case ( RMobilePhone::ERegistrationUnknown ):
            return ENetworkRegistrationUnknown;

        case ( RMobilePhone::ENotRegisteredNoService ):
            return ENetworkRegistrationNoService;

        case ( RMobilePhone::ENotRegisteredEmergencyOnly ):
            return ENetworkRegistrationEmergencyOnly;

        case ( RMobilePhone::ENotRegisteredSearching ):
            return ENetworkRegistrationSearching;

        case ( RMobilePhone::ERegisteredBusy ):
            return ENetworkRegistrationBusy;

        case ( RMobilePhone::ERegisteredOnHomeNetwork ):
            return ENetworkRegistrationHomeNetwork;

        case ( RMobilePhone::ERegistrationDenied ):
            return ENetworkRegistrationDenied;

        case ( RMobilePhone::ERegisteredRoaming ):
            return ENetworkRegistrationRoaming;

        default:
            break;
        }
    return aRegistration;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::CalculateNetworkRegistration_v2
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::CalculateNetworkRegistration_v2(
        const RMobilePhone::TMobilePhoneRegistrationStatus&
        aRegistration ) const
    {
    switch ( aRegistration )
        {
        case ( RMobilePhone::ERegistrationUnknown ):
            return ENetworkRegistrationExtUnknown;

        case ( RMobilePhone::ENotRegisteredNoService ):
            return ENetworkRegistrationExtNoService;

        case ( RMobilePhone::ENotRegisteredEmergencyOnly ):
            return ENetworkRegistrationExtEmergencyOnly;

        case ( RMobilePhone::ENotRegisteredSearching ):
            return ENetworkRegistrationExtSearching;

        case ( RMobilePhone::ERegisteredBusy ):
            return ENetworkRegistrationExtBusy;

        case ( RMobilePhone::ERegisteredOnHomeNetwork ):
            return ENetworkRegistrationExtHomeNetwork;

        case ( RMobilePhone::ERegistrationDenied ):
            return ENetworkRegistrationExtDenied;

        case ( RMobilePhone::ERegisteredRoaming ):
            {
            RMobilePhone::TMobilePhoneNetworkInfoV1 network;
            RMobilePhone::TMobilePhoneNetworkInfoV1Pckg networkPckg( network );

            RMobilePhone::TMobilePhoneNetworkInfoV1 homeNetwork;
            RMobilePhone::TMobilePhoneNetworkInfoV1Pckg homeNetworkPckg( homeNetwork );

            TRequestStatus status( KErrNone );

            iMobilePhone.GetCurrentNetwork(status, networkPckg);
            User::WaitForRequest( status );

            if(status.Int() == KErrNone)
                {
                iMobilePhone.GetHomeNetwork(status, homeNetworkPckg);
                User::WaitForRequest( status );

                if(network.iCountryCode.Compare(homeNetwork.iCountryCode) == 0)
                    {
                    return ENetworkRegistrationExtRoamingNational;
                    }
                else
                    {
                    return ENetworkRegistrationExtRoamingInternational;
                    }
                }
          }

        default:
            break;
        }
    return aRegistration;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::IsEdgeCell
// -----------------------------------------------------------------------------
//
TBool CConnMonIAP::IsEdgeCell()
    {
    LOGENTRFN("CConnMonIAP::IsEdgeCell()")
    TBool edgeStatus( EFalse );

    LOGTIMINGSTART("CConnMonIAP::IsEdgeCell")

    if ( FeatureManager::FeatureSupported( KFeatureIdEdgeKnowledge ) )
        {
        RMmCustomAPI customApi;
        RMmCustomAPI::TGprsInformation gprsInfo;
        RMmCustomAPI::TGprsInformationPckg gprsInfoPckg( gprsInfo );
        TRequestStatus status( KErrNone );

        TInt ret = customApi.Open( iMobilePhone );

        if ( KErrNone == ret )
            {
            customApi.GetEGprsInfo( status, gprsInfoPckg );
            User::WaitForRequest( status );

            customApi.Close();

            if ( KErrNone == status.Int() )
                {
                if ( gprsInfoPckg().iGprsInfo == RMmCustomAPI::EEdgeGprs )
                    {
                    edgeStatus = ETrue;
                    }
                }
            else
                {
                LOGIT1("IsEdgeCell: Error, RMmCustomAPI.GetEGprsInfo() <%d>", status.Int())
                }
            }
        else
            {
            LOGIT1("IsEdgeCell: Error, RMmCustomAPI.Open() <%d>", ret)
            }
        }
    else
        {
        LOGIT("IsEdgeCell: KFeatureIdEdgeKnowledge not supported")
        }
    LOGTIMINGEND("CConnMonIAP::IsEdgeCell")

    LOGEXITFN1("CConnMonIAP::IsEdgeCell()", (TInt)edgeStatus)
    return edgeStatus;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::IsHsdpaCell
// -----------------------------------------------------------------------------
//
TBool CConnMonIAP::IsHsdpaCell()
    {
    LOGENTRFN("CConnMonIAP::IsHsdpaCell()")

    RPacketService::TDynamicCapsFlags dynamicCaps( 0 );
    TBool hsdpaStatus( EFalse );

    LOGTIMINGSTART("CConnMonIAP::IsHsdpaCell")

    TInt ret = iPacketService.GetDynamicCaps( dynamicCaps );
    if ( dynamicCaps & RPacketService::KCapsHSDPA )
        {
        hsdpaStatus = ETrue;
        }
    LOGTIMINGEND("CConnMonIAP::IsHsdpaCell")
    LOGIT2("IsHsdpaCell: Dynamic caps 0x%06X <%d>", dynamicCaps, ret)

    LOGEXITFN1("CConnMonIAP::IsHsdpaCell()", (TInt)hsdpaStatus)
    return hsdpaStatus;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::HsxpaStatus
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::HsxpaStatus()
    {
    LOGENTRFN("CConnMonIAP::HsxpaStatus()")

    RPacketService::TDynamicCapsFlags dynamicCaps( 0 );
    TInt hspaState( EBearerInfoWCDMA );

    LOGTIMINGSTART("CConnMonIAP::HsxpaStatus")

    TInt ret = iPacketService.GetDynamicCaps( dynamicCaps );
    if ( dynamicCaps & RPacketService::KCapsHSDPA )
        {
        if ( dynamicCaps & RPacketService::KCapsHSUPA )
            {
            hspaState = EBearerInfoHSxPA;
            }
        else
            {
            hspaState = EBearerInfoHSDPA;
            }
        }
    else
        {
        if ( dynamicCaps & RPacketService::KCapsHSUPA )
            {
            hspaState = EBearerInfoHSUPA;
            }
        else
            {
            hspaState = EBearerInfoWCDMA;
            }
        }
    LOGTIMINGEND("CConnMonIAP::HsxpaStatus")
    LOGIT2("HsxpaStatus: Dynamic caps 0x%06X <%d>", dynamicCaps, ret)

    LOGEXITFN1("CConnMonIAP::HsxpaStatus()", hspaState)
    return hspaState;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetStartTime
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetStartTime( const TUint& aConnectionId, TTime& aTime )
    {
    TInt err( KErrNone );

    // Find connection matching the given Id
    TInt index = Index( aConnectionId );

    if ( index < 0  )
        {
        return KErrNotFound;
        }

    if ( iConnInfos[index].iBearer < EBearerExternalCSD
         && iConnInfos[index].iBearerInfo.iBearer <= EBearerInfoHSxPA )
        {
        // INTERNAL CONNECTIONS
        TUint subConnectionCount( 0 );

        // Find the start time of the earliest subconnection
        err = iConnInfos[index].iConnAttach->EnumerateSubConnections( subConnectionCount );

        if ( KErrNone != err )
            {
            return err;
            }

        LOGIT1("GetStartTime: Sub connection count %d", subConnectionCount)
        for ( TUint i = 1; i <= subConnectionCount; i++ )
            {
            TSubConnectionInfo subInfo;
            TPckg<TSubConnectionInfo> pckgSubInfo( subInfo );

            err = iConnInfos[index].iConnAttach->GetSubConnectionInfo( i, pckgSubInfo );

            if ( KErrNone != err )
                {
                LOGIT2("GetStartTime: Error getting conn.info for index %d, <%d>", i, err)
                return err;
                }

            if ( i == 1 )
                {
                aTime = pckgSubInfo().iTimeStarted;
                }
            else if ( aTime > pckgSubInfo().iTimeStarted )
                {
                aTime = pckgSubInfo().iTimeStarted;
                }
            }
        }
    else if ( iConnInfos[index].iBearer == EBearerExternalGPRS     ||
              iConnInfos[index].iBearer == EBearerExternalEdgeGPRS ||
              iConnInfos[index].iBearer == EBearerExternalWCDMA    ||
              iConnInfos[index].iBearer == EBearerExternalCDMA2000 ||
              ( !iConnInfos[index].iBearerInfo.iInternal &&
                ( iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSDPA ||
                  iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSUPA ||
                  iConnInfos[index].iBearerInfo.iBearer == EBearerInfoHSxPA ) ) )
        {
        // EXTERNAL PSD
        if ( iPsdFax )
            {
            err = iPsdFax->GetStartTime( aConnectionId, aTime );

            if ( KErrNone != err )
                {
                return err;
                }
            }
        else
            {
            return KErrNotFound;
            }
        }
    else if ( iConnInfos[index].iBearer == EBearerExternalCSD   ||
              iConnInfos[index].iBearer == EBearerExternalHSCSD ||
              iConnInfos[index].iBearer == EBearerExternalWcdmaCSD )
        {
        // EXTERNAL CSD
        if ( iCsdFax )
            {
            err = iCsdFax->GetStartTime( aTime );

            if ( KErrNone != err )
                {
                return err;
                }
            }
        else
            {
            err = KErrNotFound;
            }
        }
    else
        {
        return KErrNotSupported;
        }

    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetBearer
// Gets the bearer setting for the internal connections.
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetBearer(
        const TUint& aConnectionId,
        TInt& aBearer,
        TBearerInfo& aBearerInfo )
    {
    TInt err( KErrNone );
    TUint32 bearerType( EBearerUnknown );
    TBuf<KCommsDbSvrMaxFieldLength> settingName;
    TBuf<KCommsDbSvrMaxFieldLength> settingValue;

    LOGENTRFN("CConnMonIAP::GetBearer()")

    // Find connection matching the given Id
    TInt index = Index( aConnectionId );
    if ( index < 0 )
        {
        LOGEXITFN1("CConnMonIAP::GetBearer()", KErrNotFound)
        return KErrNotFound;
        }

    if ( iConnInfos[index].iConnAttach == 0 )
        {
        LOGIT("GetBearer: error, iConnAttach was NULL")
        LOGEXITFN1("CConnMonIAP::GetBearer()", KErrArgument)
        return KErrArgument;
        }

    // Find out BEARER TYPE
    settingName.Copy( TPtrC( IAP ) );
    settingName.Append( TChar( '\\' ) );
    settingName.Append( TPtrC( IAP_BEARER_TYPE ) );

    err = iConnInfos[index].iConnAttach->GetDesSetting( TPtrC( settingName ), settingValue );
    if ( KErrNone != err )
        {
        LOGIT1("GetBearer: ERROR getting IAP bearer type <%d>", err)
        LOGEXITFN1("CConnMonIAP::GetBearer()", err)
        return err;
        }

    if ( settingValue == TPtrC( VIRTUAL_BEARER ) )
        {
        aBearer = EBearerVirtual;
        aBearerInfo.iBearer = EBearerInfoVirtual;
        aBearerInfo.iInternal = ETrue;
        }

    // Find out SERVICE TYPE
    settingName.Copy( TPtrC( IAP ) );
    settingName.Append( TChar( '\\' ) );
    settingName.Append( TPtrC( IAP_SERVICE_TYPE ) );

    err = iConnInfos[index].iConnAttach->GetDesSetting( TPtrC( settingName ), settingValue );
    if ( KErrNone != err )
        {
        LOGIT1("GetBearer: ERROR getting IAP service type <%d>", err)
        LOGEXITFN1("CConnMonIAP::GetBearer()", err)
        return err;
        }

    // Is this virtual bearer + VPN service
    if ( ( aBearer == EBearerVirtual ) && ( settingValue == TPtrC( VPN_SERVICE ) ) )
        {
        aBearer = EBearerVirtualVPN;
        aBearerInfo.iBearer = EBearerInfoVirtualVPN;
        aBearerInfo.iInternal = ETrue;
        }

    // Return if bearer has been solved
    if ( aBearer != EBearerUnknown )
        {
        LOGEXITFN1("CConnMonIAP::GetBearer()", KErrNone)
        return KErrNone;
        }

    // Study service type if bearer is still unknown
    if ( settingValue == TPtrC( DIAL_OUT_ISP ) || settingValue == TPtrC( DIAL_IN_ISP ) )
        {
        LOGIT("GetBearer: type is dial_x_isp")
        settingName.Copy( settingValue );
        settingName.Append( TChar( '\\' ) );
        settingName.Append( TPtrC( ISP_BEARER_TYPE ) );

        err = iConnInfos[index].iConnAttach->GetIntSetting( TPtrC( settingName ), bearerType );

        if ( KErrNone != err )
            {
            return err;
            }

        if ( bearerType == EBearerTypeCSD )
            {
            aBearer = EBearerCSD;
            aBearerInfo.iBearer = EBearerInfoCSD;
            aBearerInfo.iInternal = ETrue;
            }
        else
            {
            // EBearerTypeHSCSD
            aBearer = EBearerHSCSD;
            aBearerInfo.iBearer = EBearerInfoHSCSD;
            aBearerInfo.iInternal = ETrue;
            }

        if ( iTSYLoaded )
            {
            RMobilePhone::TMobilePhoneNetworkMode mode;

            err = iMobilePhone.GetCurrentMode( mode );

            if ( ( KErrNone == err ) && ( mode == RMobilePhone::ENetworkModeWcdma ) )
                {
                aBearer = EBearerWcdmaCSD;
                aBearerInfo.iBearer = EBearerInfoWcdmaCSD;
                aBearerInfo.iInternal = ETrue;
                }
            }

        if ( aBearer == EBearerHSCSD || aBearer == EBearerCSD )
            {
            // If TsyName == PHONETSY try to find out the real life situation (CSD/HSCSD) from ETel
            // For point-to-point connections TSY is NOT PHONETSY.
            settingName.Copy( TPtrC( IAP ) );
            settingName.Append( TChar( '\\' ) );
            settingName.Append( TPtrC( IAP_BEARER_TYPE ) );

            err = iConnInfos[index].iConnAttach->GetDesSetting(
                    TPtrC( settingName ),
                    settingValue );

            if ( ( KErrNone == err ) && ( settingValue == TPtrC( MODEM_BEARER ) ) )
                {
                settingName.Copy( TPtrC( MODEM_BEARER ) );
                settingName.Append( TChar( '\\' ) );
                settingName.Append( TPtrC( MODEM_TSY_NAME ) );

                err = iConnInfos[index].iConnAttach->GetDesSetting(
                        TPtrC( settingName ),
                        settingValue );

                TBuf<KConnMonSmallBufferLen> tmp( KMmTsyModuleName );
                tmp.UpperCase();

                if ( ( KErrNone == err ) && ( settingValue == tmp ) )
                    {
                    // TSY is PHONETSY
                    TBuf<KConnMonSmallBufferLen> number;

                    err = GetTelNumber( aConnectionId, number );

                    if ( KErrNone == err )
                        {
                        GetBearerFromETel( number, aBearer, aBearerInfo );
                        }
                    }
                }
            }
        }
    else if ( settingValue == TPtrC( OUTGOING_WCDMA ) ||
              settingValue == TPtrC( INCOMING_WCDMA ) )
        {
        LOGIT("GetBearer: type is wcdma")
        if ( iTSYLoaded )
            {
            RMobilePhone::TMobilePhoneNetworkMode mode;
            err = iMobilePhone.GetCurrentMode( mode );
            LOGIT2("GetBearer: phone mode %d <%d>", (TInt)mode, err)
            if ( ( KErrNone != err ) ||
                 ( mode == RMobilePhone::ENetworkModeUnknown ) ||
                 ( mode == RMobilePhone::ENetworkModeUnregistered ) )
                {
                // MODE is UNKNOWN
                LOGIT2("GetBearer: mode is unknown %d <%d>", mode, err)
                if ( FeatureManager::FeatureSupported( KFeatureIdProtocolGsm ) )
                    {
                    // KFeatureIdProtocolGsm means that phone supports only GSM
                    if ( IsEdgeCell() )
                        {
                        aBearer = EBearerEdgeGPRS;
                        aBearerInfo.iBearer = EBearerInfoEdgeGPRS;
                        }
                    else
                        {
                        aBearer = EBearerGPRS;
                        aBearerInfo.iBearer = EBearerInfoGPRS;
                        }
                    aBearerInfo.iInternal = ETrue;
                    }
                else
                    {
                    LOGIT("GetBearer: KFeatureIdProtocolGsm not supported")
                    }
                }
            else
                {
                // MODE is KNOWN
                if ( mode == RMobilePhone::ENetworkModeWcdma )
                    {
                    aBearer = EBearerWCDMA;
                    aBearerInfo.iBearer = HsxpaStatus();
                    aBearerInfo.iInternal = ETrue;
                    }
                else if ( mode == RMobilePhone::ENetworkModeGsm )
                    {
                    if ( IsEdgeCell() )
                        {
                        aBearer = EBearerEdgeGPRS;
                        aBearerInfo.iBearer = EBearerInfoEdgeGPRS;
                        }
                    else
                        {
                        aBearer = EBearerGPRS;
                        aBearerInfo.iBearer = EBearerInfoGPRS;
                        }
                    aBearerInfo.iInternal = ETrue;
                    }
                else
                    {
                    LOGIT1("GetBearer: error, mode was unexpected %d", mode)
                    }
                }
            }
        }

    else if ( settingValue == TPtrC( LAN_SERVICE ) )
        {
        LOGIT("GetBearer: type is (w)lan")
        aBearer = EBearerLAN;
        aBearerInfo.iBearer = EBearerInfoLAN;
        aBearerInfo.iInternal = ETrue;

        settingName.FillZ();
        settingValue.FillZ();
        settingName.Copy( TPtrC( LAN_BEARER ) );
        settingName.Append( TChar( '\\' ) );
        settingName.Append( TPtrC( COMMDB_NAME ) );

        err = iConnInfos[index].iConnAttach->GetDesSetting( TPtrC( settingName ), settingValue );

        if ( KErrNone != err )
            {
            return err;
            }

        if ( settingValue == TPtrC( KWlanBearerRecordName ) )
            {
            aBearer = EBearerWLAN;
            aBearerInfo.iBearer = EBearerInfoWLAN;
            }
        }
    LOGIT2("GetBearer: bearer %d, bearerInfo %d", aBearer, aBearerInfo.iBearer)
    LOGEXITFN1("CConnMonIAP::GetBearer()", err)
    return err;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::UpdateActivity
// Updates connection activity information.
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::UpdateActivity( const TUint& aConnectionId, const TUint& aActivity )
    {
    // Find connection matching the given Id
    TInt index = Index( aConnectionId );

    if ( index < 0  )
        {
        return KErrNotFound;
        }

    if ( aActivity == 0 )
        {
        iConnInfos[index].iActivity = 0;
        }
    else
        {
        iConnInfos[index].iActivity = 1;
        }

    return KErrNone;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::GetDeleteNotifyStatus
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::GetDeleteNotifyStatus( TConnInfo& aConnection, TBool& aSent )
    {
    TInt index( KErrNotFound );

    if ( aConnection.iBearer >= EBearerExternalCSD )
        {
        return KErrNotSupported;
        }

    index = iConnInfos.Find( aConnection, TConnInfo::MatchIap );

    if ( index < 0 )
        {
        return KErrNotFound;
        }

    aConnection.iConnectionId = iConnInfos[index].iConnectionId;
    aConnection.iBearer = iConnInfos[index].iBearer;

    TInt connectionStatus( 0 );
    GetConnectionStatus( index, connectionStatus );

    if ( ( iConnInfos[index].iConnDownNotifier != 0 ) &&
         ( iConnInfos[index].iProgressNotifier != 0 ) )
        {
        if ( !iConnInfos[index].iConnDownNotifier->DeleteSent() &&
             !iConnInfos[index].iConnDownNotifier->IsActive() &&
             ( !iConnInfos[index].iProgressNotifier->IsActive() ||
               ( connectionStatus != KLinkLayerOpen ) ) )
            {
            aSent = EFalse;
            }
        else
            {
            aSent = ETrue;
            }
        }
    else
        {
        aSent = EFalse;
        }

    return KErrNone;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::GetActivityNotifier
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::GetActivityNotifier(
        const TUint& aConnectionId,
        CActivityNotifier** aActivityNotifier )
    {
    // Find connection matching the given Id
    TInt index = Index( aConnectionId );

    if ( index < 0  )
        {
        return KErrNotFound;
        }

    if ( aActivityNotifier == 0 )
        {
        return KErrUnknown;
        }

    *aActivityNotifier = iConnInfos[ index ].iActivityNotifier;

    return KErrNone;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::GetProgressNotifier
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::GetProgressNotifier(
        const TUint& aConnectionId,
        CProgressNotifier** aProgressNotifier )
    {
    // Find connection matching the given Id
    TInt index = Index( aConnectionId );

    if ( index < 0  )
        {
        return KErrNotFound;
        }

    if ( aProgressNotifier == 0 )
        {
        return KErrUnknown;
        }

    *aProgressNotifier = iConnInfos[index].iProgressNotifier;

    return KErrNone;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::GetSubConnUpDownNotifier
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::GetSubConnUpDownNotifier(
        const TUint& aConnectionId,
        CSubConnUpDownNotifier** aSubConnUpDownNotifier )
    {
    // Find connection matching the given Id
    TInt index = Index( aConnectionId );

    if ( index < 0  )
        {
        return KErrNotFound;
        }

    if ( aSubConnUpDownNotifier == 0 )
        {
        return KErrUnknown;
        }

    *aSubConnUpDownNotifier = iConnInfos[index].iConnDownNotifier;

    return KErrNone;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::WakeUpNotifications
// Wakes up sleeping CONNECTION SPECIFIC event watchers that depend on a threshold.
// (data volume, activity).
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::WakeUpNotifications( const TUint& aConnectionId )
    {
    // Find connection matching the given Id
    TInt index = Index( aConnectionId );

    if ( index < 0  )
        {
        return KErrNotFound;
        }

    if ( ( iConnInfos[index].iBearer < EBearerExternalCSD ) &&  ( iCountListeners > 0 ) )
        {
        // INTERNAL CONNECTIONS
        TInt connectionStatus( 0 );
        GetConnectionStatus( index, connectionStatus );

        if ( ( connectionStatus == KLinkLayerOpen ) || ( connectionStatus == KPsdSuspended ) )
            {
            // -------------------------
            // Amount of Downlink data
            // -------------------------
            if ( iConnInfos[index].iDLDataNotifier != 0 )
                {
                if ( !iConnInfos[index].iDLDataNotifier->IsActive() )
                    {
                    iConnInfos[index].iDLDataNotifier->Receive(); // (re)start listening
                    }
                }

            // -------------------------
            // Amount of Uplink data
            // -------------------------
            if ( iConnInfos[index].iULDataNotifier != 0 )
                {
                if ( !iConnInfos[index].iULDataNotifier->IsActive() )
                    {
                    iConnInfos[index].iULDataNotifier->Receive(); // (re)start listening
                    }
                }

            // ----------------------
            // Connection Activity
            // ----------------------
            if ( iConnInfos[index].iActivityNotifier != 0 )
                {
                if ( !iConnInfos[index].iActivityNotifier->IsActive() )
                    {
                    iConnInfos[index].iActivityNotifier->Receive( iConnInfos[index].iActivity );
                    }
                }

            if ( iConnInfos[index].iBearerNotifier )
                {
                if ( !iConnInfos[index].iBearerNotifier->Listening() )
                    {
                    iConnInfos[index].iBearerNotifier->Listen();
                    }
                }
            }
        }

    return KErrNone;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::WakeUpNotifications
// Wakes up GENERAL sleeping event watchers that depend on a threshold.
// (signal strength, bearer availability).
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::WakeUpNotifications()
    {
    if ( iGSMSignalNotifier != 0 )
        {
        if ( !iGSMSignalNotifier->IsActive() )
            {
            iGSMSignalNotifier->Receive(); // (re)start listening
            }
        }

    if ( iGSMBearerAvailabilityNotifier != 0 )
        {
        if ( !iGSMBearerAvailabilityNotifier->IsActive() )
            {
            iGSMBearerAvailabilityNotifier->Receive(); // (re)start listening
            }
        }

    return KErrNone;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::LaunchActivityNotifierL
// Launches the activity notifier for the given connection id.
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::LaunchActivityNotifierL( const TUint& aConnectionId )
    {
    TInt index = Index( aConnectionId );

    if ( index < 0  )
        {
        return KErrNotFound;
        }

    GetActivityOneShotL( index );
    return KErrNone;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::LaunchDataNotifiers
// Launches the data notifiers (uplink & downlink) for the given connection id.
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::LaunchDataNotifiers( const TUint& aConnectionId )
    {
    TInt index = Index( aConnectionId );

    if ( index < 0  )
        {
        return KErrNotFound;
        }

    if ( iConnInfos[index].iDLDataNotifier != 0 )
        {
        if ( !iConnInfos[index].iDLDataNotifier->IsActive() )
            {
            iConnInfos[index].iDLDataNotifier->Receive();
            }
        }

    if ( iConnInfos[index].iULDataNotifier != 0 )
        {
        if ( !iConnInfos[index].iULDataNotifier->IsActive() )
            {
            iConnInfos[index].iULDataNotifier->Receive();
            }
        }

    return KErrNone;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::LaunchDataNotifiers
// Launches the data notifiers (uplink & downlink) for the given connection id.
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::LaunchBearerNotifier( const TUint& aConnectionId )
    {
    TInt index = Index( aConnectionId );

    if ( index < 0  )
        {
        return KErrNotFound;
        }

    if ( iConnInfos[index].iBearerNotifier )
        {
        if ( !iConnInfos[index].iBearerNotifier->Listening() )
            {
            iConnInfos[index].iBearerNotifier->Listen();
            }
        }

    return KErrNone;
    }


// -----------------------------------------------------------------------------
// CConnMonIAP::AppendActiveConnections
// -----------------------------------------------------------------------------
//
void CConnMonIAP::GetActiveConnectionsIds( const TUint& aBearerId, RArray<TUint>& aIdArray )
    {
    //LOGENTRFN("CConnMonIAP::GetActiveConnectionsIds()")

    const TInt count = iConnInfos.Count();
    for ( TInt i = 0; i < count; i++ )
        {
        // Bearer might still be uninitialized
        if ( iConnInfos[i].iBearer == EBearerUnknown )
            {
            LOGIT1("GetActiveConnectionsIds: bearer unknown for conn.id %d",
                    iConnInfos[i].iConnectionId)
            TInt err = GetBearer(
                    iConnInfos[i].iConnectionId,
                    iConnInfos[i].iBearer,
                    iConnInfos[i].iBearerInfo );

            if ( KErrNone != err )
                {
                // Skip because bearer is unknown. This connection has not yet fully started.
                continue;
                }
            }
        switch ( iConnInfos[i].iBearer )
            {
            case EBearerGPRS:
            case EBearerEdgeGPRS:
            case EBearerWCDMA:
                {
                if ( aBearerId == EBearerIdGPRS )
                    {
                    aIdArray.Append( iConnInfos[i].iIapId );
                    }
                }
                break;
            case EBearerWLAN:
                {
                if ( aBearerId == EBearerIdWLAN )
                    {
                    TInt connectionStatus( 0 );
                    GetConnectionStatus( i, connectionStatus );
                    if ( connectionStatus == KLinkLayerOpen )
                        {
                        aIdArray.Append( iConnInfos[i].iIapId );
                        }
                    }
                }
                break;
            case EBearerCSD:
            case EBearerHSCSD:
            case EBearerWcdmaCSD:
                {
                if ( aBearerId == EBearerIdCSD )
                    {
                    aIdArray.Append( iConnInfos[i].iIapId );
                    }
                }
                break;
            case EBearerLAN:
                {
                if ( aBearerId == EBearerIdLAN )
                    {
                    aIdArray.Append( iConnInfos[i].iIapId );
                    }
                }
                break;
            default:
                break;
            }
        }
    //LOGEXITFN("CConnMonIAP::GetActiveConnectionsIds()")
    }


// -----------------------------------------------------------------------------
// CConnMonIAP::GetBearerSupportInfo
// Checks whether the current cell and the phone support a bearer (GPRS or CSD).
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetBearerSupportInfo(
        const TUint aConnectionId,
        TBool& aByCell,
        TBool& aByPhone ) const
    {
    LOGENTRFN("CConnMonIAP::GetBearerSupportInfo()")
    TInt err( KErrNone );

    aByCell = EFalse;
    aByPhone = EFalse;

    if ( !iTSYLoaded  )
        {
        LOGIT("GetBearerSupportInfo: ERROR, TSY not loaded")
        LOGEXITFN1("CConnMonIAP::GetBearerSupportInfo()", err)
        return err;
        }

    RPacketService::TDynamicCapsFlags capsDynamic( 0 );
    if ( iPacketServLoaded )
        {
        err = iPacketService.GetDynamicCaps( capsDynamic );
        if ( KErrNone != err )
            {
            LOGIT1("GetBearerSupportInfo: ERROR getting dynamic caps <%d>", err)
            capsDynamic = 0;
            }
        }

    if ( aConnectionId == EBearerIdGPRS || aConnectionId == EBearerIdWCDMA )
        {
        LOGIT2("GetBearerSupportInfo: GPRS and WCDMA, dynamic caps:   0x%04X <%d>", capsDynamic, err)

        // 1. Is GPRS/WCDMA supported by this NETWORK CELL
        if ( ( capsDynamic & RPacketService::KCapsManualAttach ) ||
             ( capsDynamic & RPacketService::KCapsManualDetach ) )
            {
            // Is the phone registered on the packet network
            RPacketService::TRegistrationStatus nwRegStatus( RPacketService::EUnknown );
            TRequestStatus status( KErrNone );
            iPacketService.GetNtwkRegStatus( status, nwRegStatus );
            User::WaitForRequest( status );

            LOGIT2("GetBearerSupportInfo: pckt service ntwrk reg status:  %d <%d>", nwRegStatus, status.Int())
            if ( KErrNone == status.Int() &&
                 nwRegStatus != RPacketService::ENotRegisteredNotSearching &&
                 nwRegStatus != RPacketService::ENotRegisteredSearching    &&
                 nwRegStatus != RPacketService::ERegistrationDenied        &&
                 nwRegStatus != RPacketService::ENotRegisteredAndNotAvailable )
                {
                // Query the TSY for the attach mode
                RPacketService::TAttachMode attachMode( RPacketService::EAttachWhenNeeded );
                err = iPacketService.GetAttachMode( attachMode );

                LOGIT2("GetBearerSupportInfo: pckt service attach mode:       %d <%d>", attachMode, err)
                // Query packet network status (but only if the TSY is set to attach when possible)
                if ( KErrNone == err && attachMode == RPacketService::EAttachWhenPossible )
                    {
                    RPacketService::TStatus pcktStatus( RPacketService::EStatusUnattached );
                    err = iPacketService.GetStatus( pcktStatus );

                    LOGIT2("GetBearerSupportInfo: pckt service status:            %d <%d>", pcktStatus, err)
                    if ( KErrNone == err && pcktStatus != RPacketService::EStatusUnattached )
                        {
                        aByCell = ETrue;
                        }
                    }
                else
                    {
                    // Attach mode is 'EAttachWhenNeeded'
                    aByCell = ETrue;
                    }
                }
            }

        // 2. Check the PHONE'S MODE if it is known
        TUint bearerId( 0 );
        err = GetBearerId( bearerId );

        // If phone mode query failed, mode is unknown, or bearer ID equals connection ID.
        if ( bearerId == 0 || bearerId == aConnectionId )
            {
            // 3. Check the PHONE'S MODE CAPABILITIES
            TUint32 capsPhone( 0 );
            err = iMobilePhone.GetMultimodeCaps( capsPhone );

            LOGIT2("GetBearerSupportInfo: mobile phone mode caps:         0x%04X <%d>", capsPhone, err)
            if ( KErrNone == err )
                {
                if ( aConnectionId == EBearerIdGPRS &&
                     ( capsPhone & RMobilePhone::KCapsGprsSupported ) )
                    {
                    aByPhone = ETrue;
                    }
                else if ( aConnectionId == EBearerIdWCDMA &&
                        ( capsPhone &
                        ( RMobilePhone::KCapsWcdmaSupported |
                        RMobilePhone::KCapsGprsSupported ) ) )
                    {
                    aByPhone = ETrue;
                    }
                }
            }
        }
    else if ( aConnectionId == EBearerIdCSD || aConnectionId == EBearerIdWcdmaCSD )
        {
        LOGIT2("GetBearerSupportInfo: CSD and WcdmaCSD, dynamic caps: 0x%04X <%d>", capsDynamic, err)

        // 1. Is CSD/WcdmaCSD supported by this NETWORK CELL
        if ( capsDynamic & RPacketService::KCapsRxCSCall )
            {
            // Has phone registered to the network
            TRequestStatus status( KErrNone );
            RMobilePhone::TMobilePhoneRegistrationStatus gsmReg(
                    RMobilePhone::ERegistrationUnknown );

            iMobilePhone.GetNetworkRegistrationStatus( status, gsmReg );
            User::WaitForRequest( status );

            LOGIT2("GetBearerSupportInfo: mobile phone reg status:        %d <%d>", gsmReg, status.Int())
            if ( KErrNone == status.Int() )
                {
                if ( gsmReg == RMobilePhone::ERegisteredBusy ||
                        gsmReg == RMobilePhone::ERegisteredOnHomeNetwork ||
                        gsmReg == RMobilePhone::ERegisteredRoaming )
                    {
                    aByCell = ETrue;
                    }
                }
            }

        // 2. Check the PHONE'S MODE if it is known
        TUint bearerId( 0 );
        err = GetBearerId( bearerId, ETrue );

        // If phone mode query failed, mode is unknown, or bearer ID equals connection ID.
        if ( bearerId == 0 || bearerId == aConnectionId )
            {
            // 3. Check the PHONE'S CAPABILITIES
            err = iTelServer.IsSupportedByModule(
                    KMmTsyModuleName,
                    KETelFuncMobileDataCall,
                    aByPhone );
            }
        }
    else
        {
        LOGIT1("GetBearerSupportInfo: invalid connection id: %d", aConnectionId)
        err = KErrArgument;
        }

    LOGIT2("GetBearerSupportInfo: by cell: %d, by phone: %d", aByCell, aByPhone)
    LOGEXITFN1("CConnMonIAP::GetBearerSupportInfo()", err)
    return err;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::GetBearerId
// Gets the bearer ID matching the phone's current mode.
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::GetBearerId( TUint& aBearerId, TBool aCsd ) const
    {
    aBearerId = 0;
    RMobilePhone::TMobilePhoneNetworkMode mode;
    TInt err = iMobilePhone.GetCurrentMode( mode );
    // If GetCurrentMode() failed for any reason, aBearerId will be 0.

    LOGIT2("CConnMonIAP::GetBearerId(): current phone mode %d <%d>", mode, err)
    if ( err == KErrNone )
        {
        switch ( mode )
            {
            case RMobilePhone::ENetworkModeWcdma:
                if ( aCsd )
                    {
                    aBearerId  = EBearerIdWcdmaCSD;
                    }
                else
                    {
                    aBearerId  = EBearerIdWCDMA;
                    }
                break;

            case RMobilePhone::ENetworkModeGsm:
            case RMobilePhone::ENetworkModeUnknown: // Emulator default
                if ( aCsd )
                    {
                    aBearerId = EBearerIdCSD;
                    }
                else
                    {
                    aBearerId = EBearerIdGPRS;
                    }
                break;

            case RMobilePhone::ENetworkModeCdma2000:
                aBearerId = EBearerIdCDMA2000;
                break;

            // ENetworkModeUnregistered
            // ENetworkModeAmps
            // ENetworkModeCdma95
            // ENetworkModeTdcdma
            default:
                break;
            }
        }
    return err;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::Reconnect
// A new connection has been established by reconnecting to an old connection.
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::Reconnect( TUint& aConnectionId )
    {
    LOGENTRFN("CConnMonIAP::Reconnect()")
    TInt err( KErrNone );

    TInt index = Index( aConnectionId );
    if ( index < 0  )
        {
        //return KErrNotFound;
        err = KErrNotFound;
        }
    else
        {
        // Prevent ConnDown notifier from being deleted
        // It will destroy itself later in reconnect case.
        iConnInfos[index].iConnDownNotifier = 0;
        TBearerInfo bearerInfo( EBearerInfoUnknown, EFalse );

        TConnInfo connInfo( iConnInfos[index].iIapId, iConnInfos[index].iNetId, 0, 0, bearerInfo );

        // AddConnectionL will remove the old connection
        TInt err2( KErrNone );
        TRAP( err2, ( err = AddConnectionL( connInfo ) ) );
        if ( ( err2 != KErrNone ) || ( err != KErrNone ) )
            {
            err = KErrUnknown;
            }
        else
            {
            aConnectionId = connInfo.iConnectionId;
            }
        }

    LOGEXITFN1("CConnMonIAP::Reconnect()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::WlanSupportCheck
//
// Returns KErrNone if the given connection ID is EBearerIdWLAN, or belongs to
// an active connection where bearer has been marked as EBearerIdWLAN.
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::WlanSupportCheck( const TUint& aConnectionId )
    {
    LOGENTRFN("CConnMonIAP::WlanSupportCheck()")
    TInt ret( KErrNotSupported );

    // Check if WLAN is supported at all
    if ( !iWlanSupport )
        {
        LOGIT("WlanSupportCheck: no WLAN support")
        ret = KErrNotSupported;
        }
    else
        {
        if ( EBearerIdWLAN == aConnectionId )
            {
            ret = KErrNone;
            }
        else
            {
            // Find connection matching the given ID
            TInt index = Index( aConnectionId );
            LOGIT2("WlanSupportCheck: checking connection id %d, index %d ", aConnectionId, index)
            if ( index < 0 )
                {
                ret = KErrArgument;
                }
            else
                {
                // Connection found, check if bearer is EBearerWLAN
                if ( EBearerWLAN == iConnInfos[index].iBearer )
                    {
                    ret = KErrNone;
                    }
                else
                    {
                    LOGIT1("WlanSupportCheck: connection bearer %d is not WLAN", iConnInfos[index].iBearer)
                    ret = KErrArgument;
                    }
                }
            }
        }

    LOGEXITFN1("CConnMonIAP::WlanSupportCheck()", ret)
    return ret;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::AppendAvailableWLANIaps
// Gets available WLAN IAPs from WLAN engine.
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::AppendAvailableWLANIaps( RArray<TUint>& aIdArray )
    {
    //LOGENTRFN("CConnMonIAP::AppendAvailableWLANIaps()")
    TInt err( KErrNone );

    if ( !iWlanSupport )
        {
        LOGIT("AppendAvailableWLANIaps: No WLAN support")
        err = KErrNotSupported;
        }
    else
        {
        err = iWlanSupport->AppendAvailableIaps( aIdArray );
        }

    //LOGEXITFN1("CConnMonIAP::AppendAvailableWLANIaps()", err)
    return err;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::AppendAvailableWLANIapsBySsid
// Gets available WLAN IAPs from CommsDat, matching with current WLAN connection SSID.
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::AppendAvailableWLANIapsBySsid( RArray<TUint>& aIdArray )
    {
    //LOGENTRFN("CConnMonIAP::AppendAvailableWLANIapsBySsid()")
    TInt err( KErrNone );

    if ( !iWlanSupport )
        {
        LOGIT("AppendAvailableWLANIapsBySsid: No WLAN support")
        err = KErrNotSupported;
        }
    else
        {
        TRAPD( err2, err = iWlanSupport->AppendAvailableIapsBySsidL( aIdArray ) );
        if ( err2 != KErrNone )
            {
            LOGIT1("AppendAvailableWLANIapsBySsid: error, LEAVE <%d> from AppendAvailableIapsBySsidL()", err2)
            err = err2;
            }
        }

    //LOGEXITFN1("CConnMonIAP::AppendAvailableWLANIapsBySsid()", err)
    return err;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::EnableWlanScan
// Enables WLAN scan for the next iap availability query.
// -----------------------------------------------------------------------------------
//
void CConnMonIAP::EnableWlanScan()
    {
    if ( iWlanSupport )
        {
        iWlanSupport->EnableWlanScan();
        }
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::DtmStateChanged
// -----------------------------------------------------------------------------
//
void CConnMonIAP::DtmStateChanged()
    {
    LOGENTRFN("CConnMonIAP::DtmStateChanged()")

    TEventInfo eventInfo;
    eventInfo.Reset();

    // When not in dual mode and call is active, gprs and wcdma bearers are unavailable
    // Note that even the WCDMA can be unavailable, if the phone doesn't support DTM
    if ( iDualTransferModeNotifier && !iDualTransferModeNotifier->IsInDualMode() &&
            iTelephonyNotifier && iTelephonyNotifier->IsCallActive() )
        {
        LOGIT("SERVER: DtmStateChanged: Packet data UNAVAILABLE (2G&3G), no DTM and call is active")
        eventInfo.iEventType = EConnMonPacketDataUnavailable;

        // Send event to all clients that are listening for bearer EBearerIdGPRS
        LOGIT("SERVER: EVENT -> Packet data UNAVAILABLE (GPRS), no DTM and call is active")
        eventInfo.iConnectionId = EBearerIdGPRS;
        iServer->EventQueue()->Add( eventInfo ); // Create bearer availability event if needed

        // Send event to all clients that are listening for bearer EBearerIdWCDMA
        LOGIT("SERVER: EVENT -> Packet data UNAVAILABLE (WCDMA), no DTM and call is active")
        eventInfo.iConnectionId = EBearerIdWCDMA;
        iServer->EventQueue()->Add( eventInfo );
        }
    else
        {
        TBool byPhone( EFalse );
        TBool byCell( EFalse );

        // Lets check if GPRS bearer is available at all
        TInt ret = GetBearerSupportInfo( EBearerIdGPRS, byCell, byPhone );
        LOGIT2("Bearer support (GPRS): byCell %d, byPhone %d", byCell, byPhone)
        if ( ret != KErrNone )
            {
            LOGIT1("SERVER: DtmStateChanged: GetBearerSupportInfo (GPRS) returned error <%d>", ret)
            return; // No event on error
            }

        eventInfo.iConnectionId = EBearerIdGPRS;
        if ( byCell && byPhone )
            {
            LOGIT("SERVER: EVENT -> Packet data AVAILABLE (GPRS), DTM or no call is active")
            eventInfo.iEventType = EConnMonPacketDataAvailable;
            }
        else
            {
            LOGIT("SERVER: EVENT -> Packet data UNAVAILABLE (GPRS), no GPRS bearer")
            eventInfo.iEventType = EConnMonPacketDataUnavailable;
            }
        // Send event to all clients that are listening for bearer EBearerIdGPRS
        iServer->EventQueue()->Add( eventInfo );


        // Same for WCDMA as for GPRS above
        ret = GetBearerSupportInfo( EBearerIdWCDMA, byCell, byPhone );
        LOGIT2("Bearer support (WCDMA): byCell %d, byPhone %d", byCell, byPhone)
        if ( ret != KErrNone )
            {
            LOGIT1("SERVER: DtmStateChanged: GetBearerSupportInfo (WCDMA) returned error <%d>", ret)
            return; // No event on error
            }

        eventInfo.iConnectionId = EBearerIdWCDMA;
        if ( byCell && byPhone )
            {
            LOGIT("SERVER: EVENT -> Packet data AVAILABLE (WCDMA), DTM or no call is active")
            eventInfo.iEventType = EConnMonPacketDataAvailable;
            }
        else
            {
            LOGIT("SERVER: EVENT -> Packet data UNAVAILABLE (WCDMA), no WCDMA bearer")
            eventInfo.iEventType = EConnMonPacketDataUnavailable;
            }
        // Send event to all clients that are listening for bearer EBearerIdWCDMA
        iServer->EventQueue()->Add( eventInfo );
        }

    LOGEXITFN("CConnMonIAP::DtmStateChanged()")
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::PhoneLineStatusChange
// -----------------------------------------------------------------------------
//
void CConnMonIAP::PhoneLineStatusChange()
    {
    LOGENTRFN("CConnMonIAP::PhoneLineStatusChange()")

    // At this time the implementation would be identical
    // to DtmStateChanged so we just call it
    DtmStateChanged();

    LOGEXITFN("CConnMonIAP::PhoneLineStatusChange()")
    }


// PRIVATE METHODS BELOW

// -----------------------------------------------------------------------------------
// CConnMonIAP::OpenAndAttachTo
// Opens and attaches an RConnection instance.
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::OpenAndAttachTo( TConnInfo& aConnInfo )
    {
    //LOGENTRFN("CConnMonIAP::OpenAndAttachTo()")
    TInt err( KErrNone );
    TConnectionInfo info;
    TPckg<TConnectionInfo> pckgInfo( info );

    // Leave left out intentionally, check for NULL instead
    aConnInfo.iConnAttach = new RConnection(); // No (ELeave)
    if ( !aConnInfo.iConnAttach )
        {
        err = KErrNoMemory;
        }
    if ( KErrNone == err )
        {
        err = aConnInfo.iConnAttach->Open( iSocketServer, KAfInet );
        }

    if ( KErrNone == err )
        {
        info.iIapId = aConnInfo.iIapId;
        info.iNetId = aConnInfo.iNetId;

        err = aConnInfo.iConnAttach->Attach( pckgInfo, RConnection::EAttachTypeMonitor );
        if ( err != KErrNone )
            {
            aConnInfo.iConnAttach->Close();
            delete aConnInfo.iConnAttach;
            }
        }

    //LOGEXITFN1("CConnMonIAP::OpenAndAttachTo()", err)
    return err;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::StopConnection
// Closes a connection.
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::StopConnection( const TInt aIndex )
    {
    LOGENTRFN("CConnMonIAP::StopConnection()")
    TInt err( KErrNone );

    if ( ( aIndex < 0 ) || ( aIndex >= iConnInfos.Count() ) )
        {
        LOGEXITFN1("CConnMonIAP::StopConnection()", KErrArgument)
        return KErrArgument;
        }

    if ( iConnInfos[aIndex].iBearer < EBearerExternalCSD )
        {
        // Stop an internal connection
        RConnection connection;
        TConnectionInfo info;

        // Cancel data volume and activity notifiers before stopping
        if ( iConnInfos[aIndex].iDLDataNotifier != 0 )
            {
            iConnInfos[aIndex].iDLDataNotifier->Cancel();
            }
        if ( iConnInfos[aIndex].iULDataNotifier != 0 )
            {
            iConnInfos[aIndex].iULDataNotifier->Cancel();
            }
        if ( iConnInfos[aIndex].iDataVolumeAO != 0 )
            {
            iConnInfos[aIndex].iDataVolumeAO->Cancel();
            }
        if ( iConnInfos[aIndex].iActivityNotifier != 0 )
            {
            iConnInfos[aIndex].iActivityNotifier->Cancel();
            }

        // RConnection object with EAttachTypeNormal is needed for stopping
        err = connection.Open( iSocketServer, KAfInet );
        if ( KErrNone == err )
            {
            info.iIapId = iConnInfos[aIndex].iIapId;
            info.iNetId = iConnInfos[aIndex].iNetId;

            err = connection.Attach( TPckg<TConnectionInfo>( info ),
                    RConnection::EAttachTypeNormal );
            if ( KErrNone == err )
                {
                err = connection.Stop( RConnection::EStopAuthoritative );
                if ( KErrNone == err )
                    {
                    // Stop notifications, delete connection settings and remove from the table
                    // If conn up/down notifier is active, let the event remove connection later.
                    if ( !iConnUpDownNotifier || !iConnUpDownNotifier->IsActive() )
                        {
                        RemoveConnection( iConnInfos[aIndex] );
                        }
                    }
                else
                    {
                    LOGIT1("StopConnection: RConnection::Stop() failed <%d>", err)
                    }
                }
            else
                {
                LOGIT1("StopConnection: RConnection::Attach() failed <%d>", err)
                }
            connection.Close();
            }
        else
            {
            LOGIT1("StopConnection: RConnection::Open() failed <%d>", err)
            }
        }

    else if ( iConnInfos[aIndex].iBearer == EBearerExternalGPRS     ||
              iConnInfos[aIndex].iBearer == EBearerExternalEdgeGPRS ||
              iConnInfos[aIndex].iBearer == EBearerExternalWCDMA    ||
              iConnInfos[aIndex].iBearer == EBearerExternalCDMA2000 ||
              ( !iConnInfos[aIndex].iBearerInfo.iInternal &&
                ( iConnInfos[aIndex].iBearerInfo.iBearer == EBearerInfoHSDPA ||
                  iConnInfos[aIndex].iBearerInfo.iBearer == EBearerInfoHSUPA ||
                  iConnInfos[aIndex].iBearerInfo.iBearer == EBearerInfoHSxPA ) ) )
        {
        // EXTERNAL PSD
        if ( iPsdFax )
            {
            err = iPsdFax->Stop( iConnInfos[aIndex].iConnectionId );
            }
        else
            {
            err = KErrNotFound;
            }
        }

    else if ( iConnInfos[aIndex].iBearer == EBearerExternalCSD   ||
              iConnInfos[aIndex].iBearer == EBearerExternalHSCSD ||
              iConnInfos[aIndex].iBearer == EBearerExternalWcdmaCSD )
        {
        // EXTERNAL CSD
        if ( iCsdFax )
            {
            err = iCsdFax->Stop();
            }
        else
            {
            err = KErrNotFound;
            }
        }
    else
        {
        err = KErrNotSupported;
        }

    LOGEXITFN1("CConnMonIAP::StopConnection()", err)
    return err;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::AddConnNotificationsL
// Adds connection specific event watchers (connection status, data volume, activity).
// -----------------------------------------------------------------------------------
//
void CConnMonIAP::AddConnNotificationsL( const TInt& aIndex )
    {
    LOGENTRFN("CConnMonIAP::AddConnNotificationsL()")

    if ( iConnInfos[aIndex].iBearer < EBearerExternalCSD )
        {
        // INTERNAL CONNECTIONS
        TInt connectionStatus( 0 );
        GetConnectionStatus( aIndex, connectionStatus );

        // ----------------------
        // Connection Status
        // ----------------------
        if ( iConnInfos[aIndex].iProgressNotifier == 0 )
            {
            TInt subConnectionId( 0 );

            // Create an active object and add it to scheduler
            iConnInfos[aIndex].iProgressNotifier = new( ELeave ) CProgressNotifier(
                    iServer,
                    iConnInfos[aIndex].iConnAttach,
                    iConnInfos[aIndex].iConnectionId,
                    subConnectionId );

            iConnInfos[aIndex].iProgressNotifier->Construct();

            if ( iConnUpDownNotifier->IsActive() )
                {
                // Client is starting notifications. Filter old status events.
                iConnInfos[aIndex].iProgressNotifier->Receive( connectionStatus );
                }
            else
                {
                // Event is starting notifification. No filtering is needed.
                iConnInfos[aIndex].iProgressNotifier->Receive();
                }
            }

        // -------------------------
        // Amount of Downlink data
        // -------------------------
        if ( iConnInfos[aIndex].iDLDataNotifier == 0 )
            {
            TInt subConnectionId( 0 );

            // Create an active object and add it to scheduler
            iConnInfos[aIndex].iDLDataNotifier = new( ELeave ) CDataNotifier(
                    iServer,
                    iConnInfos[aIndex].iConnAttach,
                    iConnInfos[aIndex].iConnectionId,
                    subConnectionId,
                    CDataNotifier::EDownlink);

            iConnInfos[aIndex].iDLDataNotifier->Construct();

            if ( ( connectionStatus == KLinkLayerOpen ) ||
                 ( connectionStatus == KPsdSuspended ) )
                {
                iConnInfos[aIndex].iDLDataNotifier->Receive();
                }
            }

        // -------------------------
        // Amount of Uplink data
        // -------------------------
        if ( iConnInfos[aIndex].iULDataNotifier == 0 )
            {
            TInt subConnectionId( 0 );

            // Create an active object and add it to scheduler
            iConnInfos[aIndex].iULDataNotifier = new( ELeave ) CDataNotifier(
                    iServer,
                    iConnInfos[aIndex].iConnAttach,
                    iConnInfos[aIndex].iConnectionId,
                    subConnectionId,
                    CDataNotifier::EUplink);

            iConnInfos[aIndex].iULDataNotifier->Construct();

            if ( ( connectionStatus == KLinkLayerOpen ) ||
                 ( connectionStatus == KPsdSuspended ) )
                {
                iConnInfos[aIndex].iULDataNotifier->Receive();
                }
            }

        // ---------------------------------------
        // Connection down event with data volumes
        // ---------------------------------------
        if ( iConnInfos[aIndex].iConnDownNotifier == 0 )
            {
            TInt subConnectionId( 0 );

            // Create an active object and add it to scheduler
            iConnInfos[aIndex].iConnDownNotifier = new( ELeave ) CSubConnUpDownNotifier(
                    iServer,
                    iConnInfos[aIndex].iConnAttach,
                    iConnInfos[aIndex].iConnectionId,
                    subConnectionId );

            iConnInfos[aIndex].iConnDownNotifier->Construct();

            // Receiving will start only when connection status reaches KLinkLayerOpen
            if ( ( connectionStatus == KLinkLayerOpen ) ||
                 ( connectionStatus == KPsdSuspended ) )
                {
                iConnInfos[aIndex].iConnDownNotifier->Receive();
                }
            }

        // ----------------------
        // Connection Activity
        // ----------------------
        if ( iConnInfos[aIndex].iActivityNotifier == 0 )
            {
            // To update internal table fast at the first time
            if ( ( connectionStatus == KLinkLayerOpen ) ||
                 ( connectionStatus == KPsdSuspended ) )
                {
                GetActivityOneShotL( aIndex );
                }
            }
        else
            {
            if ( !iConnInfos[aIndex].iActivityNotifier->IsActive() )
                {
                iConnInfos[aIndex].iActivityNotifier->Receive( iConnInfos[aIndex].iActivity );
                }
            }

        // ----------------------
        // Connection Bearer
        // ----------------------
        if ( iConnInfos[aIndex].iBearerNotifier == 0 )
            {
            // Create an active object and add it to scheduler
            iConnInfos[aIndex].iBearerNotifier = CConnMonBearerNotifier::NewL(
                    iServer,
                    iMobilePhone,
                    iConnInfos[aIndex].iConnectionId );

            // Receiving will start only when connection status reaches KLinkLayerOpen
            if ( ( connectionStatus == KLinkLayerOpen ) ||
                 ( connectionStatus == KPsdSuspended ) )
                {
                iConnInfos[aIndex].iBearerNotifier->Listen();
                }
            }

        // Note. iDataVolumeAO is created when client asks data volume info
        }
    LOGEXITFN("CConnMonIAP::AddConnNotificationsL()")
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::DeleteConnNotifications
// Deletes event watchers owned by a connection
// -----------------------------------------------------------------------------------
//
void CConnMonIAP::DeleteConnNotifications( const TInt& aIndex )
    {
    LOGENTRFN("CConnMonIAP::DeleteConnNotifications()")
    if ( iConnInfos[ aIndex ].iBearer < EBearerExternalCSD )
        {
        if ( iConnInfos[ aIndex ].iProgressNotifier )
            {
            iConnInfos[ aIndex ].iProgressNotifier->Cancel();
            delete iConnInfos[ aIndex ].iProgressNotifier;
            iConnInfos[ aIndex ].iProgressNotifier = NULL;
            }

        if ( iConnInfos[ aIndex ].iDLDataNotifier )
            {
            iConnInfos[ aIndex ].iDLDataNotifier->Cancel();
            delete iConnInfos[ aIndex ].iDLDataNotifier;
            iConnInfos[ aIndex ].iDLDataNotifier = NULL;
            }

        if ( iConnInfos[ aIndex ].iULDataNotifier )
            {
            iConnInfos[ aIndex ].iULDataNotifier->Cancel();
            delete iConnInfos[ aIndex ].iULDataNotifier;
            iConnInfos[ aIndex ].iULDataNotifier = NULL;
            }

        if ( iConnInfos[ aIndex ].iDataVolumeAO )
            {
            iConnInfos[ aIndex ].iDataVolumeAO->Cancel();
            delete iConnInfos[ aIndex ].iDataVolumeAO;
            iConnInfos[ aIndex ].iDataVolumeAO = NULL;
            }

        if ( iConnInfos[ aIndex ].iConnDownNotifier )
            {
            iConnInfos[ aIndex ].iConnDownNotifier->Cancel();
            delete iConnInfos[ aIndex ].iConnDownNotifier;
            iConnInfos[ aIndex ].iConnDownNotifier = NULL;
            }

        if ( iConnInfos[ aIndex ].iActivityNotifier )
            {
            iConnInfos[ aIndex ].iActivityNotifier->Cancel();
            delete iConnInfos[ aIndex ].iActivityNotifier;
            iConnInfos[ aIndex ].iActivityNotifier = NULL;
            }

        if ( iConnInfos[ aIndex ].iBearerNotifier )
            {
            iConnInfos[ aIndex ].iBearerNotifier->CancelListen();
            delete iConnInfos[ aIndex ].iBearerNotifier;
            iConnInfos[ aIndex ].iBearerNotifier = NULL;
            }
        }
    LOGEXITFN("CConnMonIAP::DeleteConnNotifications()")
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::DeleteNotifications
// Deletes all the event watchers from the system (expect connection up/down events)
// -----------------------------------------------------------------------------------
//
void CConnMonIAP::DeleteNotifications()
    {
    if( iTelephonyNotifier )
        {
        delete iTelephonyNotifier;
        iTelephonyNotifier = NULL;
        }

    if( iDualTransferModeNotifier )
        {
        delete iDualTransferModeNotifier;
        iDualTransferModeNotifier = NULL;
        }

    if ( iPsdNetwStatusNotifier )
        {
        // Cancel any outstanding requests
        iPsdNetwStatusNotifier->Cancel();
        delete iPsdNetwStatusNotifier;
        iPsdNetwStatusNotifier = NULL;
        }

    if ( iNetwRegistrationNotifier )
        {
        // Cancel any outstanding requests
        iNetwRegistrationNotifier->Cancel();
        delete iNetwRegistrationNotifier;
        iNetwRegistrationNotifier = NULL;
        }

    if ( iEdgeNotifier )
        {
        // Cancel any outstanding requests
        iEdgeNotifier->Cancel();
        delete iEdgeNotifier;
        iEdgeNotifier = NULL;
        }

    if ( iWcdmaNotifier )
        {
        iWcdmaNotifier->Cancel();
        delete iWcdmaNotifier;
        iWcdmaNotifier = NULL;
        }

    if ( iModeNotifier )
        {
        // Cancel any outstanding requests
        iModeNotifier->Cancel();
        delete iModeNotifier;
        iModeNotifier = NULL;
        }

    if ( iGSMSignalNotifier )
        {
        // Cancel any outstanding requests
        iGSMSignalNotifier->Cancel();
        delete iGSMSignalNotifier;
        iGSMSignalNotifier = NULL;
        }

    if ( iGSMBearerAvailabilityNotifier )
        {
        // Cancel any outstanding requests
        iGSMBearerAvailabilityNotifier->Cancel();
        delete iGSMBearerAvailabilityNotifier;
        iGSMBearerAvailabilityNotifier = NULL;
        }

    if ( iWlanSupport )
        {
        iWlanSupport->DisableEventsToClients();
        }

    // Delete notifications owned by the connections
    TInt count = iConnInfos.Count();
    for ( TInt i = 0; i < count; i++ )
        {
        DeleteConnNotifications( i );
        }
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::NewConnectionId
// Returns a new unique connection id for the connection.
// -----------------------------------------------------------------------------------
//
TUint CConnMonIAP::NewConnectionId()
    {
    ++iIdCounter;

    if ( iIdCounter == KMaxConnectionId )
        {
        iIdCounter = 1;
        }

    return iIdCounter;
    }

// -----------------------------------------------------------------------------------
// CConnMonIAP::Index
// Finds the index of the matching object within the array.
// KErrNotFound, if no matching object can be found.
// -----------------------------------------------------------------------------------
//
TInt CConnMonIAP::Index( const TUint& aConnectionId )
    {
    TInt count = iConnInfos.Count();
    for ( TInt i = 0; i < count; i++ )
        {
        if ( iConnInfos[i].iConnectionId == aConnectionId )
            {
            return i;
            }
        }

    return KErrNotFound;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetAccessPointName
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetAccessPointName( const TUint& aConnectionId, TDes& aName )
    {
    LOGENTRFN("CConnMonIAP::GetAccessPointName()")
    TInt err( KErrNone );

    // Find connection matching the given Id
    TInt index = Index( aConnectionId );
    if ( index < 0  )
        {
        err = KErrNotFound;
        }
    else
        {
        // Find out access point name
        TBuf<KCommsDbSvrMaxFieldLength> settingName;
        TBuf<KCommsDbSvrMaxFieldLength> settingValue;
        settingName.Copy( TPtrC( IAP ) );
        settingName.Append( TChar( '\\' ) );
        settingName.Append( TPtrC( IAP_SERVICE_TYPE ) );

        err = iConnInfos[index].iConnAttach->GetDesSetting(
                TPtrC( settingName ),
                settingValue );
        if ( KErrNone == err )
            {
            if ( settingValue == TPtrC( OUTGOING_WCDMA ) ||
                    settingValue == TPtrC( INCOMING_WCDMA ) )
                {
                settingName.Copy( settingValue );
                settingName.Append( TChar( '\\' ) );
                settingName.Append( TPtrC( GPRS_APN ) );

                err = iConnInfos[index].iConnAttach->GetDesSetting(
                        TPtrC( settingName ),
                        aName );
                }
            else
                {
                err = KErrNotFound;
                }
            }
        }

    LOGEXITFN1("CConnMonIAP::GetAccessPointName()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetTelNumber
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetTelNumber( const TUint& aConnectionId, TDes& aTelNum )
    {
    LOGENTRFN("CConnMonIAP::GetTelNumber()")
    TInt err( KErrNone );

    // Find connection matching the given Id
    TInt index = Index( aConnectionId );
    if ( index < 0  )
        {
        err = KErrNotFound;
        }
    else
        {
        // Find out tel. number
        TBuf<KCommsDbSvrMaxFieldLength> settingName;
        TBuf<KCommsDbSvrMaxFieldLength> settingValue;
        settingName.Copy( TPtrC( IAP ) );
        settingName.Append( TChar( '\\' ) );
        settingName.Append( TPtrC( IAP_SERVICE_TYPE ) );

        err = iConnInfos[index].iConnAttach->GetDesSetting(
                TPtrC( settingName ),
                settingValue );
        if ( KErrNone == err )
            {
            if ( settingValue == TPtrC( DIAL_OUT_ISP ) ||
                    settingValue == TPtrC( DIAL_IN_ISP ) )
                {
                settingName.Copy( settingValue );
                settingName.Append( TChar( '\\' ) );
                settingName.Append( TPtrC( ISP_DEFAULT_TEL_NUM ) );

                err = iConnInfos[index].iConnAttach->GetDesSetting(
                        TPtrC( settingName ),
                        aTelNum );
                }
            else
                {
                err = KErrNotFound;
                }
            }
        }

    LOGEXITFN1("CConnMonIAP::GetTelNumber()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetConnectionStatus
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetConnectionStatus( const TInt& aIndex, TInt& aConnectionStatus )
    {
    //LOGENTRFN("CConnMonIAP::GetConnectionStatus()")
    TInt err( KErrNone );
    TNifProgress nifProgress;

    if ( ( aIndex < 0 ) || ( aIndex >= iConnInfos.Count() ) )
        {
        LOGIT1("GetConnectionStatus: invalid index value: %d", aIndex)
        err = KErrArgument;
        }
    else
        {
        aConnectionStatus = 0;
        err = iConnInfos[aIndex].iConnAttach->Progress( nifProgress );
        if ( KErrNone == err )
            {
            aConnectionStatus = nifProgress.iStage;
            LOGIT1("GetConnectionStatus: iConnAttach->Progress() status: %d", aConnectionStatus)
            }
        else
            {
            LOGIT1("GetConnectionStatus: ERROR getting progress status <%d>", err)
            }
        }

    //LOGEXITFN1("CConnMonIAP::GetConnectionStatus()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetPsdNetworkStatus
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetPsdNetworkStatus( TInt& aNetworkStatus ) const
    {
    LOGENTRFN("CConnMonIAP::GetPsdNetworkStatus()")
    TInt err( KErrNone );

    if ( iTSYLoaded && iPacketServLoaded )
        {
        RPacketService::TStatus packetStatus;
        err = iPacketService.GetStatus( packetStatus );
        if ( KErrNone == err )
            {
            aNetworkStatus = CalculateNetworkStatus( packetStatus );
            LOGIT1("GetPsdNetworkStatus: status %d", aNetworkStatus)
            }
        }
    else
        {
        aNetworkStatus = EConnMonStatusUnattached;
        }

    LOGEXITFN1("CConnMonIAP::GetPsdNetworkStatus()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetNetworkRegistrationMode
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetNetworkRegistrationMode( TInt& aRegistration ) const
    {
    return GetNetworkRegistration( aRegistration );
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetNetworkRegistration
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetNetworkRegistration( TInt& aRegistration ) const
    {
    LOGENTRFN("CConnMonIAP::GetNetworkRegistration()")
    TInt err( KErrNone );

    if ( !FeatureManager::FeatureSupported( KFeatureIdNetworkRegistration ) )
        {
        LOGIT("GetNetworkRegistration: KFeatureIdNetworkRegistration not supported")
        err = KErrNotSupported;
        }
    else
        {
        if ( iTSYLoaded )
            {
            TRequestStatus status( KErrNone );
            RMobilePhone::TMobilePhoneRegistrationStatus registration(
                    RMobilePhone::ERegistrationUnknown );

            iMobilePhone.GetNetworkRegistrationStatus( status, registration );
            User::WaitForRequest( status );
            err = status.Int();
            if ( KErrNone == err )
                {
                aRegistration = CalculateNetworkRegistration( registration );
                LOGIT1("GetNetworkRegistration: registration %d", aRegistration)
                }
            }
        else
            {
            aRegistration = ENetworkRegistrationNotAvailable;
            }
        }

    LOGEXITFN1("CConnMonIAP::GetNetworkRegistration()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetNetworkRegistration_v2
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetNetworkRegistration_v2( TInt& aRegistration ) const
    {
    LOGENTRFN("CConnMonIAP::GetNetworkRegistration_v2()")
    TInt err( KErrNone );

    if ( !FeatureManager::FeatureSupported( KFeatureIdNetworkRegistration ) )
        {
        LOGIT("GetNetworkRegistration_v2: KFeatureIdNetworkRegistration not supported")
        err = KErrNotSupported;
        }
    else
        {
        if ( iTSYLoaded )
            {
            TRequestStatus status( KErrNone );
            RMobilePhone::TMobilePhoneRegistrationStatus registration(
                    RMobilePhone::ERegistrationUnknown );

            iMobilePhone.GetNetworkRegistrationStatus( status, registration );
            User::WaitForRequest( status );
            err = status.Int();
            if ( KErrNone == err )
                {
                aRegistration = CalculateNetworkRegistration_v2( registration );
                LOGIT1("GetNetworkRegistration_v2: registration <%d>", aRegistration )
                }
            }
        else
            {
            aRegistration = ENetworkRegistrationExtNotAvailable;
            }
        }

    LOGEXITFN1("CConnMonIAP::GetNetworkRegistration_v2()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetGSMSignalStrength
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetGSMSignalStrength( TInt& aSignalStrength ) const
    {
    LOGENTRFN("CConnMonIAP::GetGSMSignalStrength()")
    TInt err( KErrNone );

    if ( iTSYLoaded )
        {
        TRequestStatus status( KErrNone );
        TInt32 strength( 0 );
        TInt8 bar( -1 );

        iMobilePhone.GetSignalStrength( status, strength, bar );
        User::WaitForRequest( status );

        err = status.Int();
        if ( KErrNone == err )
            {
            aSignalStrength = strength;
            LOGIT1("GetGSMSignalStrength: strength %d", aSignalStrength)
            }
        }
    else
        {
        err = KErrNotSupported;
        }

    LOGEXITFN1("CConnMonIAP::GetGSMSignalStrength()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetProtocolTypeL
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetProtocolTypeL( const TUint& aConnectionId, TInt& aProtocolType )
    {
    LOGENTRFN("CConnMonIAP::GetProtocolTypeL()")
    TInt err( KErrNone );

    // Find connection matching the given Id
    TInt index = Index( aConnectionId );
    if ( index < 0  )
        {
        LOGEXITFN1("CConnMonIAP::GetProtocolTypeL()", KErrNotFound)
        return KErrNotFound;
        }

    aProtocolType = EProtocolTypeUnknown;

    if ( iTSYLoaded && iPacketServLoaded )
        {
        // Get AP name for the connection
        TBuf<KCommsDbSvrMaxFieldLength> apName;

        err = GetAccessPointName( iConnInfos[index].iConnectionId, apName );

        if ( KErrNotFound == err )
            {
            LOGEXITFN1("CConnMonIAP::GetProtocolTypeL()", err)
            return err;
            }

        // Enumerate all PDP contexts
        TRequestStatus status( KErrNone );
        TInt contextCount( 0 );
        TInt maxContextCount( 0 );

        iPacketService.EnumerateContexts( status, contextCount, maxContextCount );
        User::WaitForRequest( status );

        err = status.Int();
        if ( err != KErrNone )
            {
            LOGEXITFN1("CConnMonIAP::GetProtocolTypeL()", err)
            return err;
            }

        RPacketService::TContextInfo contextInfo;
        RPacketContext context;
        CleanupClosePushL( context );

        // Find PDP contexts matching the given connectionId
        for ( TInt i = 0; ( i < contextCount ) && ( aProtocolType != EProtocolTypeIP ); i++ )
            {
            iPacketService.GetContextInfo( status, i, contextInfo ); //iName, iStatus
            User::WaitForRequest( status );

            err = status.Int();
            if ( err != KErrNone )
                {
                LOGEXITFN1("CConnMonIAP::GetProtocolTypeL()", err)
                return err;
                }

            err = context.OpenExistingContext( iPacketService, contextInfo.iName );
            if ( err != KErrNone )
                {
                LOGEXITFN1("CConnMonIAP::GetProtocolTypeL()", err)
                return err;
                }

            RPacketContext::TContextConfigGPRS* getParams;
            getParams = new( ELeave ) RPacketContext::TContextConfigGPRS();
            TPckg<RPacketContext::TContextConfigGPRS> getContextConfigPckg( *getParams );

            context.GetConfig( status, getContextConfigPckg );
            User::WaitForRequest( status );

            err = status.Int();
            if ( KErrNone == err )
                {
                TInt ret = CompareAccessPointNames( apName, getParams->iAccessPointName );

                if ( ret == 0 )
                    {
                    // PDP context matching the IAP connection found
                    if ( getParams->iPdpType == RPacketContext::EPdpTypeIPv4 )
                        {
                        if ( aProtocolType == EProtocolTypeIPv6 )
                            {
                            aProtocolType = EProtocolTypeIP;    // Both 4 & 6
                            }
                        else
                            {
                            aProtocolType = EProtocolTypeIPv4;
                            }
                        }
                    else if ( getParams->iPdpType == RPacketContext::EPdpTypeIPv6 )
                        {
                        if ( aProtocolType == EProtocolTypeIPv4 )
                            {
                            aProtocolType = EProtocolTypeIP;    // Both 4 & 6
                            }
                        else
                            {
                            aProtocolType = EProtocolTypeIPv6;
                            }
                        }
                    else
                        {
                        aProtocolType = EProtocolTypeUnknown;
                        }
                    }
                }

            delete getParams;
            context.Close();

            if ( err != KErrNone )
                {
                break;
                }
            } // for
        CleanupStack::PopAndDestroy( &context );
        } // if

    LOGEXITFN1("CConnMonIAP::GetProtocolTypeL()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetActivityOneShotL
// -----------------------------------------------------------------------------
//
void CConnMonIAP::GetActivityOneShotL( const TInt& aIndex )
    {
    if ( iConnInfos[aIndex].iActivityNotifier == 0 )
        {
        iConnInfos[aIndex].iActivityNotifier = new( ELeave ) CActivityNotifier(
                iServer,
                iConnInfos[aIndex].iConnAttach,
                iConnInfos[aIndex].iConnectionId,
                0 );
        iConnInfos[aIndex].iActivityNotifier->Construct();
        }

    if ( !iConnInfos[aIndex].iActivityNotifier->IsActive() )
        {
        iConnInfos[aIndex].iActivityNotifier->ReceiveOne(
                iConnInfos[aIndex].iActivity );

        // This AO will cancel the activity notifier after one second in case it has not completed.
        // AO will destroy itself in RunL.
        CTimerAO* timerAO = new( ELeave ) CTimerAO(
                iServer,
                iConnInfos[aIndex].iConnectionId,
                iConnInfos[aIndex].iActivity );

        CleanupStack::PushL( timerAO );
        timerAO->ConstructL();
        CleanupStack::Pop( timerAO );

        timerAO->Start();
        }
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::GetBearerFromETel
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::GetBearerFromETel(
        const TDes& aNumber,
        TInt& aBearer,
        TBearerInfo& aBearerInfo )
    {
    TInt ret( KErrNone );
    TInt countCalls( 0 );
    RLine line;
    RMobileCall call;

    // Get phone info
    RTelServer::TPhoneInfo phoneInfo;
    ret = iTelServer.GetPhoneInfo( 0, phoneInfo );
    if ( KErrNone != ret )
        {
        return ret;
        }

    ret = line.Open( iMobilePhone, KMmTsyDataLineName );
    if ( KErrNone != ret )
        {
        return ret;
        }

    // Enumerate calls on data line
    ret = line.EnumerateCall( countCalls );
    if ( KErrNone != ret )
        {
        line.Close();
        return ret;
        }

    // Get call info
    for ( TInt j = 0; j < countCalls; j++ )
        {
        RLine::TCallInfo callInfo;

        ret = line.GetCallInfo( j, callInfo );
        if ( KErrNone != ret )
            {
            line.Close();
            return ret;
            }

        if ( callInfo.iStatus != RCall::EStatusIdle )
            {
            TName callName;

            callName.Copy( phoneInfo.iName );
            callName.Append( KDoubleColon );
            callName.Append( KMmTsyDataLineName );
            callName.Append( KDoubleColon );
            callName.Append( callInfo.iCallName );

            ret = call.OpenExistingCall( iTelServer, callName );
            if ( KErrNone != ret )
                {
                line.Close();
                return ret;
                }

            RMobileCall::TMobileCallInfoV1 info;
            RMobileCall::TMobileCallInfoV1Pckg infoPckg( info );

            ret = call.GetMobileCallInfo( infoPckg );
            if ( KErrNone == ret )
                {
                if ( infoPckg().iRemoteParty.iRemoteNumber.iTelNumber.Length() > 0 )
                    {
                    ret = aNumber.Compare( infoPckg().iRemoteParty.iRemoteNumber.iTelNumber );
                    }
                else if ( infoPckg().iDialledParty.iTelNumber.Length() > 0 )
                    {
                    ret = aNumber.Compare( infoPckg().iDialledParty.iTelNumber );
                    }
                else
                    {
                    ret = KErrNotFound;
                    }

                if ( ret == 0 )
                    {
                    aBearer = EBearerCSD;
                    aBearerInfo.iBearer = EBearerInfoCSD;
                    aBearerInfo.iInternal = ETrue;

                    RMobileCall::TMobileCallHscsdInfoV1 hscsdInfo;
                    RMobileCall::TMobileCallHscsdInfoV1Pckg hscsdInfoPckg( hscsdInfo );

                    ret = call.GetCurrentHscsdInfo( hscsdInfoPckg );
                    if ( KErrNone == ret )
                        {
                        if ( hscsdInfo.iAiur != RMobileCall::EAiurBpsUnspecified )
                            {
                            aBearer = EBearerHSCSD;
                            aBearerInfo.iBearer = EBearerInfoHSCSD;
                            }
                        }
                    call.Close();
                    line.Close();
                    return KErrNone;
                    }
                }
            call.Close();
            }
        } // for
    line.Close();
    return KErrNotFound;
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::CompareAccessPointNames
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::CompareAccessPointNames(
        const TDesC& aNameFromCommDB,
        const TDesC& aNameFromETel ) const
    {
    return ( aNameFromETel.Compare( aNameFromCommDB ) );
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::CompareAccessPointNames
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::CompareAccessPointNames(
        const TDesC& aNameFromCommDB,
        const TDesC8& aNameFromETel ) const
    {
    TBuf<KCommsDbSvrMaxFieldLength> tempBuffer;

    CnvUtfConverter::ConvertToUnicodeFromUtf8( tempBuffer, aNameFromETel );

    return( tempBuffer.Compare( aNameFromCommDB ) );
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::SendConnectionEvents
// -----------------------------------------------------------------------------
//
void CConnMonIAP::SendConnectionEvents( TConnMonBearerInfo& /*aBearerinfo*/ )
    {
    if ( iConnInfos.Count() > 0 )
        {
        for ( TInt i = 0; i < iConnInfos.Count(); i++ )
            {
            if ( iConnInfos[i].iBearerNotifier )
                {
                iConnInfos[i].iBearerNotifier->SendBearerInfoEvent();
                iConnInfos[i].iBearerNotifier->SendBearerGroupEvent();
                }
            }
        }
    }

// -----------------------------------------------------------------------------
// CConnMonIAP::LastProgressError
// -----------------------------------------------------------------------------
//
TInt CConnMonIAP::LastProgressError(
        const TUint& aConnectionId,
        TNifProgress& aProgress )
    {
    TInt err( KErrNone );

    // Find connection matching the given Id
    TInt index = Index( aConnectionId );

    if ( index < 0  )
        {
        return KErrNotFound;
        }

    err = iConnInfos[index].iConnAttach->LastProgressError( aProgress );

    LOGIT3("iConnection->Progress() ret <%d> stage %d error <%d>", err, aProgress.iStage, aProgress.iError)
    return err;
    }

// ---------------------------------------------------------------------------
// CConnMonIAP::WlanRssGoodEnough
// ---------------------------------------------------------------------------
//
TBool CConnMonIAP::WlanRssGoodEnough()
    {
    //LOGENTRFN("CConnMonIAP::WlanRssGoodEnough()")
    TBool value( EFalse );

    if ( !iWlanSupport )
        {
        LOGIT("WlanRssGoodEnough: No WLAN support")
        value = EFalse;
        }
    else
        {
        value = iWlanSupport->WlanRssGoodEnough();
        }

    //LOGEXITFN1("CConnMonIAP::WlanRssGoodEnough()", value)
    return value;
    }

// ---------------------------------------------------------------------------
// CConnMonIAP::DiscoverBearerId
// ---------------------------------------------------------------------------
//
TInt CConnMonIAP::BearerIdForBearerAvailability(
        const TUint& aConnId,
        TUint& aBearerId )
    {
    LOGENTRFN("CConnMonIAP::BearerIdForBearerAvailability()")
    TInt err( KErrNone );

    TInt index = Index( aConnId );
    if ( index < 0 )
        {
        // Bearer specific connection id given as attribute
        switch ( aConnId )
            {
            case EBearerIdWLAN:     aBearerId = EBearerIdWLAN;      break;
            case EBearerIdGPRS:     aBearerId = EBearerIdGPRS;      break;
            case EBearerIdWCDMA:    aBearerId = EBearerIdWCDMA;     break;
            case EBearerIdCSD:      aBearerId = EBearerIdCSD;       break;
            case EBearerIdWcdmaCSD: aBearerId = EBearerIdWcdmaCSD;  break;
            // Let session send this request to the plugin
            case EBearerIdLAN:      err = KErrCancel;               break;
            default:                err = KErrNotFound;             break;
            }
        }
    else
        {
        // Valid connection id given as attribute
        switch ( iConnInfos[index].iBearer )
            {
            case EBearerWLAN:               aBearerId = EBearerIdWLAN;      break;
            case EBearerGPRS:
            case EBearerEdgeGPRS:
            case EBearerExternalGPRS:
            case EBearerExternalEdgeGPRS:   aBearerId = EBearerIdGPRS;      break;
            case EBearerWCDMA:
            case EBearerExternalWCDMA:      aBearerId = EBearerIdWCDMA;     break;
            case EBearerCSD:
            case EBearerHSCSD:
            case EBearerExternalCSD:
            case EBearerExternalHSCSD:      aBearerId = EBearerIdCSD;       break;
            case EBearerWcdmaCSD:
            case EBearerExternalWcdmaCSD:   aBearerId = EBearerIdWcdmaCSD;  break;
            // Let session send this request to the plugin
            case EBearerLAN:                err = KErrCancel;               break;
            default:                        err = KErrNotSupported;         break;
            }
        }

    LOGEXITFN1("CConnMonIAP::BearerIdForBearerAvailability()", err)
    return err;
    }

// End-of-file