src/plugins/bearer/symbian/symbianengine.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
child 37 758a864f9613
--- a/src/plugins/bearer/symbian/symbianengine.cpp	Tue Jul 06 15:10:48 2010 +0300
+++ b/src/plugins/bearer/symbian/symbianengine.cpp	Wed Aug 18 10:37:55 2010 +0300
@@ -46,7 +46,6 @@
 #include <cdbcols.h>
 #include <d32dbms.h>
 #include <nifvar.h>
-#include <QEventLoop>
 #include <QTimer>
 #include <QTime>  // For randgen seeding
 #include <QtCore> // For randgen seeding
@@ -64,18 +63,15 @@
     #include <cmpluginpacketdatadef.h>
     #include <cmplugindialcommondefs.h>
 #else
-    #include <apaccesspointitem.h>
-    #include <apdatahandler.h>
-    #include <aputils.h> 
+    #include <ApAccessPointItem.h>
+    #include <ApDataHandler.h>
+    #include <ApUtils.h> 
 #endif
 
 #ifndef QT_NO_BEARERMANAGEMENT
 
 QT_BEGIN_NAMESPACE
 
-#ifdef SNAP_FUNCTIONALITY_AVAILABLE
-    static const int KValueThatWillBeAddedToSNAPId = 1000;
-#endif
 static const int KUserChoiceIAPId = 0;
 
 SymbianNetworkConfigurationPrivate::SymbianNetworkConfigurationPrivate()
@@ -114,14 +110,19 @@
 }
 
 SymbianEngine::SymbianEngine(QObject *parent)
-:   QBearerEngine(parent), CActive(CActive::EPriorityIdle), iFirstUpdate(true), iInitOk(true),
-    iIgnoringUpdates(false), iTimeToWait(0), iIgnoreEventLoop(0)
+:   QBearerEngine(parent), CActive(CActive::EPriorityHigh), iFirstUpdate(true), iInitOk(true),
+    iUpdatePending(false)
 {
+}
+
+void SymbianEngine::initialize()
+{
+    QMutexLocker locker(&mutex);
+
     CActiveScheduler::Add(this);
 
     // Seed the randomgenerator
     qsrand(QTime(0,0,0).secsTo(QTime::currentTime()) + QCoreApplication::applicationPid());
-    iIgnoreEventLoop = new QEventLoop(this);
 
     TRAPD(error, ipCommsDB = CCommsDatabase::NewL(EDatabaseTypeIAP));
     if (error != KErrNone) {
@@ -130,20 +131,18 @@
     }
 
     TRAP_IGNORE(iConnectionMonitor.ConnectL());
+#ifdef SNAP_FUNCTIONALITY_AVAILABLE
+    TRAP_IGNORE(iConnectionMonitor.SetUintAttribute(EBearerIdAll, 0, KBearerGroupThreshold, 1));
+#endif
     TRAP_IGNORE(iConnectionMonitor.NotifyEventL(*this));
 
-#ifdef SNAP_FUNCTIONALITY_AVAILABLE    
+#ifdef SNAP_FUNCTIONALITY_AVAILABLE
     TRAP(error, iCmManager.OpenL());
     if (error != KErrNone) {
         iInitOk = false;
         return;
     }
 #endif
-}
-
-void SymbianEngine::initialize()
-{
-    QMutexLocker locker(&mutex);
 
     SymbianNetworkConfigurationPrivate *cpPriv = new SymbianNetworkConfigurationPrivate;
     cpPriv->name = "UserChoice";
@@ -190,6 +189,28 @@
     delete cleanup;
 }
 
+void SymbianEngine::delayedConfigurationUpdate()
+{
+    QMutexLocker locker(&mutex);
+
+    if (iUpdatePending) {
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+        qDebug("QNCM delayed configuration update (ECommit or ERecover occurred).");
+#endif
+        TRAPD(error, updateConfigurationsL());
+        if (error == KErrNone) {
+            updateStatesToSnaps();
+        }
+        iUpdatePending = false;
+        // Start monitoring again.
+        if (!IsActive()) {
+            SetActive();
+            // Start waiting for new notification
+            ipCommsDB->RequestNotification(iStatus);
+        }
+    }
+}
+
 bool SymbianEngine::hasIdentifier(const QString &id)
 {
     QMutexLocker locker(&mutex);
@@ -238,19 +259,14 @@
 
 void SymbianEngine::updateConfigurations()
 {
-    QMutexLocker locker(&mutex);
-
-    if (!iInitOk) {
+    if (!iInitOk)
         return;
-    }
 
     TRAP_IGNORE(updateConfigurationsL());
 }
 
 void SymbianEngine::updateConfigurationsL()
 {
-    QMutexLocker locker(&mutex);
-
     QList<QString> knownConfigs = accessPointConfigurations.keys();
     QList<QString> knownSnapConfigs = snapConfigurations.keys();
 
@@ -266,7 +282,7 @@
         RCmConnectionMethod connectionMethod = iCmManager.ConnectionMethodL(connectionMethods[i]);
         CleanupClosePushL(connectionMethod);
         TUint32 iapId = connectionMethod.GetIntAttributeL(CMManager::ECmIapId);
-        QString ident = QString::number(qHash(iapId));
+        QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId));
         if (accessPointConfigurations.contains(ident)) {
             knownConfigs.removeOne(ident);
         } else {
@@ -276,9 +292,13 @@
                 QNetworkConfigurationPrivatePointer ptr(cpPriv);
                 accessPointConfigurations.insert(ptr->id, ptr);
 
-                locker.unlock();
-                emit configurationAdded(ptr);
-                locker.relock();
+                mutex.unlock();
+                // Emit configuration added. Connected slots may throw execptions
+                // which propagate here --> must be converted to leaves (standard
+                // std::exception would cause any TRAP trapping this function to terminate
+                // program).
+                QT_TRYCATCH_LEAVING(emit configurationAdded(ptr));
+                mutex.lock();
             }
         }
         CleanupStack::PopAndDestroy(&connectionMethod);
@@ -293,15 +313,15 @@
         RCmDestination destination;
         destination = iCmManager.DestinationL(destinations[i]);
         CleanupClosePushL(destination);
-        QString ident = QString::number(qHash(destination.Id()+KValueThatWillBeAddedToSNAPId)); //TODO: Check if it's ok to add 1000 SNAP Id to prevent SNAP ids overlapping IAP ids
+        QString ident = QT_BEARERMGMT_CONFIGURATION_SNAP_PREFIX +
+                        QString::number(qHash(destination.Id()));
         if (snapConfigurations.contains(ident)) {
             knownSnapConfigs.removeOne(ident);
         } else {
             SymbianNetworkConfigurationPrivate *cpPriv = new SymbianNetworkConfigurationPrivate;
-            CleanupStack::PushL(cpPriv);
     
             HBufC *pName = destination.NameLC();
-            cpPriv->name = QString::fromUtf16(pName->Ptr(),pName->Length());
+            QT_TRYCATCH_LEAVING(cpPriv->name = QString::fromUtf16(pName->Ptr(),pName->Length()));
             CleanupStack::PopAndDestroy(pName);
             pName = NULL;
     
@@ -317,60 +337,61 @@
             QNetworkConfigurationPrivatePointer ptr(cpPriv);
             snapConfigurations.insert(ident, ptr);
 
-            locker.unlock();
-            emit configurationAdded(ptr);
-            locker.relock();
-            
-            CleanupStack::Pop(cpPriv);
+            mutex.unlock();
+            QT_TRYCATCH_LEAVING(emit configurationAdded(ptr));
+            mutex.lock();
         }
-        QNetworkConfigurationPrivatePointer privSNAP = snapConfigurations.value(ident);
-            
+
+        // Loop through all connection methods in this SNAP
+        QMap<unsigned int, QNetworkConfigurationPrivatePointer> connections;
         for (int j=0; j < destination.ConnectionMethodCount(); j++) {
             RCmConnectionMethod connectionMethod = destination.ConnectionMethodL(j);
             CleanupClosePushL(connectionMethod);
-            
+
             TUint32 iapId = connectionMethod.GetIntAttributeL(CMManager::ECmIapId);
-            QString iface = QString::number(qHash(iapId));
+            QString iface = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId));
             // Check that IAP can be found from accessPointConfigurations list
-            QNetworkConfigurationPrivatePointer priv = accessPointConfigurations.value(iface);
-            if (!priv) {
+            QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iface);
+            if (ptr) {
+                knownConfigs.removeOne(iface);
+            } else {
                 SymbianNetworkConfigurationPrivate *cpPriv = NULL;
                 TRAP(error, cpPriv = configFromConnectionMethodL(connectionMethod));
                 if (error == KErrNone) {
-                    QNetworkConfigurationPrivatePointer ptr(cpPriv);
-                    toSymbianConfig(ptr)->serviceNetworkPtr = privSNAP;
+                    ptr = QNetworkConfigurationPrivatePointer(cpPriv);
                     accessPointConfigurations.insert(ptr->id, ptr);
 
-                    locker.unlock();
-                    emit configurationAdded(ptr);
-                    locker.relock();
-
-                    privSNAP->serviceNetworkMembers.append(ptr);
-                }
-            } else {
-                knownConfigs.removeOne(iface);
-                // Check that IAP can be found from related SNAP's configuration list
-                bool iapFound = false;
-                for (int i = 0; i < privSNAP->serviceNetworkMembers.count(); i++) {
-                    if (toSymbianConfig(privSNAP->serviceNetworkMembers[i])->numericId == iapId) {
-                        iapFound = true;
-                        break;
-                    }
-                }
-                if (!iapFound) {
-                    toSymbianConfig(priv)->serviceNetworkPtr = privSNAP;
-                    privSNAP->serviceNetworkMembers.append(priv);
+                    mutex.unlock();
+                    QT_TRYCATCH_LEAVING(emit configurationAdded(ptr));
+                    mutex.lock();
                 }
             }
-            
+
+            if (ptr) {
+                unsigned int priority;
+                TRAPD(error, priority = destination.PriorityL(connectionMethod));
+                if (!error)
+                    connections.insert(priority, ptr);
+            }
+
             CleanupStack::PopAndDestroy(&connectionMethod);
         }
-        
-        if (privSNAP->serviceNetworkMembers.count() > 1) {
+
+        QNetworkConfigurationPrivatePointer privSNAP = snapConfigurations.value(ident);
+        QMutexLocker snapConfigLocker(&privSNAP->mutex);
+
+        if (privSNAP->serviceNetworkMembers != connections) {
+            privSNAP->serviceNetworkMembers = connections;
+
             // Roaming is supported only if SNAP contains more than one IAP
-            privSNAP->roamingSupported = true;
+            privSNAP->roamingSupported = privSNAP->serviceNetworkMembers.count() > 1;
+
+            snapConfigLocker.unlock();
+            mutex.unlock();
+            QT_TRYCATCH_LEAVING(emit configurationChanged(privSNAP));
+            mutex.lock();
         }
-        
+
         CleanupStack::PopAndDestroy(&destination);
     }
     CleanupStack::PopAndDestroy(&destinations);
@@ -384,7 +405,7 @@
     TInt retVal = pDbTView->GotoFirstRecord();
     while (retVal == KErrNone) {
         pDbTView->ReadUintL(TPtrC(COMMDB_ID), apId);
-        QString ident = QString::number(qHash(apId));
+        QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(apId));
         if (accessPointConfigurations.contains(ident)) {
             knownConfigs.removeOne(ident);
         } else {
@@ -393,9 +414,9 @@
                 QNetworkConfigurationPrivatePointer ptr(cpPriv);
                 accessPointConfigurations.insert(ident, ptr);
 
-                locker.unlock();
-                emit configurationAdded(ptr);
-                locker.relock();
+                mutex.unlock();
+                QT_TRYCATCH_LEAVING(emit configurationAdded(ptr));
+                mutex.lock();
             } else {
                 delete cpPriv;
             }
@@ -404,24 +425,29 @@
     }
     CleanupStack::PopAndDestroy(pDbTView);
 #endif
-    updateActiveAccessPoints();
+    QT_TRYCATCH_LEAVING(updateActiveAccessPoints());
     
     foreach (const QString &oldIface, knownConfigs) {
         //remove non existing IAP
         QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(oldIface);
 
-        locker.unlock();
+        mutex.unlock();
         emit configurationRemoved(ptr);
-        locker.relock();
+        QT_TRYCATCH_LEAVING(emit configurationRemoved(ptr));
+        mutex.lock();
 
         // Remove non existing IAP from SNAPs
         foreach (const QString &iface, snapConfigurations.keys()) {
             QNetworkConfigurationPrivatePointer ptr2 = snapConfigurations.value(iface);
             // => Check if one of the IAPs of the SNAP is active
-            for (int i = 0; i < ptr2->serviceNetworkMembers.count(); ++i) {
-                if (toSymbianConfig(ptr2->serviceNetworkMembers[i])->numericId ==
-                    toSymbianConfig(ptr)->numericId) {
-                    ptr2->serviceNetworkMembers.removeAt(i);
+            QMutexLocker snapConfigLocker(&ptr2->mutex);
+            QMutableMapIterator<unsigned int, QNetworkConfigurationPrivatePointer> i(ptr2->serviceNetworkMembers);
+            while (i.hasNext()) {
+                i.next();
+
+                if (toSymbianConfig(i.value())->numericIdentifier() ==
+                    toSymbianConfig(ptr)->numericIdentifier()) {
+                    i.remove();
                     break;
                 }
             }
@@ -432,27 +458,29 @@
         //remove non existing SNAPs
         QNetworkConfigurationPrivatePointer ptr = snapConfigurations.take(oldIface);
 
-        locker.unlock();
+        mutex.unlock();
         emit configurationRemoved(ptr);
-        locker.relock();
+        QT_TRYCATCH_LEAVING(emit configurationRemoved(ptr));
+        mutex.lock();
     }
+
+    // find default configuration.
+    stopCommsDatabaseNotifications();
+    TRAP_IGNORE(defaultConfig = defaultConfigurationL());
+    startCommsDatabaseNotifications();
 }
 
 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
 SymbianNetworkConfigurationPrivate *SymbianEngine::configFromConnectionMethodL(
         RCmConnectionMethod& connectionMethod)
 {
-    QMutexLocker locker(&mutex);
-
     SymbianNetworkConfigurationPrivate *cpPriv = new SymbianNetworkConfigurationPrivate;
-    CleanupStack::PushL(cpPriv);
-    
     TUint32 iapId = connectionMethod.GetIntAttributeL(CMManager::ECmIapId);
-    QString ident = QString::number(qHash(iapId));
+    QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId));
     
     HBufC *pName = connectionMethod.GetStringAttributeL(CMManager::ECmName);
     CleanupStack::PushL(pName);
-    cpPriv->name = QString::fromUtf16(pName->Ptr(),pName->Length());
+    QT_TRYCATCH_LEAVING(cpPriv->name = QString::fromUtf16(pName->Ptr(),pName->Length()));
     CleanupStack::PopAndDestroy(pName);
     pName = NULL;
     
@@ -500,7 +528,7 @@
 
     if (error == KErrNone && pName) {
         CleanupStack::PushL(pName);
-        cpPriv->mappingName = QString::fromUtf16(pName->Ptr(),pName->Length());
+        QT_TRYCATCH_LEAVING(cpPriv->mappingName = QString::fromUtf16(pName->Ptr(),pName->Length()));
         CleanupStack::PopAndDestroy(pName);
         pName = NULL;
     }
@@ -518,16 +546,12 @@
     cpPriv->type = QNetworkConfiguration::InternetAccessPoint;
     cpPriv->purpose = QNetworkConfiguration::UnknownPurpose;
     cpPriv->roamingSupported = false;
-    
-    CleanupStack::Pop(cpPriv);
     return cpPriv;
 }
 #else
 bool SymbianEngine::readNetworkConfigurationValuesFromCommsDb(
         TUint32 aApId, SymbianNetworkConfigurationPrivate *apNetworkConfiguration)
 {
-    QMutexLocker locker(&mutex);
-
     TRAPD(error, readNetworkConfigurationValuesFromCommsDbL(aApId,apNetworkConfiguration));
     if (error != KErrNone) {
         return false;        
@@ -538,8 +562,6 @@
 void SymbianEngine::readNetworkConfigurationValuesFromCommsDbL(
         TUint32 aApId, SymbianNetworkConfigurationPrivate *apNetworkConfiguration)
 {
-    QMutexLocker locker(&mutex);
-
     CApDataHandler* pDataHandler = CApDataHandler::NewLC(*ipCommsDB); 
     CApAccessPointItem* pAPItem = CApAccessPointItem::NewLC(); 
     TBuf<KCommsDbSvrMaxColumnNameLength> name;
@@ -554,9 +576,9 @@
         User::Leave(KErrNotFound);
     }
     
-    QString ident = QString::number(qHash(aApId));
+    QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(aApId));
     
-    apNetworkConfiguration->name = QString::fromUtf16(name.Ptr(),name.Length());
+    QT_TRYCATCH_LEAVING(apNetworkConfiguration->name = QString::fromUtf16(name.Ptr(),name.Length()));
     apNetworkConfiguration->isValid = true;
     apNetworkConfiguration->id = ident;
     apNetworkConfiguration->numericId = aApId;
@@ -602,15 +624,7 @@
 {
     QMutexLocker locker(&mutex);
 
-    QNetworkConfigurationPrivatePointer ptr;
-
-    if (iInitOk) {
-        stopCommsDatabaseNotifications();
-        TRAP_IGNORE(ptr = defaultConfigurationL());
-        startCommsDatabaseNotifications();
-    }
-
-    return ptr;
+    return defaultConfig;
 }
 
 QStringList SymbianEngine::accessPointConfigurationIdentifiers()
@@ -622,8 +636,6 @@
 
 QNetworkConfigurationPrivatePointer SymbianEngine::defaultConfigurationL()
 {
-    QMutexLocker locker(&mutex);
-
     QNetworkConfigurationPrivatePointer ptr;
 
 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
@@ -631,26 +643,28 @@
     TCmDefConnValue defaultConnectionValue;
     iCmManager.ReadDefConnL(defaultConnectionValue);
     if (defaultConnectionValue.iType == ECmDefConnDestination) {
-        QString iface = QString::number(qHash(defaultConnectionValue.iId+KValueThatWillBeAddedToSNAPId));
+        QString iface = QT_BEARERMGMT_CONFIGURATION_SNAP_PREFIX +
+                        QString::number(qHash(defaultConnectionValue.iId));
         ptr = snapConfigurations.value(iface);
     } else if (defaultConnectionValue.iType == ECmDefConnConnectionMethod) {
-        QString iface = QString::number(qHash(defaultConnectionValue.iId));
+        QString iface = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX +
+                        QString::number(qHash(defaultConnectionValue.iId));
         ptr = accessPointConfigurations.value(iface);
     }
 #endif
     
-    if (!ptr || !ptr->isValid) {
-        QString iface = QString::number(qHash(KUserChoiceIAPId));
-        ptr = userChoiceConfigurations.value(iface);
+    if (ptr) {
+        QMutexLocker configLocker(&ptr->mutex);
+        if (ptr->isValid)
+            return ptr;
     }
-    
-    return ptr;
+
+    QString iface = QString::number(qHash(KUserChoiceIAPId));
+    return userChoiceConfigurations.value(iface);
 }
 
 void SymbianEngine::updateActiveAccessPoints()
 {
-    QMutexLocker locker(&mutex);
-
     bool online = false;
     QList<QString> inactiveConfigs = accessPointConfigurations.keys();
 
@@ -672,8 +686,14 @@
             iConnectionMonitor.GetConnectionInfo(i, connectionId, subConnectionCount);
             iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status);
             User::WaitForRequest(status);
-            QString ident = QString::number(qHash(apId));
+            QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(apId));
             QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident);
+#ifdef OCC_FUNCTIONALITY_AVAILABLE
+            if (!ptr) {
+                // If IAP was not found, check if the update was about EasyWLAN
+                ptr = configurationFromEasyWlan(apId, connectionId);
+            }
+#endif
             if (ptr) {
                 iConnectionMonitor.GetIntAttribute(connectionId, subConnectionCount, KConnectionStatus, connectionStatus, status);
                 User::WaitForRequest(status);          
@@ -681,8 +701,9 @@
                     online = true;
                     inactiveConfigs.removeOne(ident);
 
-                    QMutexLocker configLocker(&ptr->mutex);
+                    ptr->mutex.lock();
                     toSymbianConfig(ptr)->connectionId = connectionId;
+                    ptr->mutex.unlock();
 
                     // Configuration is Active
                     changeConfigurationStateTo(ptr, QNetworkConfiguration::Active);
@@ -702,16 +723,14 @@
 
     if (iOnline != online) {
         iOnline = online;
-        locker.unlock();
-        emit this->onlineStateChanged(iOnline);
-        locker.relock();
+        mutex.unlock();
+        emit this->onlineStateChanged(online);
+        mutex.lock();
     }
 }
 
 void SymbianEngine::updateAvailableAccessPoints()
 {
-    QMutexLocker locker(&mutex);
-
     if (!ipAccessPointsAvailabilityScanner) {
         ipAccessPointsAvailabilityScanner = new AccessPointsAvailabilityScanner(*this, iConnectionMonitor);
     }
@@ -723,8 +742,6 @@
 
 void SymbianEngine::accessPointScanningReady(TBool scanSuccessful, TConnMonIapInfo iapInfo)
 {
-    QMutexLocker locker(&mutex);
-
     iUpdateGoingOn = false;
     if (scanSuccessful) {
         QList<QString> unavailableConfigs = accessPointConfigurations.keys();
@@ -732,10 +749,13 @@
         // Set state of returned IAPs to Discovered
         // if state is not already Active
         for(TUint i=0; i<iapInfo.iCount; i++) {
-            QString ident = QString::number(qHash(iapInfo.iIap[i].iIapId));
+            QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX +
+                            QString::number(qHash(iapInfo.iIap[i].iIapId));
             QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident);
             if (ptr) {
                 unavailableConfigs.removeOne(ident);
+
+                QMutexLocker configLocker(&ptr->mutex);
                 if (ptr->state < QNetworkConfiguration::Active) {
                     // Configuration is either Discovered or Active
                     changeConfigurationStateAtMinTo(ptr, QNetworkConfiguration::Discovered);
@@ -757,31 +777,38 @@
     
     if (!iFirstUpdate) {
         startCommsDatabaseNotifications();
-        locker.unlock();
+        mutex.unlock();
         emit updateCompleted();
-        locker.relock();
+        mutex.lock();
     }
 }
 
 void SymbianEngine::updateStatesToSnaps()
 {
-    QMutexLocker locker(&mutex);
-
     // Go through SNAPs and set correct state to SNAPs
     foreach (const QString &iface, snapConfigurations.keys()) {
         bool discovered = false;
         bool active = false;
         QNetworkConfigurationPrivatePointer ptr = snapConfigurations.value(iface);
+
+        QMutexLocker snapConfigLocker(&ptr->mutex);
+
         // => Check if one of the IAPs of the SNAP is discovered or active
         //    => If one of IAPs is active, also SNAP is active
         //    => If one of IAPs is discovered but none of the IAPs is active, SNAP is discovered
-        for (int i=0; i<ptr->serviceNetworkMembers.count(); i++) {
-            if ((ptr->serviceNetworkMembers[i]->state & QNetworkConfiguration::Active)
-                    == QNetworkConfiguration::Active) {
+        QMapIterator<unsigned int, QNetworkConfigurationPrivatePointer> i(ptr->serviceNetworkMembers);
+        while (i.hasNext()) {
+            i.next();
+
+            const QNetworkConfigurationPrivatePointer child = i.value();
+
+            QMutexLocker configLocker(&child->mutex);
+
+            if ((child->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
                 active = true;
                 break;
-            } else if ((ptr->serviceNetworkMembers[i]->state & QNetworkConfiguration::Discovered)
-                        == QNetworkConfiguration::Discovered) {
+            } else if ((child->state & QNetworkConfiguration::Discovered) ==
+                       QNetworkConfiguration::Discovered) {
                 discovered = true;
             }
         }
@@ -795,19 +822,70 @@
     }    
 }
 
+#ifdef SNAP_FUNCTIONALITY_AVAILABLE
+void SymbianEngine::updateMobileBearerToConfigs(TConnMonBearerInfo bearerInfo)
+{
+    QHash<QString, QNetworkConfigurationPrivatePointer>::const_iterator i =
+        accessPointConfigurations.constBegin();
+    while (i != accessPointConfigurations.constEnd()) {
+        QNetworkConfigurationPrivatePointer ptr = i.value();
+
+        QMutexLocker locker(&ptr->mutex);
+
+        SymbianNetworkConfigurationPrivate *p = toSymbianConfig(ptr);
+
+        if (p->bearer >= SymbianNetworkConfigurationPrivate::Bearer2G &&
+            p->bearer <= SymbianNetworkConfigurationPrivate::BearerHSPA) {
+            switch (bearerInfo) {
+            case EBearerInfoCSD:
+                p->bearer = SymbianNetworkConfigurationPrivate::Bearer2G;
+                break;
+            case EBearerInfoWCDMA:
+                p->bearer = SymbianNetworkConfigurationPrivate::BearerWCDMA;
+                break;
+            case EBearerInfoCDMA2000:
+                p->bearer = SymbianNetworkConfigurationPrivate::BearerCDMA2000;
+                break;
+            case EBearerInfoGPRS:
+                p->bearer = SymbianNetworkConfigurationPrivate::Bearer2G;
+                break;
+            case EBearerInfoHSCSD:
+                p->bearer = SymbianNetworkConfigurationPrivate::Bearer2G;
+                break;
+            case EBearerInfoEdgeGPRS:
+                p->bearer = SymbianNetworkConfigurationPrivate::Bearer2G;
+                break;
+            case EBearerInfoWcdmaCSD:
+                p->bearer = SymbianNetworkConfigurationPrivate::BearerWCDMA;
+                break;
+            case EBearerInfoHSDPA:
+                p->bearer = SymbianNetworkConfigurationPrivate::BearerHSPA;
+                break;
+            case EBearerInfoHSUPA:
+                p->bearer = SymbianNetworkConfigurationPrivate::BearerHSPA;
+                break;
+            case EBearerInfoHSxPA:
+                p->bearer = SymbianNetworkConfigurationPrivate::BearerHSPA;
+                break;
+            }
+        }
+
+        ++i;
+    }
+}
+#endif
+
 bool SymbianEngine::changeConfigurationStateTo(QNetworkConfigurationPrivatePointer ptr,
                                                QNetworkConfiguration::StateFlags newState)
 {
-    QMutexLocker locker(&mutex);
-
     ptr->mutex.lock();
     if (newState != ptr->state) {
         ptr->state = newState;
         ptr->mutex.unlock();
 
-        locker.unlock();
+        mutex.unlock();
         emit configurationChanged(ptr);
-        locker.relock();
+        mutex.lock();
 
         return true;
     } else {
@@ -823,16 +901,14 @@
 bool SymbianEngine::changeConfigurationStateAtMinTo(QNetworkConfigurationPrivatePointer ptr,
                                                     QNetworkConfiguration::StateFlags newState)
 {
-    QMutexLocker locker(&mutex);
-
     ptr->mutex.lock();
     if ((newState | ptr->state) != ptr->state) {
         ptr->state = (ptr->state | newState);
         ptr->mutex.unlock();
 
-        locker.unlock();
+        mutex.unlock();
         emit configurationChanged(ptr);
-        locker.relock();
+        mutex.lock();
 
         return true;
     } else {
@@ -849,16 +925,14 @@
 bool SymbianEngine::changeConfigurationStateAtMaxTo(QNetworkConfigurationPrivatePointer ptr,
                                                     QNetworkConfiguration::StateFlags newState)
 {
-    QMutexLocker locker(&mutex);
-
     ptr->mutex.lock();
     if ((newState & ptr->state) != ptr->state) {
         ptr->state = (newState & ptr->state);
         ptr->mutex.unlock();
 
-        locker.unlock();
+        mutex.unlock();
         emit configurationChanged(ptr);
-        locker.relock();
+        mutex.lock();
 
         return true;
     } else {
@@ -869,8 +943,6 @@
 
 void SymbianEngine::startCommsDatabaseNotifications()
 {
-    QMutexLocker locker(&mutex);
-
     if (!iWaitingCommsDatabaseNotifications) {
         iWaitingCommsDatabaseNotifications = ETrue;
         if (!IsActive()) {
@@ -883,19 +955,9 @@
 
 void SymbianEngine::stopCommsDatabaseNotifications()
 {
-    QMutexLocker locker(&mutex);
-
     if (iWaitingCommsDatabaseNotifications) {
         iWaitingCommsDatabaseNotifications = EFalse;
-        if (!IsActive()) {
-            SetActive();
-            // Make sure that notifier recorded events will not be returned
-            // as soon as the client issues the next RequestNotification() request.
-            ipCommsDB->RequestNotification(iStatus);
-            ipCommsDB->CancelRequestNotification();
-        } else {
-            ipCommsDB->CancelRequestNotification();
-        }
+        Cancel();
     }
 }
 
@@ -903,48 +965,25 @@
 {
     QMutexLocker locker(&mutex);
 
-    if (iIgnoringUpdates) {
-#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
-        qDebug("QNCM CommsDB event handling postponed (postpone-timer running because IAPs/SNAPs were updated very recently).");
-#endif
-        return;
-    }
-
     if (iStatus != KErrCancel) {
+        // By default, start relistening notifications. Stop only if interesting event occured.
+        iWaitingCommsDatabaseNotifications = true;
         RDbNotifier::TEvent event = STATIC_CAST(RDbNotifier::TEvent, iStatus.Int());
-
         switch (event) {
-        case RDbNotifier::EUnlock:   /** All read locks have been removed.  */
-        case RDbNotifier::ECommit:   /** A transaction has been committed.  */ 
-        case RDbNotifier::ERollback: /** A transaction has been rolled back */
+        case RDbNotifier::ECommit:   /** A transaction has been committed.  */
         case RDbNotifier::ERecover:  /** The database has been recovered    */
 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
             qDebug("QNCM CommsDB event (of type RDbNotifier::TEvent) received: %d", iStatus.Int());
 #endif
-            iIgnoringUpdates = true;
-            // Other events than ECommit get lower priority. In practice with those events,
-            // we delay_before_updating methods, whereas
-            // with ECommit we _update_before_delaying the reaction to next event.
-            // Few important notes: 1) listening to only ECommit does not seem to be adequate,
-            // but updates will be missed. Hence other events are reacted upon too.
-            // 2) RDbNotifier records the most significant event, and that will be returned once
-            // we issue new RequestNotification, and hence updates will not be missed even
-            // when we are 'not reacting to them' for few seconds.
-            if (event == RDbNotifier::ECommit) {
-                TRAPD(error, updateConfigurationsL());
-                if (error == KErrNone) {
-                    updateStatesToSnaps();
-                }
-                waitRandomTime();
-            } else {
-                waitRandomTime();
-                TRAPD(error, updateConfigurationsL());
-                if (error == KErrNone) {
-                    updateStatesToSnaps();
-                }   
+            // Mark that there is update pending. No need to ask more events,
+            // as we know we will be updating anyway when the timer expires.
+            if (!iUpdatePending) {
+                iUpdatePending = true;
+                iWaitingCommsDatabaseNotifications = false;
+                // Update after random time, so that many processes won't
+                // start updating simultaneously
+                updateConfigurationsAfterRandomTime();
             }
-            iIgnoringUpdates = false; // Wait time done, allow updating again
-            iWaitingCommsDatabaseNotifications = true;
             break;
         default:
             // Do nothing
@@ -973,6 +1012,20 @@
     QMutexLocker locker(&mutex);
 
     switch (aEvent.EventType()) {
+#ifdef SNAP_FUNCTIONALITY_AVAILABLE
+    case EConnMonBearerInfoChange:
+        {
+        CConnMonBearerInfoChange* realEvent;
+        realEvent = (CConnMonBearerInfoChange*) &aEvent;
+        TUint connectionId = realEvent->ConnectionId();
+        if (connectionId == EBearerIdAll) {
+            //Network level event
+            TConnMonBearerInfo bearerInfo = (TConnMonBearerInfo)realEvent->BearerInfo();
+            updateMobileBearerToConfigs(bearerInfo);
+        }
+        break;
+        }
+#endif
     case EConnMonConnectionStatusChange:
         {
         CConnMonConnectionStatusChange* realEvent;
@@ -988,12 +1041,23 @@
             TRequestStatus status;
             iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status);
             User::WaitForRequest(status);
-            QString ident = QString::number(qHash(apId));
+
+            QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(apId));
             QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident);
+#ifdef OCC_FUNCTIONALITY_AVAILABLE
+            if (!ptr) {
+                // Check if status was regarding EasyWLAN
+                ptr = configurationFromEasyWlan(apId, connectionId);
+            }
+#endif
             if (ptr) {
-                QMutexLocker configLocker(&ptr->mutex);
+                ptr->mutex.lock();
                 toSymbianConfig(ptr)->connectionId = connectionId;
-                emit this->configurationStateChanged(toSymbianConfig(ptr)->numericId, connectionId, QNetworkSession::Connecting);
+                ptr->mutex.unlock();
+                QT_TRYCATCH_LEAVING(
+                    emit configurationStateChanged(toSymbianConfig(ptr)->numericIdentifier(),
+                                                   connectionId, QNetworkSession::Connecting)
+                );
             }
         } else if (connectionStatus == KLinkLayerOpen) {
             // Connection has been successfully opened
@@ -1003,27 +1067,41 @@
             TRequestStatus status;
             iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status);
             User::WaitForRequest(status);
-            QString ident = QString::number(qHash(apId));
+            QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(apId));
             QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident);
+#ifdef OCC_FUNCTIONALITY_AVAILABLE
+            if (!ptr) {
+                // Check for EasyWLAN
+                ptr = configurationFromEasyWlan(apId, connectionId);
+            }
+#endif
             if (ptr) {
-                QMutexLocker configLocker(&ptr->mutex);
+                ptr->mutex.lock();
                 toSymbianConfig(ptr)->connectionId = connectionId;
+                ptr->mutex.unlock();
+
                 // Configuration is Active
-                if (changeConfigurationStateTo(ptr, QNetworkConfiguration::Active)) {
-                    updateStatesToSnaps();
-                }
-                emit this->configurationStateChanged(toSymbianConfig(ptr)->numericId, connectionId, QNetworkSession::Connected);
-                if (!iOnline) {
-                    iOnline = true;
-                    emit this->onlineStateChanged(iOnline);
-                }
+                QT_TRYCATCH_LEAVING(
+                    if (changeConfigurationStateTo(ptr, QNetworkConfiguration::Active)) {
+                        updateStatesToSnaps();
+                    }
+                    emit configurationStateChanged(toSymbianConfig(ptr)->numericIdentifier(),
+                                                   connectionId, QNetworkSession::Connected);
+
+                    if (!iOnline) {
+                        iOnline = true;
+                        emit this->onlineStateChanged(iOnline);
+                    }
+                );
             }
         } else if (connectionStatus == KConfigDaemonStartingDeregistration) {
             TUint connectionId = realEvent->ConnectionId();
             QNetworkConfigurationPrivatePointer ptr = dataByConnectionId(connectionId);
             if (ptr) {
-                QMutexLocker configLocker(&ptr->mutex);
-                emit this->configurationStateChanged(toSymbianConfig(ptr)->numericId, connectionId, QNetworkSession::Closing);
+                QT_TRYCATCH_LEAVING(
+                    emit configurationStateChanged(toSymbianConfig(ptr)->numericIdentifier(),
+                                                   connectionId, QNetworkSession::Closing)
+                );
             }
         } else if (connectionStatus == KLinkLayerClosed ||
                    connectionStatus == KConnectionClosed) {
@@ -1033,12 +1111,13 @@
             QNetworkConfigurationPrivatePointer ptr = dataByConnectionId(connectionId);
             if (ptr) {
                 // Configuration is either Defined or Discovered
-                if (changeConfigurationStateAtMaxTo(ptr, QNetworkConfiguration::Discovered)) {
-                    updateStatesToSnaps();
-                }
-
-                QMutexLocker configLocker(&ptr->mutex);
-                emit this->configurationStateChanged(toSymbianConfig(ptr)->numericId, connectionId, QNetworkSession::Disconnected);
+                QT_TRYCATCH_LEAVING(
+                    if (changeConfigurationStateAtMaxTo(ptr, QNetworkConfiguration::Discovered)) {
+                        updateStatesToSnaps();
+                    }
+                    emit configurationStateChanged(toSymbianConfig(ptr)->numericIdentifier(),
+                                                   connectionId, QNetworkSession::Disconnected);
+                );
             }
             
             bool online = false;
@@ -1052,7 +1131,7 @@
             }
             if (iOnline != online) {
                 iOnline = online;
-                emit this->onlineStateChanged(iOnline);
+                QT_TRYCATCH_LEAVING(emit this->onlineStateChanged(iOnline));
             }
         }
         }
@@ -1065,12 +1144,13 @@
         TConnMonIapInfo iaps = realEvent->IapAvailability();
         QList<QString> unDiscoveredConfigs = accessPointConfigurations.keys();
         for ( TUint i = 0; i < iaps.Count(); i++ ) {
-            QString ident = QString::number(qHash(iaps.iIap[i].iIapId));
+            QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX +
+                            QString::number(qHash(iaps.iIap[i].iIapId));
 
             QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident);
             if (ptr) {
                 // Configuration is either Discovered or Active 
-                changeConfigurationStateAtMinTo(ptr, QNetworkConfiguration::Discovered);
+                QT_TRYCATCH_LEAVING(changeConfigurationStateAtMinTo(ptr, QNetworkConfiguration::Discovered));
                 unDiscoveredConfigs.removeOne(ident);
             }
         }
@@ -1078,7 +1158,7 @@
             QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iface);
             if (ptr) {
                 // Configuration is Defined
-                changeConfigurationStateAtMaxTo(ptr, QNetworkConfiguration::Defined);
+                QT_TRYCATCH_LEAVING(changeConfigurationStateAtMaxTo(ptr, QNetworkConfiguration::Defined));
             }
         }
         }
@@ -1095,8 +1175,14 @@
         TRequestStatus status;
         iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status);
         User::WaitForRequest(status);
-        QString ident = QString::number(qHash(apId));
+        QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(apId));
         QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident);
+#ifdef OCC_FUNCTIONALITY_AVAILABLE
+        if (!ptr) {
+            // If IAP was not found, check if the update was about EasyWLAN
+            ptr = configurationFromEasyWlan(apId, connectionId);
+        }
+#endif
         if (ptr) {
             QMutexLocker configLocker(&ptr->mutex);
 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
@@ -1112,6 +1198,43 @@
     }
 }
 
+#ifdef OCC_FUNCTIONALITY_AVAILABLE
+// Tries to derive configuration from EasyWLAN.
+// First checks if the interface brought up was EasyWLAN, then derives the real SSID,
+// and looks up configuration based on that one.
+QNetworkConfigurationPrivatePointer SymbianEngine::configurationFromEasyWlan(TUint32 apId, TUint connectionId)
+{
+    if (apId == iCmManager.EasyWlanIdL()) {
+        TRequestStatus status;
+        TBuf<50> easyWlanNetworkName;
+        iConnectionMonitor.GetStringAttribute( connectionId, 0, KNetworkName,
+                                               easyWlanNetworkName, status );
+        User::WaitForRequest(status);
+        if (status.Int() == KErrNone) {
+            QString realSSID = QString::fromUtf16(easyWlanNetworkName.Ptr(), easyWlanNetworkName.Length());
+
+            // Browser through all items and check their name for match
+            QHash<QString, QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> >::const_iterator i =
+                    accessPointConfigurations.constBegin();
+            while (i != accessPointConfigurations.constEnd()) {
+                QNetworkConfigurationPrivatePointer ptr = i.value();
+
+                QMutexLocker configLocker(&ptr->mutex);
+
+                if (ptr->name == realSSID) {
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+                    qDebug() << "QNCM EasyWlan uses real SSID: " << realSSID;
+#endif
+                    return ptr;
+                }
+                ++i;
+            }
+        }
+    }
+    return QNetworkConfigurationPrivatePointer();
+}
+#endif
+
 // Sessions may use this function to report configuration state changes,
 // because on some Symbian platforms (especially Symbian^3) all state changes are not
 // reported by the RConnectionMonitor, in particular in relation to stop() call,
@@ -1121,13 +1244,16 @@
 // manager). Currently only 'Disconnected' state is of interest because it has proven to be troublesome.
 void SymbianEngine::configurationStateChangeReport(TUint32 accessPointId, QNetworkSession::State newState)
 {
+    QMutexLocker locker(&mutex);
+
 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
     qDebug() << "QNCM A session reported state change for IAP ID: " << accessPointId << " whose new state is: " << newState;
 #endif
     switch (newState) {
     case QNetworkSession::Disconnected:
         {
-            QString ident = QString::number(qHash(accessPointId));
+            QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX +
+                            QString::number(qHash(accessPointId));
             QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident);
             if (ptr) {
                 // Configuration is either Defined or Discovered
@@ -1135,10 +1261,11 @@
                     updateStatesToSnaps();
                 }
 
-                QMutexLocker configLocker(&ptr->mutex);
-                emit this->configurationStateChanged(toSymbianConfig(ptr)->numericId,
-                                                     toSymbianConfig(ptr)->connectionId,
-                                                     QNetworkSession::Disconnected);
+                locker.unlock();
+                emit configurationStateChanged(toSymbianConfig(ptr)->numericIdentifier(),
+                                               toSymbianConfig(ptr)->connectionIdentifier(),
+                                               QNetworkSession::Disconnected);
+                locker.relock();
             }
         }
         break;
@@ -1148,30 +1275,23 @@
 }
 
 // Waits for 2..6 seconds.
-void SymbianEngine::waitRandomTime()
+void SymbianEngine::updateConfigurationsAfterRandomTime()
 {
-    iTimeToWait = (qAbs(qrand()) % 7) * 1000;
-    if (iTimeToWait < 2000) {
-        iTimeToWait = 2000;
-    }
+    int iTimeToWait = qMax(1000, (qAbs(qrand()) % 68) * 100);
 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
     qDebug("QNCM waiting random time: %d ms", iTimeToWait);
 #endif
-    QTimer::singleShot(iTimeToWait, iIgnoreEventLoop, SLOT(quit()));
-    iIgnoreEventLoop->exec();
+    QTimer::singleShot(iTimeToWait, this, SLOT(delayedConfigurationUpdate()));
 }
 
 QNetworkConfigurationPrivatePointer SymbianEngine::dataByConnectionId(TUint aConnectionId)
 {
-    QMutexLocker locker(&mutex);
-
     QNetworkConfiguration item;
     QHash<QString, QNetworkConfigurationPrivatePointer>::const_iterator i =
             accessPointConfigurations.constBegin();
     while (i != accessPointConfigurations.constEnd()) {
         QNetworkConfigurationPrivatePointer ptr = i.value();
-        QMutexLocker configLocker(&ptr->mutex);
-        if (toSymbianConfig(ptr)->connectionId == aConnectionId)
+        if (toSymbianConfig(ptr)->connectionIdentifier() == aConnectionId)
             return ptr;
 
         ++i;
@@ -1182,7 +1302,7 @@
 
 AccessPointsAvailabilityScanner::AccessPointsAvailabilityScanner(SymbianEngine& owner,
                                                                RConnectionMonitor& connectionMonitor)
-    : CActive(CActive::EPriorityStandard), iOwner(owner), iConnectionMonitor(connectionMonitor)
+    : CActive(CActive::EPriorityHigh), iOwner(owner), iConnectionMonitor(connectionMonitor)
 {
     CActiveScheduler::Add(this);  
 }
@@ -1218,11 +1338,13 @@
 
 void AccessPointsAvailabilityScanner::RunL()
 {
+    QMutexLocker locker(&iOwner.mutex);
+
     if (iStatus.Int() != KErrNone) {
         iIapBuf().iCount = 0;
-        iOwner.accessPointScanningReady(false,iIapBuf());
+        QT_TRYCATCH_LEAVING(iOwner.accessPointScanningReady(false,iIapBuf()));
     } else {
-        iOwner.accessPointScanningReady(true,iIapBuf());
+        QT_TRYCATCH_LEAVING(iOwner.accessPointScanningReady(true,iIapBuf()));
     }
 }