/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: CCCHCommDbWatcher implementation
*
*/
// INCLUDE FILES
#include <cmdestination.h>
#include <cmconnectionmethoddef.h>
#include <cmpluginwlandef.h>
#include <cmpluginvpndef.h>
#include <centralrepository.h>
#include <commsdat.h>
#include "cchcommdbwatcher.h"
#include "cchcommdbwatcherobserver.h"
#include "cchlogger.h"
#include "d32dbms.h"
// EXTERNAL DATA STRUCTURES
// None
// EXTERNAL FUNCTION PROTOTYPES
// None
// CONSTANTS
// None
// MACROS
// None
// LOCAL CONSTANTS AND MACROS
const TInt KDefaultGranularity = 5;
const TInt KMaxCheckAttempts = 3;
// Repository for CommsDat
const TUid KCDCommsRepositoryId = { 0xCCCCCC00 };
// MODULE DATA STRUCTURES
// None
// LOCAL FUNCTION PROTOTYPES
// None
// FORWARD DECLARATIONS
// None
// ============================= LOCAL FUNCTIONS =============================
// ============================ MEMBER FUNCTIONS =============================
// ---------------------------------------------------------------------------
// CCCHCommDbWatcher::CCCHCommDbWatcher
// C++ default constructor can NOT contain any code, that might leave.
// ---------------------------------------------------------------------------
//
CCCHCommDbWatcher::CCCHCommDbWatcher( MCCHCommDbWatcherObserver& aObserver ) :
CActive( CActive::EPriorityStandard ),
iObserver( aObserver ),
iTableId( KCDTIdIAPRecord )
{
CActiveScheduler::Add( this );
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::ConstructL
// Symbian 2nd phase constructor can leave.
// ---------------------------------------------------------------------------
//
void CCCHCommDbWatcher::ConstructL()
{
CCHLOGSTRING( "CCCHCommDbWatcher::ConstructL IN" );
iRepository = CRepository::NewL( KCDCommsRepositoryId );
iDestinations = RArray<TDestinationData>( KDefaultGranularity );
InitializeDestination();
TInt err( RequestNotifications() );
User::LeaveIfError( err );
CCHLOGSTRING( "CCCHCommDbWatcher::ConstructL OUT" );
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::NewL
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CCCHCommDbWatcher* CCCHCommDbWatcher::NewL(
MCCHCommDbWatcherObserver& aObserver )
{
CCCHCommDbWatcher* self = CCCHCommDbWatcher::NewLC( aObserver );
CleanupStack::Pop( self );
return self;
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::NewLC
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CCCHCommDbWatcher* CCCHCommDbWatcher::NewLC(
MCCHCommDbWatcherObserver& aObserver )
{
CCCHCommDbWatcher* self = new (ELeave) CCCHCommDbWatcher( aObserver );
CleanupStack::PushL( self );
self->ConstructL();
return self;
}
// Destructor
CCCHCommDbWatcher::~CCCHCommDbWatcher()
{
CCHLOGSTRING( "CCCHCommDbWatcher::~CCCHCommDbWatcher" );
iDestinations.Close();
// Cancel outstanding request, if exists
Cancel();
delete iRepository;
if ( iCmmOpen )
{
iCmm.Close();
}
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::RequestNotifications()
//
// ---------------------------------------------------------------------------
//
TInt CCCHCommDbWatcher::RequestNotifications()
{
CCHLOGSTRING( "CCCHCommDbWatcher::RequestNotifications()" );
CCHLOGSTRING2( "Calling iRepository->NotifyRequest() for table 0x%08X", iTableId );
TInt err = iRepository->NotifyRequest( iTableId, KCDMaskShowRecordType, iStatus );
if ( KErrNone == err )
{
SetActive();
}
else
{
CCHLOGSTRING2( "ERROR, iRepository->NotifyRequest() <%d>", err );
}
return err;
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::CmManagerL
//
// ---------------------------------------------------------------------------
//
RCmManager& CCCHCommDbWatcher::CmManagerL()
{
// Remove this method and open cmmanager connection in ConstructL
// after cmmanager is refactored -> to become a server, schedule is unknown
if ( !iCmmOpen )
{
CCHLOGSTRING( "CCCHCommDbWatcher::CmManagerL open connection" );
iCmm.OpenL();
iCmmOpen = ETrue;
}
return iCmm;
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::GetWLANIapCountFromSnap
//
// ---------------------------------------------------------------------------
//
TInt CCCHCommDbWatcher::GetIapCountFromSnap(
TInt aSNAPId,
TBool aWLANIapsOnly,
TBool aUpdateDestinations )
{
CCHLOGSTRING( "CCCHCommDbWatcher::GetIapCountFromSnap - Forced CheckIapsL" );
// Remove this error check after cmmanager is refactored -> to become
// a server, schedule is unknown
// Force destination update if we are pending unlock event
if ( iLastError || iUseForce || aUpdateDestinations )
{
CCHLOGSTRING( "CCCHCommDbWatcher::GetIapCountFromSnap - Forced DESTINATION UPDATE" );
InitializeDestination();
iUseForce = EFalse;
}
TInt iaps( KErrNotFound );
for ( TInt i = 0; iaps == KErrNotFound && i < iDestinations.Count(); i++ )
{
if ( iDestinations[ i ].iDestId == aSNAPId )
{
iaps = 0; //if destination is not found, KErrNotFound is returned
if ( aWLANIapsOnly )
{
iaps = iDestinations[ i ].iWlanIaps;
}
else
{
iaps = iDestinations[ i ].iIapCount;
}
}
}
return iaps;
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::IsVpnApL
//
// ---------------------------------------------------------------------------
//
TBool CCCHCommDbWatcher::IsVpnApL(
TInt aIapId )
{
CCHLOGSTRING( "CCCHCommDbWatcher::IsVpnApL: IN" );
TBool response( KPluginVPNBearerTypeUid == GetBearerL( aIapId ) );
CCHLOGSTRING3( "CCCHCommDbWatcher::IsVpnApL: iap id: %d is vpn ap: %d",
aIapId, response );
return response;
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::IsWLANAPL
//
// ---------------------------------------------------------------------------
//
TBool CCCHCommDbWatcher::IsWlanApL(
TInt aIapId )
{
CCHLOGSTRING( "CCCHCommDbWatcher::IsWLANAPL: IN" );
TBool response( KUidWlanBearerType == GetBearerL( aIapId ) );
CCHLOGSTRING3( "CCCHCommDbWatcher::IsWLANAPL: iap id: %d is wlan ap: %d",
aIapId, response );
return response;
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::GetBearerL
//
// ---------------------------------------------------------------------------
//
TUint32 CCCHCommDbWatcher::GetBearerL(
TInt aIapId )
{
return CmManagerL().ConnectionMethodL( aIapId ).GetIntAttributeL(
CMManager::ECmBearerType );
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::RunL
//
// ---------------------------------------------------------------------------
//
void CCCHCommDbWatcher::RunL()
{
if ( iStatus.Int() < KErrNone )
{
CCHLOGSTRING2( "CCCHCommDbWatcher::RunL: error <%d>", iStatus.Int() );
iErrorCounter++;
if ( iErrorCounter > KCchConnCenRepErrorThreshold )
{
CCHLOGSTRING2( "Over %d consecutive errors, stopping notifications permanently",
KCchConnCenRepErrorThreshold );
return;
}
}
else
{
iErrorCounter = 0;
UpdateIapTable();
}
CCHLOGSTRING2( "CCCHCommDbWatcher::RunL: CenRep event 0x%08X", iStatus.Int() );
TInt err( RequestNotifications() );
User::LeaveIfError( err );
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::DoCancel
//
// ---------------------------------------------------------------------------
//
void CCCHCommDbWatcher::DoCancel()
{
iRepository->NotifyCancel( iTableId, KCDMaskShowRecordType );
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::RunError
//
// ---------------------------------------------------------------------------
//
TInt CCCHCommDbWatcher::RunError( TInt /*aError*/ )
{
TInt err( RequestNotifications() );
return KErrNone;
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::CheckIapsL
//
// ---------------------------------------------------------------------------
//
void CCCHCommDbWatcher::CheckIapsL( TBool& aChanged, TInt& aSNAPId )
{
CCHLOGSTRING2( "CCCHCommDbWatcher::CheckIapsL: IN Current iap count %d",
CountIapsFromArray( iDestinations ) );
RArray<TUint32> destIdArray = RArray<TUint32>( KDefaultGranularity );
CleanupClosePushL( destIdArray ); // CS:1
RArray<TDestinationData> currentDestinations = RArray<TDestinationData>(
KDefaultGranularity );
CleanupClosePushL( currentDestinations ); // CS:2
//Get count of iaps that do not belong to any destination
RArray<TUint32> cmMethods = RArray<TUint32>( KDefaultGranularity );
CleanupClosePushL( cmMethods ); // CS:3
CmManagerL().ConnectionMethodL( cmMethods );
TDestinationData destinationlessIaps( KErrNotFound, cmMethods.Count() );
CCHLOGSTRING2( "CCCHCommDbWatcher::CheckIapsL: cmMethods count %d",
cmMethods.Count() );
for ( TInt i = 0; i < cmMethods.Count(); i++ )
{
RCmConnectionMethod cm = CmManagerL().ConnectionMethodL( cmMethods[ i ] );
CleanupClosePushL( cm ); // CS:4
if( KUidWlanBearerType ==
cm.GetIntAttributeL( CMManager::ECmBearerType ) )
{
destinationlessIaps.iWlanIaps++;
}
CleanupStack::PopAndDestroy( &cm ); // CS:3
}
CleanupStack::PopAndDestroy( &cmMethods ); // CS:2
currentDestinations.Append( destinationlessIaps );
//Get count of iaps per destination
CmManagerL().AllDestinationsL( destIdArray );
CCHLOGSTRING2( "CCCHCommDbWatcher::CheckIapsL: destination count %d",
destIdArray.Count() )
for ( TInt i = 0; i < destIdArray.Count(); i++ )
{
RCmDestination destination = CmManagerL().DestinationL( destIdArray[ i ] );
CleanupClosePushL( destination ); // CS:3
TDestinationData destinationInfo(
destination.Id(), destination.ConnectionMethodCount() );
for ( TInt k = 0; k < destinationInfo.iIapCount; k++ )
{
RCmConnectionMethod cm = destination.ConnectionMethodL( k );
CleanupClosePushL( cm ); // CS:4
if( KUidWlanBearerType ==
cm.GetIntAttributeL( CMManager::ECmBearerType ) )
{
destinationInfo.iWlanIaps++;
}
CleanupStack::PopAndDestroy( &cm ); // CS:3
}
currentDestinations.Append( destinationInfo );
CleanupStack::PopAndDestroy( &destination ); // CS:2
}
destIdArray.Close();
UpdateDestinationStore( currentDestinations, aChanged, aSNAPId );
CleanupStack::PopAndDestroy( ¤tDestinations ); // CS:1
CleanupStack::PopAndDestroy( &destIdArray ); // CS:0
CCHLOGSTRING2( "CCCHCommDbWatcher::CheckIapsL: OUT changed: %d", aChanged );
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::CountIapsFromArray
//
// ---------------------------------------------------------------------------
//
TInt CCCHCommDbWatcher::CountIapsFromArray(
RArray<TDestinationData>& aArray ) const
{
TInt iaps = 0;
for ( TInt i=0; i<aArray.Count(); i++ )
{
iaps+= aArray[i].iIapCount;
}
return iaps;
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::UpdateDestinationStore
//
// ---------------------------------------------------------------------------
//
void CCCHCommDbWatcher::UpdateDestinationStore(
RArray<TDestinationData>& aDestinations,
TBool& aChanged,
TInt& aSNAPId )
{
//Now compare fetched data with store
TInt iapsBefore = CountIapsFromArray ( iDestinations );
TInt iapsAfter = CountIapsFromArray ( aDestinations );
aSNAPId = KErrNotFound;
aChanged = EFalse;
//no further checking is needed if iap count decreased
if ( iapsAfter >= iapsBefore )
{
//compare store with current setup for changes
//only change in WLAN iap count is reported
for ( TInt i = 0; !aChanged && i < aDestinations.Count(); i++ )
{
TBool alreadyexists = EFalse;
for ( TInt j = 0; !aChanged && j < iDestinations.Count(); j++ )
{
if ( aDestinations[i].iDestId == iDestinations[j].iDestId )
{
alreadyexists = ETrue;
// Do not update snap id if destination is -1, this means
// that cmmanager hasn't moved iap to the right destination yet
if ( aDestinations[i].iWlanIaps >
iDestinations[j].iWlanIaps )
{
if ( KErrNotFound == aDestinations[ i ].iDestId )
{
// If destination -1 is the only updated destination
// we have to use force next time when asking GetIapCountFromSnap
iUseForce = ETrue;
CCHLOGSTRING( "CCCHCommDbWatcher - USE THE FORCE NEXT TIME" );
}
else
{
//wlan iap count increased in comp[i]
aSNAPId = aDestinations[i].iDestId;
aChanged = ETrue;
iUseForce = EFalse;
CCHLOGSTRING2( "CCCHCommDbWatcher - snap id: %d", aSNAPId );
}
}
}
}
//if there is a new SNAP, check wlan iap count in the new IAP
if ( !alreadyexists && aDestinations[i].iWlanIaps > 0 )
{
aSNAPId = aDestinations[i].iDestId;
aChanged = ETrue;
CCHLOGSTRING2( "CCCHCommDbWatcher new snap id: %d", aSNAPId );
}
}
}
//update store
iDestinations.Reset();
for ( TInt i=0; i < aDestinations.Count(); i++ )
{
iDestinations.Append( aDestinations[i] );
// Destinations are refreshed, set last error to kerrnone
iLastError = KErrNone;
}
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::UpdateIapTable
//
// ---------------------------------------------------------------------------
//
TInt CCCHCommDbWatcher::UpdateIapTable()
{
TBool configurationChanged( EFalse );
TInt changedSnapId( KErrNotFound );
TInt error( KErrNone );
TRAP( error, CheckIapsL( configurationChanged, changedSnapId ) );
if ( error == KErrNone )
{
if( configurationChanged )
{
// new IAP(s) added, notify observer
iObserver.HandleWLANIapAdded( changedSnapId );
}
}
CCHLOGSTRING2( "CCCHCommDbWatcher::UpdateIapTable: CActive iStatus : %d", iStatus.Int() );
return error;
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::InitializeDestination
//
// ---------------------------------------------------------------------------
//
void CCCHCommDbWatcher::InitializeDestination()
{
//call CheckWLANIapsL to get initial iap/snap list to array
//we're not interested in the return value at this point
TBool configurationChanged( EFalse );
TInt changedSnapId( 0 );
// Loop, because transaction might pend and error(KErrLocked) may occur
TInt error( KErrNone );
for ( TInt i( 0 ); i < KMaxCheckAttempts; i++ )
{
TRAP( error, CheckIapsL( configurationChanged, changedSnapId ) );
CCHLOGSTRING2(
"CCCHCommDbWatcher::InitializeDestination; error: %d", error );
if( KErrNone == error || KErrNotFound == error )
{
break;
}
}
if( error )
{
iLastError = error;
}
}
// ---------------------------------------------------------------------------
// CCCHCommsDbWatcher::RemoveOtherThanVpnIapsL
//
// ---------------------------------------------------------------------------
//
void CCCHCommDbWatcher::RemoveOtherThanVpnIapsL(
RArray<TUint>& aIapIds,
TUint aIAPId )
{
CCHLOGSTRING2( "CCCHCommDbWatcher::RemoveOtherThanVpnIapsL; IAP ID: %d", aIAPId );
CCHLOGSTRING2( "CCCHCommDbWatcher::RemoveOtherThanVpnIapsL; IAPs count before: %d", aIapIds.Count() );
TUint32 iapId( KErrNone );
RArray<TUint> iaps;
CleanupClosePushL( iaps );
RCmConnectionMethod cm = CmManagerL().ConnectionMethodL( aIAPId );
CleanupClosePushL( cm );
TUint32 realIap( cm.GetIntAttributeL( CMManager::ECmNextLayerIapId ) );
CCHLOGSTRING2( "CCCHCommDbWatcher::RemoveOtherThanVpnIapsL: real iap %d ", realIap );
TUint32 realSnap( cm.GetIntAttributeL( CMManager::ECmNextLayerSNAPId ) );
CCHLOGSTRING2( "CCCHCommDbWatcher::RemoveOtherThanVpnIapsL: real snap %d", realSnap );
if ( realIap )
{
CCHLOGSTRING( "CCCHCommDbWatcher::RemoveOtherThanVpnIapsL: VPN linked to IAP" );
if ( KErrNotFound != aIapIds.Find( realIap ) )
{
iaps.Append( realIap );
}
}
else
{
CCHLOGSTRING( "CCCHCommDbWatcher::RemoveOtherThanVpnIapsL: VPN linked to SNAP" );
RCmDestination realDestination = CmManagerL().DestinationL( realSnap );
CleanupClosePushL( realDestination );
for ( TInt i = 0; i < realDestination.ConnectionMethodCount(); i++ )
{
RCmConnectionMethod realCm = realDestination.ConnectionMethodL( i );
CleanupClosePushL( realCm );
iapId = realCm.GetIntAttributeL( CMManager::ECmIapId );
if ( KErrNotFound != aIapIds.Find( iapId ) )
{
iaps.Append( iapId );
}
CleanupStack::PopAndDestroy( &realCm );
}
CleanupStack::PopAndDestroy( &realDestination );
}
aIapIds.Reset();
for ( TInt j( 0 ); j < iaps.Count(); j++ )
{
aIapIds.Append( iaps[ j ] );
}
CleanupStack::PopAndDestroy( &cm );
CleanupStack::PopAndDestroy( &iaps );
CCHLOGSTRING2( "CCCHCommDbWatcher::RemoveOtherThanVpnIapsL; IAPs count after: %d", aIapIds.Count() );
}
// ========================== OTHER EXPORTED FUNCTIONS =======================
// End of File