Merge remote-tracking branch 'origin/4.7' into qt-4.8-from-4.7
[qt:qt.git] / src / plugins / bearer / symbian / qnetworksession_impl.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the plugins of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qnetworksession_impl.h"
43 #include "symbianengine.h"
44
45 #include <es_enum.h>
46 #include <es_sock.h>
47 #include <in_sock.h>
48 #include <private/qcore_symbian_p.h>
49
50 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
51 #include <cmmanager.h>
52 #endif
53
54 #if defined(OCC_FUNCTIONALITY_AVAILABLE) && defined(SNAP_FUNCTIONALITY_AVAILABLE)
55 #include <extendedconnpref.h>
56 #endif
57
58 #ifndef QT_NO_BEARERMANAGEMENT
59
60 QT_BEGIN_NAMESPACE
61
62 QNetworkSessionPrivateImpl::QNetworkSessionPrivateImpl(SymbianEngine *engine)
63 :   engine(engine), iSocketServ(qt_symbianGetSocketServer()),
64     ipConnectionNotifier(0), ipConnectionStarter(0),
65     iHandleStateNotificationsFromManager(false), iFirstSync(true), iStoppedByUser(false),
66     iClosedByUser(false), iError(QNetworkSession::UnknownSessionError), iALREnabled(0),
67     iConnectInBackground(false), isOpening(false)
68 {
69
70 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
71     iMobility = NULL;
72 #endif
73
74     TRAP_IGNORE(iConnectionMonitor.ConnectL());
75 }
76
77 void QNetworkSessionPrivateImpl::closeHandles()
78 {
79     QMutexLocker lock(&mutex);
80     // Cancel Connection Progress Notifications first.
81     // Note: ConnectionNotifier must be destroyed before RConnection::Close()
82     //       => deleting ipConnectionNotifier results RConnection::CancelProgressNotification()
83     delete ipConnectionNotifier;
84     ipConnectionNotifier = NULL;
85
86 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
87     // mobility monitor must be deleted before RConnection is closed
88     delete iMobility;
89     iMobility = NULL;
90 #endif
91
92     // Cancel possible RConnection::Start() - may call RConnection::Close if Start was in progress
93     delete ipConnectionStarter;
94     ipConnectionStarter = 0;
95     //close any open connection (note Close twice is safe in case Cancel did it above)
96     iConnection.Close();
97
98     QSymbianSocketManager::instance().setDefaultConnection(0);
99
100     iConnectionMonitor.Close();
101 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
102     qDebug() << "QNS this : " << QString::number((uint)this)
103              << " - handles closed";
104 #endif
105
106 }
107
108 QNetworkSessionPrivateImpl::~QNetworkSessionPrivateImpl()
109 {
110     isOpen = false;
111     isOpening = false;
112
113     closeHandles();
114 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
115     qDebug() << "QNS this : " << QString::number((uint)this)
116              << " - destroyed";
117 #endif
118 }
119
120 void QNetworkSessionPrivateImpl::configurationStateChanged(quint32 accessPointId, quint32 connMonId, QNetworkSession::State newState)
121 {
122     if (iHandleStateNotificationsFromManager) {
123 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
124         qDebug() << "QNS this : " << QString::number((uint)this) << " - "
125                  << "configurationStateChanged from manager for IAP : " << QString::number(accessPointId)
126                  << "connMon ID : " << QString::number(connMonId) << " : to a state: " << newState
127                  << "whereas my current state is: " << state;
128 #else
129       Q_UNUSED(connMonId);
130 #endif
131         this->newState(newState, accessPointId);
132     }
133 }
134
135 void QNetworkSessionPrivateImpl::configurationRemoved(QNetworkConfigurationPrivatePointer config)
136 {
137     if (!publicConfig.isValid())
138         return;
139
140     TUint32 publicNumericId =
141         toSymbianConfig(privateConfiguration(publicConfig))->numericIdentifier();
142
143     if (toSymbianConfig(config)->numericIdentifier() == publicNumericId) {
144 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
145         qDebug() << "QNS this : " << QString::number((uint)this) << " - "
146                  << "configurationRemoved IAP: " << QString::number(publicNumericId) << " : going to State: Invalid";
147 #endif
148         this->newState(QNetworkSession::Invalid, publicNumericId);
149     }
150 }
151
152 void QNetworkSessionPrivateImpl::configurationAdded(QNetworkConfigurationPrivatePointer config)
153 {
154     Q_UNUSED(config);
155     // If session is based on service network, some other app may create new access points
156     // to the SNAP --> synchronize session's state with that of interface's.
157     if (!publicConfig.isValid() || publicConfig.type() != QNetworkConfiguration::ServiceNetwork)
158         return;
159
160 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
161         qDebug() << "QNS this : " << QString::number((uint)this) << " - "
162                  << "configurationAdded IAP: "
163                  << toSymbianConfig(config)->numericIdentifier();
164 #endif
165
166         syncStateWithInterface();
167 }
168
169 // Function sets the state of the session to match the state
170 // of the underlying interface (the configuration this session is based on)
171 void QNetworkSessionPrivateImpl::syncStateWithInterface()
172 {
173     if (!publicConfig.isValid())
174         return;
175
176     if (iFirstSync) {
177         QObject::connect(engine,
178                          SIGNAL(configurationStateChanged(quint32,quint32,QNetworkSession::State)),
179                          this,
180                          SLOT(configurationStateChanged(quint32,quint32,QNetworkSession::State)));
181         // Listen to configuration removals, so that in case the configuration
182         // this session is based on is removed, session knows to enter Invalid -state.
183         QObject::connect(engine, SIGNAL(configurationRemoved(QNetworkConfigurationPrivatePointer)),
184                          this, SLOT(configurationRemoved(QNetworkConfigurationPrivatePointer)));
185         // Connect to configuration additions, so that in case a configuration is added
186         // in a SNAP this session is based on, the session knows to synch its state with its
187         // interface.
188         QObject::connect(engine, SIGNAL(configurationAdded(QNetworkConfigurationPrivatePointer)),
189                          this, SLOT(configurationAdded(QNetworkConfigurationPrivatePointer)));
190     }
191     // Start listening IAP state changes from QNetworkConfigurationManagerPrivate
192     iHandleStateNotificationsFromManager = true;    
193
194     // Check what is the state of the configuration this session is based on
195     // and set the session in appropriate state.
196 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
197     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
198              << "syncStateWithInterface() state of publicConfig is: " << publicConfig.state();
199 #endif
200     switch (publicConfig.state()) {
201     case QNetworkConfiguration::Active:
202         newState(QNetworkSession::Connected);
203         break;
204     case QNetworkConfiguration::Discovered:
205         newState(QNetworkSession::Disconnected);
206         break;
207     case QNetworkConfiguration::Defined:
208         newState(QNetworkSession::NotAvailable);
209         break;
210     case QNetworkConfiguration::Undefined:
211     default:
212         newState(QNetworkSession::Invalid);
213     }
214 }
215
216 #ifndef QT_NO_NETWORKINTERFACE
217 QNetworkInterface QNetworkSessionPrivateImpl::interface(TUint iapId) const
218 {
219     QString interfaceName;
220
221     TSoInetInterfaceInfo ifinfo;
222     TPckg<TSoInetInterfaceInfo> ifinfopkg(ifinfo);
223     TSoInetIfQuery ifquery;
224     TPckg<TSoInetIfQuery> ifquerypkg(ifquery);
225  
226     // Open dummy socket for interface queries
227     RSocket socket;
228     TInt retVal = socket.Open(iSocketServ, _L("udp"));
229     if (retVal != KErrNone) {
230         return QNetworkInterface();
231     }
232  
233     // Start enumerating interfaces
234     socket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl);
235     while(socket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, ifinfopkg) == KErrNone) {
236         ifquery.iName = ifinfo.iName;
237         TInt err = socket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, ifquerypkg);
238         if(err == KErrNone && ifquery.iZone[1] == iapId) { // IAP ID is index 1 of iZone
239             if(ifinfo.iAddress.Address() > 0) {
240                 interfaceName = QString::fromUtf16(ifinfo.iName.Ptr(),ifinfo.iName.Length());
241                 break;
242             }
243         }
244     }
245  
246     socket.Close();
247  
248     if (interfaceName.isEmpty()) {
249         return QNetworkInterface();
250     }
251  
252     return QNetworkInterface::interfaceFromName(interfaceName);
253 }
254 #endif
255
256 #ifndef QT_NO_NETWORKINTERFACE
257 QNetworkInterface QNetworkSessionPrivateImpl::currentInterface() const
258 {
259 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
260     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
261              << "currentInterface() requested, state: " << state
262              << "publicConfig validity: " << publicConfig.isValid();
263     if (activeInterface.isValid())
264         qDebug() << "QNS this : " << QString::number((uint)this) << " - "
265                  << "interface is: " << activeInterface.humanReadableName();
266 #endif
267
268     if (!publicConfig.isValid() || state != QNetworkSession::Connected) {
269         return QNetworkInterface();
270     }
271     
272     return activeInterface;
273 }
274 #endif
275
276 QVariant QNetworkSessionPrivateImpl::sessionProperty(const QString& key) const
277 {
278     if (key == "ConnectInBackground") {
279         return QVariant(iConnectInBackground);
280     }
281     return QVariant();
282 }
283
284 void QNetworkSessionPrivateImpl::setSessionProperty(const QString& key, const QVariant& value)
285 {
286     // Valid value means adding property, invalid means removing it.
287     if (key == "ConnectInBackground") {
288         if (value.isValid()) {
289             iConnectInBackground = value.toBool();
290         } else {
291             iConnectInBackground = EFalse;
292         }
293     }
294 }
295
296 QString QNetworkSessionPrivateImpl::errorString() const
297 {
298     switch (iError) {
299     case QNetworkSession::UnknownSessionError:
300         return tr("Unknown session error.");
301     case QNetworkSession::SessionAbortedError:
302         return tr("The session was aborted by the user or system.");
303     case QNetworkSession::OperationNotSupportedError:
304         return tr("The requested operation is not supported by the system.");
305     case QNetworkSession::InvalidConfigurationError:
306         return tr("The specified configuration cannot be used.");
307     case QNetworkSession::RoamingError:
308         return tr("Roaming was aborted or is not possible.");
309     }
310  
311     return QString();
312 }
313
314 QNetworkSession::SessionError QNetworkSessionPrivateImpl::error() const
315 {
316     return iError;
317 }
318
319 void QNetworkSessionPrivateImpl::open()
320 {
321     QMutexLocker lock(&mutex);
322 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
323         qDebug() << "QNS this : " << QString::number((uint)this) << " - "
324                 << "open() called, session state is: " << state << " and isOpen is: "
325                 << isOpen << isOpening;
326 #endif
327
328     if (isOpen || isOpening)
329         return;
330
331     isOpening = true;
332
333     // Stop handling IAP state change signals from QNetworkConfigurationManagerPrivate
334     // => RConnection::ProgressNotification will be used for IAP/SNAP monitoring
335     iHandleStateNotificationsFromManager = false;
336
337     // Configuration may have been invalidated after session creation by platform
338     // (e.g. configuration has been deleted).
339     if (!publicConfig.isValid()) {
340         newState(QNetworkSession::Invalid);
341         iError = QNetworkSession::InvalidConfigurationError;
342         emit QNetworkSessionPrivate::error(iError);
343         return;
344     }
345     // If opening a undefined configuration, session emits error and enters
346     // NotAvailable -state. Note that we will try ones in 'defined' state to avoid excessive
347     // need for WLAN scans (via updateConfigurations()), because user may have walked
348     // into a WLAN range, but periodic background scan has not occurred yet -->
349     // we don't want to force application to make frequent updateConfigurations() calls
350     // to be able to try if e.g. home WLAN is available.
351     if (publicConfig.state() == QNetworkConfiguration::Undefined) {
352         newState(QNetworkSession::NotAvailable);
353         iError = QNetworkSession::InvalidConfigurationError;
354         emit QNetworkSessionPrivate::error(iError);
355         return;
356     }
357     // Clear possible previous states
358     iStoppedByUser = false;
359     iClosedByUser = false;
360
361     Q_ASSERT(!iConnection.SubSessionHandle());
362     TInt error = iConnection.Open(iSocketServ);
363     if (error != KErrNone) {
364         // Could not open RConnection
365         newState(QNetworkSession::Invalid);
366         iError = QNetworkSession::UnknownSessionError;
367         emit QNetworkSessionPrivate::error(iError);
368         syncStateWithInterface();    
369         return;
370     }
371     
372     // Use RConnection::ProgressNotification for IAP/SNAP monitoring
373     // (<=> ConnectionProgressNotifier uses RConnection::ProgressNotification)
374     if (!ipConnectionNotifier) {
375         ipConnectionNotifier = new ConnectionProgressNotifier(*this,iConnection);
376     }
377     if (ipConnectionNotifier) {
378         ipConnectionNotifier->StartNotifications();
379     }
380     
381     if (publicConfig.type() == QNetworkConfiguration::InternetAccessPoint) {
382             SymbianNetworkConfigurationPrivate *symbianConfig =
383                 toSymbianConfig(privateConfiguration(publicConfig));
384
385 #if defined(OCC_FUNCTIONALITY_AVAILABLE) && defined(SNAP_FUNCTIONALITY_AVAILABLE)
386             // With One Click Connectivity (Symbian^3 onwards) it is possible
387             // to connect silently, without any popups.
388             TConnPrefList pref;
389             TExtendedConnPref prefs;
390
391             prefs.SetIapId(symbianConfig->numericIdentifier());
392             if (iConnectInBackground) {
393                 prefs.SetNoteBehaviour( TExtendedConnPref::ENoteBehaviourConnSilent );
394             }
395             pref.AppendL(&prefs);
396 #else
397             TCommDbConnPref pref;
398             pref.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
399
400             pref.SetIapId(symbianConfig->numericIdentifier());
401 #endif
402             if (!ipConnectionStarter) {
403                 ipConnectionStarter = new ConnectionStarter(*this, iConnection);
404                 ipConnectionStarter->Start(pref);
405             }
406             // Avoid flip flop of states if the configuration is already
407             // active. IsOpen/opened() will indicate when ready.
408             if (state != QNetworkSession::Connected) {
409                 newState(QNetworkSession::Connecting);
410             }
411     } else if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) {
412         SymbianNetworkConfigurationPrivate *symbianConfig =
413             toSymbianConfig(privateConfiguration(publicConfig));
414
415 #if defined(OCC_FUNCTIONALITY_AVAILABLE) && defined(SNAP_FUNCTIONALITY_AVAILABLE)
416         // On Symbian^3 if service network is not reachable, it triggers a UI (aka EasyWLAN) where
417         // user can create new IAPs. To detect this, we need to store the number of IAPs
418         // there was before connection was started.
419         iKnownConfigsBeforeConnectionStart = engine->accessPointConfigurationIdentifiers();
420         TConnPrefList snapPref;
421         TExtendedConnPref prefs;
422         prefs.SetSnapId(symbianConfig->numericIdentifier());
423         if (iConnectInBackground) {
424             prefs.SetNoteBehaviour( TExtendedConnPref::ENoteBehaviourConnSilent );
425         }
426         snapPref.AppendL(&prefs);
427 #else
428         TConnSnapPref snapPref(symbianConfig->numericIdentifier());
429 #endif
430         if (!ipConnectionStarter) {
431             ipConnectionStarter = new ConnectionStarter(*this, iConnection);
432             ipConnectionStarter->Start(snapPref);
433         }
434         // Avoid flip flop of states if the configuration is already
435         // active. IsOpen/opened() will indicate when ready.
436         if (state != QNetworkSession::Connected) {
437             newState(QNetworkSession::Connecting);
438         }
439     } else if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
440         iKnownConfigsBeforeConnectionStart = engine->accessPointConfigurationIdentifiers();
441         if (!ipConnectionStarter) {
442             ipConnectionStarter = new ConnectionStarter(*this, iConnection);
443             ipConnectionStarter->Start();
444         }
445         newState(QNetworkSession::Connecting);
446     }
447  
448     if (error != KErrNone) {
449         isOpen = false;
450         isOpening = false;
451         iError = QNetworkSession::UnknownSessionError;
452         emit QNetworkSessionPrivate::error(iError);
453         closeHandles();
454         syncStateWithInterface();    
455     }
456 }
457
458 TUint QNetworkSessionPrivateImpl::iapClientCount(TUint aIAPId) const
459 {
460     TRequestStatus status;
461     TUint connectionCount;
462     if (!iConnectionMonitor.Handle())
463         return 0;
464     iConnectionMonitor.GetConnectionCount(connectionCount, status);
465     User::WaitForRequest(status);
466     if (status.Int() == KErrNone) {
467         for (TUint i = 1; i <= connectionCount; i++) {
468             TUint connectionId;
469             TUint subConnectionCount;
470             iConnectionMonitor.GetConnectionInfo(i, connectionId, subConnectionCount);
471             TUint apId;
472             iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status);
473             User::WaitForRequest(status);
474             if (apId == aIAPId) {
475                 TConnMonClientEnumBuf buf;
476                 iConnectionMonitor.GetPckgAttribute(connectionId, 0, KClientInfo, buf, status);
477                 User::WaitForRequest(status);
478                 if (status.Int() == KErrNone) {
479                     return buf().iCount;
480                 }
481             }
482         }
483     }
484     return 0;
485 }
486
487 void QNetworkSessionPrivateImpl::close(bool allowSignals)
488 {
489 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
490     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
491             << "close() called, session state is: " << state << " and isOpen is : "
492             << isOpen;
493 #endif
494
495     if (!isOpen && state != QNetworkSession::Connecting) {
496         return;
497     }
498     // Mark this session as closed-by-user so that we are able to report
499     // distinguish between stop() and close() state transitions
500     // when reporting.
501     iClosedByUser = true;
502     isOpen = false;
503     isOpening = false;
504
505     serviceConfig = QNetworkConfiguration();
506     
507     closeHandles();
508
509     // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate
510     iHandleStateNotificationsFromManager = true;
511
512     // If UserChoice, go down immediately. If some other configuration,
513     // go down immediately if there is no reports expected from the platform;
514     // in practice Connection Monitor is aware of connections only after
515     // KFinishedSelection event, and hence reports only after that event, but
516     // that does not seem to be trusted on all Symbian versions --> safest
517     // to go down.
518     if (publicConfig.type() == QNetworkConfiguration::UserChoice || state == QNetworkSession::Connecting) {
519 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
520         qDebug() << "QNS this : " << QString::number((uint)this) << " - "
521                  << "going disconnected right away, since either UserChoice or Connecting";
522 #endif
523         newState(QNetworkSession::Closing);
524         newState(QNetworkSession::Disconnected);
525     }
526     if (allowSignals) {
527         emit closed();
528     }
529 }
530
531 void QNetworkSessionPrivateImpl::stop()
532 {
533     QMutexLocker lock(&mutex);
534 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
535     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
536             << "stop() called, session state is: " << state << " and isOpen is : "
537             << isOpen;
538 #endif
539     if (!isOpen &&
540         publicConfig.isValid() &&
541         publicConfig.type() == QNetworkConfiguration::InternetAccessPoint &&
542         iConnectionMonitor.Handle()) {
543 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
544     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
545             << "since session is not open, using RConnectionMonitor to stop() the interface";
546 #endif
547         iStoppedByUser = true;
548         // If the publicConfig is type of IAP, enumerate through connections at
549         // connection monitor. If publicConfig is active in that list, stop it.
550         // Otherwise there is nothing to stop. Note: because this QNetworkSession is not open,
551         // activeConfig is not usable.
552         TUint count;
553         TRequestStatus status;
554         iConnectionMonitor.GetConnectionCount(count, status);
555         User::WaitForRequest(status);
556         if (status.Int() != KErrNone) {
557             return;
558         }
559         TUint numSubConnections; // Not used but needed by GetConnectionInfo i/f
560         TUint connectionId;
561         for (TUint i = 1; i <= count; ++i) {
562             // Get (connection monitor's assigned) connection ID
563             TInt ret = iConnectionMonitor.GetConnectionInfo(i, connectionId, numSubConnections);            
564             if (ret == KErrNone) {
565                 SymbianNetworkConfigurationPrivate *symbianConfig =
566                     toSymbianConfig(privateConfiguration(publicConfig));
567
568                 // See if connection Id matches with our Id. If so, stop() it.
569                 if (symbianConfig->connectionIdentifier() == connectionId) {
570                     ret = iConnectionMonitor.SetBoolAttribute(connectionId,
571                                                               0, // subConnectionId don't care
572                                                               KConnectionStop,
573                                                               ETrue);
574                 }
575             }
576             // Enter disconnected state right away since the session is not even open.
577             // Symbian^3 connection monitor does not emit KLinkLayerClosed when
578             // connection is stopped via connection monitor.
579             newState(QNetworkSession::Disconnected);
580         }
581     } else if (isOpen) {
582 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
583     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
584             << "since session is open, using RConnection to stop() the interface";
585 #endif
586         // Since we are open, use RConnection to stop the interface
587         isOpen = false;
588         isOpening = false;
589         iStoppedByUser = true;
590         newState(QNetworkSession::Closing);
591         if (ipConnectionNotifier) {
592             ipConnectionNotifier->StopNotifications();
593             // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate
594             iHandleStateNotificationsFromManager = true;
595         }
596         iConnection.Stop(RConnection::EStopAuthoritative);
597         isOpen = true;
598         isOpening = false;
599         close(false);
600         emit closed();
601     }
602 }
603
604 void QNetworkSessionPrivateImpl::migrate()
605 {
606 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
607     if (iMobility) {
608         QSymbianSocketManager::instance().setDefaultConnection(0);
609         // Start migrating to new IAP
610         iMobility->MigrateToPreferredCarrier();
611     }
612 #endif
613 }
614
615 void QNetworkSessionPrivateImpl::ignore()
616 {
617 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
618     if (iMobility) {
619         iMobility->IgnorePreferredCarrier();
620
621         if (!iALRUpgradingConnection) {
622             newState(QNetworkSession::Disconnected);
623         } else {
624             newState(QNetworkSession::Connected,iOldRoamingIap);
625         }
626     }
627 #endif
628 }
629
630 void QNetworkSessionPrivateImpl::accept()
631 {
632 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
633     if (iMobility) {
634         iMobility->NewCarrierAccepted();
635
636         QNetworkConfiguration newActiveConfig = activeConfiguration(iNewRoamingIap);
637
638         QSymbianSocketManager::instance().setDefaultConnection(&iConnection);
639
640         newState(QNetworkSession::Connected, iNewRoamingIap);
641     }
642 #endif
643 }
644
645 void QNetworkSessionPrivateImpl::reject()
646 {
647 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
648     if (iMobility) {
649         iMobility->NewCarrierRejected();
650
651         if (!iALRUpgradingConnection) {
652             newState(QNetworkSession::Disconnected);
653         } else {
654             QNetworkConfiguration newActiveConfig = activeConfiguration(iOldRoamingIap);
655
656             QSymbianSocketManager::instance().setDefaultConnection(&iConnection);
657
658             newState(QNetworkSession::Connected, iOldRoamingIap);
659         }
660     }
661 #endif
662 }
663
664 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
665 void QNetworkSessionPrivateImpl::PreferredCarrierAvailable(TAccessPointInfo aOldAPInfo,
666                                                        TAccessPointInfo aNewAPInfo,
667                                                        TBool aIsUpgrade,
668                                                        TBool aIsSeamless)
669 {
670     iOldRoamingIap = aOldAPInfo.AccessPoint();
671     iNewRoamingIap = aNewAPInfo.AccessPoint();
672     newState(QNetworkSession::Roaming);
673     if (iALREnabled > 0) {
674         iALRUpgradingConnection = aIsUpgrade;
675         QList<QNetworkConfiguration> configs = publicConfig.children();
676         for (int i=0; i < configs.count(); i++) {
677             SymbianNetworkConfigurationPrivate *symbianConfig =
678                 toSymbianConfig(privateConfiguration(configs[i]));
679
680             if (symbianConfig->numericIdentifier() == aNewAPInfo.AccessPoint()) {
681                 // Any slot connected to the signal might throw an std::exception,
682                 // which must not propagate into Symbian code (this function is a callback
683                 // from platform). We could convert exception to a symbian Leave, but since the
684                 // prototype of this function bans this (no trailing 'L'), we just catch
685                 // and drop.
686                 QT_TRY {
687                     emit preferredConfigurationChanged(configs[i], aIsSeamless);
688                 }
689                 QT_CATCH (std::exception&) {}
690             }
691         }
692     } else {
693         migrate();
694     }
695 }
696
697 void QNetworkSessionPrivateImpl::NewCarrierActive(TAccessPointInfo /*aNewAPInfo*/, TBool /*aIsSeamless*/)
698 {
699     if (iALREnabled > 0) {
700         QT_TRY {
701             emit newConfigurationActivated();
702         }
703         QT_CATCH (std::exception&) {}
704     } else {
705         accept();
706     }
707 }
708
709 void QNetworkSessionPrivateImpl::Error(TInt aError)
710 {
711 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
712     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
713             << "roaming Error() occurred" << aError << ", isOpen is: " << isOpen;
714 #endif
715     if (aError == KErrCancel)
716         return; //avoid recursive deletion
717     if (isOpen) {
718         isOpen = false;
719         isOpening = false;
720         activeConfig = QNetworkConfiguration();
721         serviceConfig = QNetworkConfiguration();
722         iError = QNetworkSession::RoamingError;
723         emit QNetworkSessionPrivate::error(iError);
724         closeHandles();
725         QT_TRY {
726             syncStateWithInterface();
727             // In some cases IAP is still in Connected state when
728             // syncStateWithInterface(); is called
729             // => Following call makes sure that Session state
730             //    changes immediately to Disconnected.
731             newState(QNetworkSession::Disconnected);
732             emit closed();
733         }
734         QT_CATCH (std::exception&) {}
735     } else if (iStoppedByUser) {
736         // If the user of this session has called the stop() and
737         // configuration is based on internet SNAP, this needs to be
738         // done here because platform might roam.
739         QT_TRY {
740             newState(QNetworkSession::Disconnected);
741         }
742         QT_CATCH (std::exception&) {}
743     }
744 }
745 #endif
746
747 void QNetworkSessionPrivateImpl::setALREnabled(bool enabled)
748 {
749     if (enabled) {
750         iALREnabled++;
751     } else {
752         iALREnabled--;
753     }
754 }
755
756 QNetworkConfiguration QNetworkSessionPrivateImpl::bestConfigFromSNAP(const QNetworkConfiguration& snapConfig) const
757 {
758     QNetworkConfiguration config;
759     QList<QNetworkConfiguration> subConfigurations = snapConfig.children();
760     for (int i = 0; i < subConfigurations.count(); i++ ) {
761         if (subConfigurations[i].state() == QNetworkConfiguration::Active) {
762             config = subConfigurations[i];
763             break;
764         } else if (!config.isValid() && subConfigurations[i].state() == QNetworkConfiguration::Discovered) {
765             config = subConfigurations[i];
766         }
767     }
768     if (!config.isValid() && subConfigurations.count() > 0) {
769         config = subConfigurations[0];
770     }
771     return config;
772 }
773
774 quint64 QNetworkSessionPrivateImpl::bytesWritten() const
775 {
776     return transferredData(KUplinkData);
777 }
778
779 quint64 QNetworkSessionPrivateImpl::bytesReceived() const
780 {
781     return transferredData(KDownlinkData);
782 }
783
784 quint64 QNetworkSessionPrivateImpl::transferredData(TUint dataType) const
785 {
786     if (!publicConfig.isValid()) {
787         return 0;
788     }
789     
790     QNetworkConfiguration config;
791     if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
792         if (serviceConfig.isValid()) {
793             config = serviceConfig;
794         } else {
795             if (activeConfig.isValid()) {
796                 config = activeConfig;
797             }
798         }
799     } else {
800         config = publicConfig;
801     }
802
803     if (!config.isValid()) {
804         return 0;
805     }
806     
807     if (!iConnectionMonitor.Handle())
808         return 0;
809     TUint count;
810     TRequestStatus status;
811     iConnectionMonitor.GetConnectionCount(count, status);
812     User::WaitForRequest(status);
813     if (status.Int() != KErrNone) {
814         return 0;
815     }
816     
817     TUint transferredData = 0;
818     TUint numSubConnections;
819     TUint connectionId;
820     bool configFound;
821     for (TUint i = 1; i <= count; i++) {
822         TInt ret = iConnectionMonitor.GetConnectionInfo(i, connectionId, numSubConnections);
823         if (ret == KErrNone) {
824             TUint apId;
825             iConnectionMonitor.GetUintAttribute(connectionId, 0, KIAPId, apId, status);
826             User::WaitForRequest(status);
827             if (status.Int() == KErrNone) {
828                 configFound = false;
829                 if (config.type() == QNetworkConfiguration::ServiceNetwork) {
830                     QList<QNetworkConfiguration> configs = config.children();
831                     for (int i=0; i < configs.count(); i++) {
832                         SymbianNetworkConfigurationPrivate *symbianConfig =
833                             toSymbianConfig(privateConfiguration(configs[i]));
834
835                         if (symbianConfig->numericIdentifier() == apId) {
836                             configFound = true;
837                             break;
838                         }
839                     }
840                 } else {
841                     SymbianNetworkConfigurationPrivate *symbianConfig =
842                         toSymbianConfig(privateConfiguration(config));
843
844                     if (symbianConfig->numericIdentifier() == apId)
845                         configFound = true;
846                 }
847                 if (configFound) {
848                     TUint tData;
849                     iConnectionMonitor.GetUintAttribute(connectionId, 0, dataType, tData, status );
850                     User::WaitForRequest(status);
851                     if (status.Int() == KErrNone) {
852                     transferredData += tData;
853                     }
854                 }
855             }
856         }
857     }
858     
859     return transferredData;
860 }
861
862 quint64 QNetworkSessionPrivateImpl::activeTime() const
863 {
864     if (!isOpen || startTime.isNull()) {
865         return 0;
866     }
867     return startTime.secsTo(QDateTime::currentDateTime());
868 }
869
870 QNetworkConfiguration QNetworkSessionPrivateImpl::activeConfiguration(TUint32 iapId) const
871 {
872     if (iapId == 0) {
873         _LIT(KSetting, "IAP\\Id");
874         iConnection.GetIntSetting(KSetting, iapId);
875 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
876         // Check if this is an Easy WLAN configuration. On Symbian^3 RConnection may report
877         // the used configuration as 'EasyWLAN' IAP ID if someone has just opened the configuration
878         // from WLAN Scan dialog, _and_ that connection is still up. We need to find the
879         // real matching configuration. Function alters the Easy WLAN ID to real IAP ID (only if
880         // easy WLAN):
881         easyWlanTrueIapId(iapId);
882 #endif
883     }
884
885 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
886     if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) {
887         // Try to search IAP from the used SNAP using IAP Id
888         QList<QNetworkConfiguration> children = publicConfig.children();
889         for (int i=0; i < children.count(); i++) {
890             SymbianNetworkConfigurationPrivate *childConfig =
891                 toSymbianConfig(privateConfiguration(children[i]));
892
893             if (childConfig->numericIdentifier() == iapId)
894                 return children[i];
895         }
896
897         // Given IAP Id was not found from the used SNAP
898         // => Try to search matching IAP using mappingName
899         //    mappingName contains:
900         //      1. "Access point name" for "Packet data" Bearer
901         //      2. "WLAN network name" (= SSID) for "Wireless LAN" Bearer
902         //      3. "Dial-up number" for "Data call Bearer" or "High Speed (GSM)" Bearer
903         //    <=> Note: It's possible that in this case reported IAP is
904         //              clone of the one of the IAPs of the used SNAP
905         //              => If mappingName matches, clone has been found
906         QNetworkConfiguration pt = QNetworkConfigurationManager().configurationFromIdentifier(
907                 QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId)));
908
909         SymbianNetworkConfigurationPrivate *symbianConfig =
910             toSymbianConfig(privateConfiguration(pt));
911         if (symbianConfig) {
912             for (int i=0; i < children.count(); i++) {
913                 SymbianNetworkConfigurationPrivate *childConfig =
914                     toSymbianConfig(privateConfiguration(children[i]));
915
916                 if (childConfig->configMappingName() == symbianConfig->configMappingName()) {
917                     return children[i];
918                 }
919             }
920         } else {
921 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
922             // On Symbian^3 (only, not earlier or Symbian^4) if the SNAP was not reachable, it
923             // triggers user choice type of activity (EasyWLAN). As a result, a new IAP may be
924             // created, and hence if was not found yet. Therefore update configurations and see if
925             // there is something new.
926
927             // 1. Update knowledge from the databases.
928             if (thread() != engine->thread())
929                 QMetaObject::invokeMethod(engine, "requestUpdate", Qt::BlockingQueuedConnection);
930             else
931                 engine->requestUpdate();
932
933             // 2. Check if new configuration was created during connection creation
934             QList<QString> knownConfigs = engine->accessPointConfigurationIdentifiers();
935 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
936             qDebug() << "QNS this : " << QString::number((uint)this) << " - "
937                     << "opened configuration was not known beforehand, looking for new.";
938 #endif
939             if (knownConfigs.count() > iKnownConfigsBeforeConnectionStart.count()) {
940                 // Configuration count increased => new configuration was created
941                 // => Search new, created configuration
942                 QString newIapId;
943                 for (int i=0; i < iKnownConfigsBeforeConnectionStart.count(); i++) {
944                     if (knownConfigs[i] != iKnownConfigsBeforeConnectionStart[i]) {
945                         newIapId = knownConfigs[i];
946                         break;
947                     }
948                 }
949                 if (newIapId.isEmpty()) {
950                     newIapId = knownConfigs[knownConfigs.count()-1];
951                 }
952                 pt = QNetworkConfigurationManager().configurationFromIdentifier(newIapId);
953                 if (pt.isValid()) {
954 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
955                     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
956                             << "new configuration was found, name, IAP id: " << pt.name() << pt.identifier();
957 #endif
958                     return pt;
959                 }
960             }
961 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
962             qDebug() << "QNS this : " << QString::number((uint)this) << " - "
963                     << "configuration was not found, returning invalid.";
964 #endif
965 #endif
966             // Given IAP Id was not found from known IAPs array
967             return QNetworkConfiguration();
968         }
969         // Matching IAP was not found from used SNAP
970         // => IAP from another SNAP is returned
971         //    (Note: Returned IAP matches to given IAP Id)
972         return pt;
973     }
974 #endif
975     if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
976         if (engine) {
977             QNetworkConfiguration pt = QNetworkConfigurationManager().configurationFromIdentifier(
978                     QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId)));
979             // Try to found User Selected IAP from known IAPs (accessPointConfigurations)
980             if (pt.isValid()) {
981                 return pt;
982             } else {
983                 // Check if new (WLAN) IAP was created in IAP/SNAP dialog
984                 // 1. Sync internal configurations array to commsdb first
985                 if (thread() != engine->thread()) {
986                     QMetaObject::invokeMethod(engine, "requestUpdate",
987                                               Qt::BlockingQueuedConnection);
988                 } else {
989                     engine->requestUpdate();
990                 }
991                 // 2. Check if new configuration was created during connection creation
992                 QStringList knownConfigs = engine->accessPointConfigurationIdentifiers();
993                 if (knownConfigs.count() > iKnownConfigsBeforeConnectionStart.count()) {
994                     // Configuration count increased => new configuration was created
995                     // => Search new, created configuration
996                     QString newIapId;
997                     for (int i=0; i < iKnownConfigsBeforeConnectionStart.count(); i++) {
998                         if (knownConfigs[i] != iKnownConfigsBeforeConnectionStart[i]) {
999                             newIapId = knownConfigs[i];
1000                             break;
1001                         }
1002                     }
1003                     if (newIapId.isEmpty()) {
1004                         newIapId = knownConfigs[knownConfigs.count()-1];
1005                     }
1006                     pt = QNetworkConfigurationManager().configurationFromIdentifier(newIapId);
1007                     if (pt.isValid())
1008                         return pt;
1009                 }
1010             }
1011         }
1012         return QNetworkConfiguration();
1013     }
1014
1015     return publicConfig;
1016 }
1017
1018 void QNetworkSessionPrivateImpl::ConnectionStartComplete(TInt statusCode)
1019 {
1020 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1021     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
1022             << "RConnection::Start completed with status code: " << statusCode;
1023 #endif
1024     delete ipConnectionStarter;
1025     ipConnectionStarter = 0;
1026
1027     switch (statusCode) {
1028         case KErrNone: // Connection created successfully
1029             {
1030             TInt error = KErrNone;
1031             QNetworkConfiguration newActiveConfig = activeConfiguration();
1032             if (!newActiveConfig.isValid()) {
1033                 // RConnection startup was successful but no configuration
1034                 // was found. That indicates that user has chosen to create a
1035                 // new WLAN configuration (from scan results), but that new
1036                 // configuration does not have access to Internet (Internet
1037                 // Connectivity Test, ICT, failed).
1038                 error = KErrGeneral;
1039             } else {
1040                 QSymbianSocketManager::instance().setDefaultConnection(&iConnection);
1041             }
1042             if (error != KErrNone) {
1043                 isOpen = false;
1044                 isOpening = false;
1045                 iError = QNetworkSession::UnknownSessionError;
1046                 QT_TRYCATCH_LEAVING(emit QNetworkSessionPrivate::error(iError));
1047                 closeHandles();
1048                 if (!newActiveConfig.isValid()) {
1049                     // No valid configuration, bail out.
1050                     // Status updates from QNCM won't be received correctly
1051                     // because there is no configuration to associate them with so transit here.
1052                     newState(QNetworkSession::Closing);
1053                     newState(QNetworkSession::Disconnected);
1054                 }
1055                 QT_TRYCATCH_LEAVING(syncStateWithInterface());
1056                 return;
1057             }
1058  
1059 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
1060             if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) {
1061                 // Activate ALR monitoring
1062                 iMobility = CActiveCommsMobilityApiExt::NewL(iConnection, *this);
1063             }
1064 #endif
1065
1066             isOpen = true;
1067             isOpening = false;
1068             activeConfig = newActiveConfig;
1069
1070             SymbianNetworkConfigurationPrivate *symbianConfig =
1071                 toSymbianConfig(privateConfiguration(activeConfig));
1072
1073 #ifndef QT_NO_NETWORKINTERFACE
1074             activeInterface = interface(symbianConfig->numericIdentifier());
1075 #endif
1076             if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
1077                 serviceConfig = QNetworkConfigurationManager()
1078                     .configurationFromIdentifier(activeConfig.identifier());
1079             }
1080
1081             startTime = QDateTime::currentDateTime();
1082
1083             QT_TRYCATCH_LEAVING({
1084                     newState(QNetworkSession::Connected);
1085                     emit quitPendingWaitsForOpened();
1086                 });
1087             }
1088             break;
1089         case KErrNotFound: // Connection failed
1090             isOpen = false;
1091             isOpening = false;
1092             activeConfig = QNetworkConfiguration();
1093             serviceConfig = QNetworkConfiguration();
1094             iError = QNetworkSession::InvalidConfigurationError;
1095             QT_TRYCATCH_LEAVING(emit QNetworkSessionPrivate::error(iError));
1096             closeHandles();
1097             QT_TRYCATCH_LEAVING(syncStateWithInterface());
1098             break;
1099         case KErrCancel: // Connection attempt cancelled
1100         case KErrAlreadyExists: // Connection already exists
1101         default:
1102             isOpen = false;
1103             isOpening = false;
1104             activeConfig = QNetworkConfiguration();
1105             serviceConfig = QNetworkConfiguration();
1106             if (statusCode == KErrCancel) {
1107                 iError = QNetworkSession::SessionAbortedError;
1108             } else if (publicConfig.state() == QNetworkConfiguration::Undefined ||
1109                 publicConfig.state() == QNetworkConfiguration::Defined) {
1110                 iError = QNetworkSession::InvalidConfigurationError;
1111             } else {
1112                 iError = QNetworkSession::UnknownSessionError;
1113             }
1114             QT_TRYCATCH_LEAVING(emit QNetworkSessionPrivate::error(iError));
1115             closeHandles();
1116             QT_TRYCATCH_LEAVING(syncStateWithInterface());
1117             break;
1118     }
1119 }
1120
1121 // Enters newState if feasible according to current state.
1122 // AccessPointId may be given as parameter. If it is zero, state-change is assumed to
1123 // concern this session's configuration. If non-zero, the configuration is looked up
1124 // and checked if it matches the configuration this session is based on.
1125 bool QNetworkSessionPrivateImpl::newState(QNetworkSession::State newState, TUint accessPointId)
1126 {
1127 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1128     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
1129              << "NEW STATE, IAP ID : " << QString::number(accessPointId) << " , newState : " << QString::number(newState);
1130 #endif
1131     // Make sure that activeConfig is always updated when SNAP is signaled to be
1132     // connected.
1133     if (isOpen && publicConfig.type() == QNetworkConfiguration::ServiceNetwork &&
1134         newState == QNetworkSession::Connected) {
1135         activeConfig = activeConfiguration(accessPointId);
1136
1137 #ifndef QT_NO_NETWORKINTERFACE
1138         SymbianNetworkConfigurationPrivate *symbianConfig =
1139             toSymbianConfig(privateConfiguration(activeConfig));
1140
1141         activeInterface = interface(symbianConfig->numericIdentifier());
1142 #endif
1143
1144 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
1145         QSymbianSocketManager::instance().setDefaultConnection(&iConnection);
1146 #endif
1147     }
1148
1149     // Make sure that same state is not signaled twice in a row.
1150     if (state == newState) {
1151         return true;
1152     }
1153
1154     // Make sure that Connecting state does not overwrite Roaming state
1155     if (state == QNetworkSession::Roaming && newState == QNetworkSession::Connecting) {
1156         return false;
1157     }
1158     
1159     // Make sure that Connected state is not reported when Connection is
1160     // already Closing.
1161     // Note: Stopping connection results sometimes KLinkLayerOpen
1162     //       to be reported first (just before KLinkLayerClosed).
1163     if (state == QNetworkSession::Closing && newState == QNetworkSession::Connected) {
1164         return false;
1165     }
1166
1167     // Make sure that some lagging 'closing' state-changes do not overwrite
1168     // if we are already disconnected or closed.
1169     if (state == QNetworkSession::Disconnected && newState == QNetworkSession::Closing) {
1170         return false;
1171     }
1172
1173     // Make sure that some lagging 'connecting' state-changes do not overwrite
1174     // if we are already connected (may righfully still happen with roaming though).
1175     if (state == QNetworkSession::Connected && newState == QNetworkSession::Connecting) {
1176         return false;
1177     }
1178
1179     bool emitSessionClosed = false;
1180
1181     // If we abruptly go down and user hasn't closed the session, we've been aborted.
1182     // Note that session may be in 'closing' state and not in 'connected' state, because
1183     // depending on platform the platform may report KConfigDaemonStartingDeregistration
1184     // event before KLinkLayerClosed
1185     if ((isOpen && state == QNetworkSession::Connected && newState == QNetworkSession::Disconnected) ||
1186         (isOpen && !iClosedByUser && newState == QNetworkSession::Disconnected)) {
1187         // Active & Connected state should change directly to Disconnected state
1188         // only when something forces connection to close (eg. when another
1189         // application or session stops connection or when network drops
1190         // unexpectedly).
1191         isOpen = false;
1192         isOpening = false;
1193         activeConfig = QNetworkConfiguration();
1194         serviceConfig = QNetworkConfiguration();
1195         iError = QNetworkSession::SessionAbortedError;
1196         emit QNetworkSessionPrivate::error(iError);
1197         closeHandles();
1198         // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate
1199         iHandleStateNotificationsFromManager = true;
1200         emitSessionClosed = true; // Emit SessionClosed after state change has been reported
1201     }
1202
1203     bool retVal = false;
1204     if (accessPointId == 0) {
1205         state = newState;
1206 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1207         qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed A to: " << state;
1208 #endif
1209         emit stateChanged(state);
1210         retVal = true;
1211     } else {
1212         if (publicConfig.type() == QNetworkConfiguration::InternetAccessPoint) {
1213             SymbianNetworkConfigurationPrivate *symbianConfig =
1214                 toSymbianConfig(privateConfiguration(publicConfig));
1215
1216             if (symbianConfig->numericIdentifier() == accessPointId) {
1217                 state = newState;
1218 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1219                 qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed B to: " << state;
1220 #endif
1221                 emit stateChanged(state);
1222                 retVal = true;
1223             }
1224         } else if (publicConfig.type() == QNetworkConfiguration::UserChoice && isOpen) {
1225             SymbianNetworkConfigurationPrivate *symbianConfig =
1226                 toSymbianConfig(privateConfiguration(activeConfig));
1227
1228             if (symbianConfig->numericIdentifier() == accessPointId) {
1229                 state = newState;
1230 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1231                 qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed C to: " << state;
1232 #endif
1233                 emit stateChanged(state);
1234                 retVal = true;
1235             }
1236         } else if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) {
1237             QList<QNetworkConfiguration> subConfigurations = publicConfig.children();
1238             for (int i = 0; i < subConfigurations.count(); i++) {
1239                 SymbianNetworkConfigurationPrivate *symbianConfig =
1240                     toSymbianConfig(privateConfiguration(subConfigurations[i]));
1241
1242                 if (symbianConfig->numericIdentifier() == accessPointId) {
1243                     if (newState != QNetworkSession::Disconnected) {
1244                         state = newState;
1245 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1246                         qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed D  to: " << state;
1247 #endif
1248                         emit stateChanged(state);
1249                         retVal = true;
1250                     } else {
1251                         QNetworkConfiguration config = bestConfigFromSNAP(publicConfig);
1252                         if ((config.state() == QNetworkConfiguration::Defined) ||
1253                             (config.state() == QNetworkConfiguration::Discovered)) {
1254                             activeConfig = QNetworkConfiguration();
1255                             state = newState;
1256 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1257                             qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed E  to: " << state;
1258 #endif
1259                             emit stateChanged(state);
1260                             retVal = true;
1261                         } else if (config.state() == QNetworkConfiguration::Active) {
1262                             // Connection to used IAP was closed, but there is another
1263                             // IAP that's active in used SNAP
1264                             // => Change state back to Connected
1265                             state =  QNetworkSession::Connected;
1266                             emit stateChanged(state);
1267                             retVal = true;
1268 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1269                             qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed F  to: " << state;
1270 #endif
1271                         }
1272                     }
1273                 }
1274             }
1275 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
1276             // If the retVal is not true here, it means that the status update may apply to an IAP outside of
1277             // SNAP (session is based on SNAP but follows IAP outside of it), which may occur on Symbian^3 EasyWlan.
1278             if (retVal == false && activeConfig.isValid() &&
1279                 toSymbianConfig(privateConfiguration(activeConfig))->numericIdentifier() == accessPointId) {
1280 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1281                 qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed G  to: " << state;
1282 #endif
1283                 if (newState == QNetworkSession::Disconnected) {
1284                     activeConfig = QNetworkConfiguration();
1285                 }
1286                 state = newState;
1287                 emit stateChanged(state);
1288                 retVal = true;
1289             }
1290 #endif
1291         }
1292     }
1293     if (emitSessionClosed) {
1294         emit closed();
1295     }
1296     if (state == QNetworkSession::Disconnected) {
1297         // Just in case clear activeConfiguration.
1298         activeConfig = QNetworkConfiguration();
1299     }
1300     return retVal;
1301 }
1302
1303 void QNetworkSessionPrivateImpl::handleSymbianConnectionStatusChange(TInt aConnectionStatus,
1304                                                                  TInt aError,
1305                                                                  TUint accessPointId)
1306 {
1307 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1308     qDebug() << "QNS this : " << QString::number((uint)this) << " - " << QString::number(accessPointId) << " , status : " << QString::number(aConnectionStatus);
1309 #endif
1310     switch (aConnectionStatus)
1311         {
1312         // Connection unitialised
1313         case KConnectionUninitialised:
1314             break;
1315
1316         // Starting connetion selection
1317         case KStartingSelection:
1318             break;
1319
1320         // Selection finished
1321         case KFinishedSelection:
1322             if (aError == KErrNone)
1323                 {
1324                 break;
1325                 }
1326             else
1327                 {
1328                 // The user pressed e.g. "Cancel" and did not select an IAP
1329                 newState(QNetworkSession::Disconnected,accessPointId);
1330                 }
1331             break;
1332
1333         // Connection failure
1334         case KConnectionFailure:
1335             newState(QNetworkSession::NotAvailable);
1336             break;
1337
1338         // Prepearing connection (e.g. dialing)
1339         case KPsdStartingConfiguration:
1340         case KPsdFinishedConfiguration:
1341         case KCsdFinishedDialling:
1342         case KCsdScanningScript:
1343         case KCsdGettingLoginInfo:
1344         case KCsdGotLoginInfo:
1345             break;
1346
1347         case KConfigDaemonStartingRegistration:
1348         // Creating connection (e.g. GPRS activation)
1349         case KCsdStartingConnect:
1350         case KCsdFinishedConnect:
1351             newState(QNetworkSession::Connecting,accessPointId);
1352             break;
1353
1354         // Starting log in
1355         case KCsdStartingLogIn:
1356             break;
1357
1358         // Finished login
1359         case KCsdFinishedLogIn:
1360             break;
1361
1362         // Connection open
1363         case KConnectionOpen:
1364             break;
1365
1366         case KLinkLayerOpen:
1367             newState(QNetworkSession::Connected,accessPointId);
1368             break;
1369
1370         // Connection blocked or suspended
1371         case KDataTransferTemporarilyBlocked:
1372             break;
1373
1374         case KConfigDaemonStartingDeregistration:
1375         // Hangup or GRPS deactivation
1376         case KConnectionStartingClose:
1377             newState(QNetworkSession::Closing,accessPointId);
1378             break;
1379
1380         // Connection closed
1381         case KConnectionClosed:
1382         case KLinkLayerClosed:
1383             newState(QNetworkSession::Disconnected,accessPointId);
1384             // Report manager about this to make sure this event
1385             // is received by all interseted parties (mediated by
1386             // manager because it does always receive all events from
1387             // connection monitor).
1388 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1389             qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "reporting disconnection to manager.";
1390 #endif
1391             if (publicConfig.isValid()) {
1392                 SymbianNetworkConfigurationPrivate *symbianConfig =
1393                     toSymbianConfig(privateConfiguration(publicConfig));
1394
1395                 engine->configurationStateChangeReport(symbianConfig->numericIdentifier(),
1396                                                        QNetworkSession::Disconnected);
1397             }
1398             break;
1399         // Unhandled state
1400         default:
1401             break;
1402         }
1403 }
1404
1405 #if defined(SNAP_FUNCTIONALITY_AVAILABLE)
1406 bool QNetworkSessionPrivateImpl::easyWlanTrueIapId(TUint32 &trueIapId) const
1407 {
1408     RCmManager iCmManager;
1409     TRAPD(err, iCmManager.OpenL());
1410     if (err != KErrNone)
1411         return false;
1412
1413     // Check if this is easy wlan id in the first place
1414     if (trueIapId != iCmManager.EasyWlanIdL()) {
1415         iCmManager.Close();
1416         return false;
1417     }
1418
1419     iCmManager.Close();
1420
1421     // Loop through all connections that connection monitor is aware
1422     // and check for IAPs based on easy WLAN
1423     if (!iConnectionMonitor.Handle())
1424         return false;
1425     TRequestStatus status;
1426     TUint connectionCount;
1427     iConnectionMonitor.GetConnectionCount(connectionCount, status);
1428     User::WaitForRequest(status);
1429     TUint connectionId;
1430     TUint subConnectionCount;
1431     TUint apId;
1432     if (status.Int() == KErrNone) {
1433         for (TUint i = 1; i <= connectionCount; i++) {
1434             iConnectionMonitor.GetConnectionInfo(i, connectionId, subConnectionCount);
1435             iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount,
1436                                                 KIAPId, apId, status);
1437             User::WaitForRequest(status);
1438             if (apId == trueIapId) {
1439                 TBuf<50>easyWlanNetworkName;
1440                 iConnectionMonitor.GetStringAttribute(connectionId, 0, KNetworkName,
1441                                                       easyWlanNetworkName, status);
1442                 User::WaitForRequest(status);
1443                 if (status.Int() != KErrNone)
1444                     continue;
1445
1446                 const QString ssid = QString::fromUtf16(easyWlanNetworkName.Ptr(),
1447                                                             easyWlanNetworkName.Length());
1448
1449                 QNetworkConfigurationPrivatePointer ptr = engine->configurationFromSsid(ssid);
1450                 if (ptr) {
1451 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1452                     qDebug() << "QNCM easyWlanTrueIapId(), found true IAP ID: "
1453                              << toSymbianConfig(ptr)->numericIdentifier();
1454 #endif
1455                     trueIapId = toSymbianConfig(ptr)->numericIdentifier();
1456                     return true;
1457                 }
1458             }
1459         }
1460     }
1461     return false;
1462 }
1463 #endif
1464
1465 RConnection* QNetworkSessionPrivateImpl::nativeSession()
1466 {
1467     return &iConnection;
1468 }
1469
1470 ConnectionProgressNotifier::ConnectionProgressNotifier(QNetworkSessionPrivateImpl& owner, RConnection& connection)
1471     : CActive(CActive::EPriorityUserInput), iOwner(owner), iConnection(connection)
1472 {
1473     CActiveScheduler::Add(this);
1474 }
1475
1476 ConnectionProgressNotifier::~ConnectionProgressNotifier()
1477 {
1478     Cancel();
1479 }
1480
1481 void ConnectionProgressNotifier::StartNotifications()
1482 {
1483     if (!IsActive()) {
1484         SetActive();
1485         iConnection.ProgressNotification(iProgress, iStatus);
1486     }
1487 }
1488
1489 void ConnectionProgressNotifier::StopNotifications()
1490 {
1491     Cancel();
1492 }
1493
1494 void ConnectionProgressNotifier::DoCancel()
1495 {
1496     iConnection.CancelProgressNotification();
1497 }
1498
1499 void ConnectionProgressNotifier::RunL()
1500 {
1501     if (iStatus == KErrNone) {
1502         SetActive();
1503         iConnection.ProgressNotification(iProgress, iStatus);
1504         // warning, this object may be deleted in the callback - do nothing after handleSymbianConnectionStatusChange
1505         QT_TRYCATCH_LEAVING(iOwner.handleSymbianConnectionStatusChange(iProgress().iStage, iProgress().iError));
1506     }
1507 }
1508
1509 ConnectionStarter::ConnectionStarter(QNetworkSessionPrivateImpl &owner, RConnection &connection)
1510     : CActive(CActive::EPriorityUserInput), iOwner(owner), iConnection(connection)
1511 {
1512     CActiveScheduler::Add(this);
1513 }
1514
1515 ConnectionStarter::~ConnectionStarter()
1516 {
1517     Cancel();
1518 }
1519
1520 void ConnectionStarter::Start()
1521 {
1522     if (!IsActive()) {
1523         iConnection.Start(iStatus);
1524         SetActive();
1525     }
1526 }
1527
1528 void ConnectionStarter::Start(TConnPref &pref)
1529 {
1530     if (!IsActive()) {
1531         iConnection.Start(pref, iStatus);
1532         SetActive();
1533     }
1534 }
1535
1536 void ConnectionStarter::RunL()
1537 {
1538     iOwner.ConnectionStartComplete(iStatus.Int());
1539     //note owner deletes on callback
1540 }
1541
1542 TInt ConnectionStarter::RunError(TInt err)
1543 {
1544     qWarning() << "ConnectionStarter::RunError" << err;
1545     return KErrNone;
1546 }
1547
1548 void ConnectionStarter::DoCancel()
1549 {
1550     iConnection.Close();
1551 }
1552
1553 QT_END_NAMESPACE
1554
1555 #endif //QT_NO_BEARERMANAGEMENT
1556