diff options
author | Morten Johan Sørvig <morten.sorvig@digia.com> | 2013-10-27 15:50:22 (GMT) |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-10-31 15:34:03 (GMT) |
commit | ef98098ef34581a473a885badea63d415bcf64f3 (patch) | |
tree | e6e071190484aafbb5211904572ccf763d356327 | |
parent | ab219c9594234356332351dd8b630d6963880b0f (diff) | |
download | Qt-ef98098ef34581a473a885badea63d415bcf64f3.zip Qt-ef98098ef34581a473a885badea63d415bcf64f3.tar.gz Qt-ef98098ef34581a473a885badea63d415bcf64f3.tar.bz2 |
Make QCoreWlan plugin compile on 10.9
Backport of 79ccb4fc from Qt 5:
We take the path of least resistence and keep the old API code for 10.6 while
updating the code for 10.7 and newer. This means we have some code duplication.
It also means that we only compile the 10.6 code for QCoreWlanEngine when the
deploymen target is 10.6.
The 10.6 version file should be removed once we drop support for Snow Leopard.
Change-Id: I07284a2579ba127abdca660ad4b8573576756399
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@digia.com>
-rw-r--r-- | src/plugins/bearer/corewlan/qcorewlanengine.mm | 270 | ||||
-rw-r--r-- | src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm | 916 |
2 files changed, 1009 insertions, 177 deletions
diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.mm b/src/plugins/bearer/corewlan/qcorewlanengine.mm index 92b2d28..b185809 100644 --- a/src/plugins/bearer/corewlan/qcorewlanengine.mm +++ b/src/plugins/bearer/corewlan/qcorewlanengine.mm @@ -52,29 +52,17 @@ #include <QtCore/qdebug.h> #include <QDir> -#include <CoreWLAN/CoreWLAN.h> -#include <CoreWLAN/CWInterface.h> -#include <CoreWLAN/CWNetwork.h> -#include <CoreWLAN/CWNetwork.h> -#include <CoreWLAN/CW8021XProfile.h> - -#include <Foundation/NSEnumerator.h> -#include <Foundation/NSKeyValueObserving.h> -#include <Foundation/NSAutoreleasePool.h> -#include <Foundation/NSLock.h> - -#include <SystemConfiguration/SCNetworkConfiguration.h> + +extern "C" { // Otherwise it won't find CWKeychain* symbols at link time +#import <CoreWLAN/CoreWLAN.h> +} + #include "private/qcore_mac_p.h" #include <net/if.h> #include <ifaddrs.h> -inline QString qt_NSStringToQString(const NSString *nsstr) -{ return QCFString::toQString(reinterpret_cast<const CFStringRef>(nsstr)); } - -inline NSString *qt_QStringToNSString(const QString &qstr) -{ return [const_cast<NSString *>(reinterpret_cast<const NSString *>(QCFString::toCFStringRef(qstr))) autorelease]; } - +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 @interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject { @@ -86,6 +74,7 @@ inline NSString *qt_QStringToNSString(const QString &qstr) - (void)notificationHandler;//:(NSNotification *)notification; - (void)remove; - (void)setEngine:(QCoreWlanEngine *)coreEngine; +- (QCoreWlanEngine *)engine; - (void)dealloc; @property (assign) QCoreWlanEngine* engine; @@ -93,7 +82,6 @@ inline NSString *qt_QStringToNSString(const QString &qstr) @end @implementation QT_MANGLE_NAMESPACE(QNSListener) -@synthesize engine; - (id) init { @@ -101,7 +89,7 @@ inline NSString *qt_QStringToNSString(const QString &qstr) NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; notificationCenter = [NSNotificationCenter defaultCenter]; currentInterface = [CWInterface interfaceWithName:nil]; - [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:kCWPowerDidChangeNotification object:nil]; + [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:CWPowerDidChangeNotification object:nil]; [locker unlock]; [autoreleasepool release]; return self; @@ -120,6 +108,11 @@ inline NSString *qt_QStringToNSString(const QString &qstr) [locker unlock]; } +-(QCoreWlanEngine *)engine +{ + return engine; +} + -(void)remove { [locker lock]; @@ -133,7 +126,7 @@ inline NSString *qt_QStringToNSString(const QString &qstr) } @end -QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; +static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; QT_BEGIN_NAMESPACE @@ -170,36 +163,28 @@ void QScanThread::run() NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; QStringList found; mutex.lock(); - CWInterface *currentInterface = [CWInterface interfaceWithName:qt_QStringToNSString(interfaceName)]; + CWInterface *currentInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceName)]; mutex.unlock(); - if([currentInterface power]) { + if (currentInterface.powerOn) { NSError *err = nil; - NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:YES], kCWScanKeyMerge, - [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, - [NSNumber numberWithInteger:100], kCWScanKeyRestTime, nil]; - NSArray* apArray = [currentInterface scanForNetworksWithParameters:parametersDict error:&err]; - CWNetwork *apNetwork; + NSSet* apSet = [currentInterface scanForNetworksWithName:nil error:&err]; if (!err) { - - for(uint row=0; row < [apArray count]; row++ ) { - apNetwork = [apArray objectAtIndex:row]; - - const QString networkSsid = qt_NSStringToQString([apNetwork ssid]); + for (CWNetwork *apNetwork in apSet) { + const QString networkSsid = QCFString::toQString(CFStringRef([apNetwork ssid])); const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); found.append(id); QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; bool known = isKnownSsid(networkSsid); - if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { - if( networkSsid == qt_NSStringToQString( [currentInterface ssid])) { + if (currentInterface.serviceActive) { + if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) { state = QNetworkConfiguration::Active; } } - if(state == QNetworkConfiguration::Undefined) { + if (state == QNetworkConfiguration::Undefined) { if(known) { state = QNetworkConfiguration::Discovered; } else { @@ -207,7 +192,7 @@ void QScanThread::run() } } QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose; - if([[apNetwork securityMode] intValue] == kCWSecurityModeOpen) { + if ([apNetwork supportsSecurity:kCWSecurityNone]) { purpose = QNetworkConfiguration::PublicPurpose; } else { purpose = QNetworkConfiguration::PrivatePurpose; @@ -237,8 +222,8 @@ void QScanThread::run() interfaceName = ij.value(); } - if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { - if( networkSsid == qt_NSStringToQString([currentInterface ssid])) { + if (currentInterface.serviceActive) { + if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) { state = QNetworkConfiguration::Active; } } @@ -300,14 +285,14 @@ void QScanThread::getUserConfigurations() NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; userProfiles.clear(); - NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; - for(uint row=0; row < [wifiInterfaces count]; row++ ) { + NSSet *wifiInterfaces = [CWInterface interfaceNames]; + for (NSString *ifName in wifiInterfaces) { - CWInterface *wifiInterface = [CWInterface interfaceWithName: [wifiInterfaces objectAtIndex:row]]; - if ( ![wifiInterface power] ) + CWInterface *wifiInterface = [CWInterface interfaceWithName: ifName]; + if (!wifiInterface.powerOn) continue; - NSString *nsInterfaceName = [wifiInterface name]; + NSString *nsInterfaceName = wifiInterface.ssid; // add user configured system networks SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil); NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]); @@ -316,11 +301,11 @@ void QScanThread::getUserConfigurations() NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"]; NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"]; - for(NSString *ssidkey in thisSsidarray) { - QString thisSsid = qt_NSStringToQString(ssidkey); + for (NSString *ssidkey in thisSsidarray) { + QString thisSsid = QCFString::toQString(CFStringRef(ssidkey)); if(!userProfiles.contains(thisSsid)) { QMap <QString,QString> map; - map.insert(thisSsid, qt_NSStringToQString(nsInterfaceName)); + map.insert(thisSsid, QCFString::toQString(CFStringRef(nsInterfaceName))); userProfiles.insert(thisSsid, map); } } @@ -329,7 +314,7 @@ void QScanThread::getUserConfigurations() // 802.1X user profiles QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist"; - NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile:qt_QStringToNSString(userProfilePath)] autorelease]; + NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile: (NSString *)QCFString::toCFStringRef(userProfilePath)] autorelease]; if(eapDict != nil) { NSString *profileStr= @"Profiles"; NSString *nameStr = @"UserDefinedName"; @@ -348,15 +333,15 @@ void QScanThread::getUserConfigurations() QString ssid; for(int i = 0; i < dictSize; i++) { if([nameStr isEqualToString:keys[i]]) { - networkName = qt_NSStringToQString(objects[i]); + networkName = QCFString::toQString(CFStringRef(objects[i])); } if([networkSsidStr isEqualToString:keys[i]]) { - ssid = qt_NSStringToQString(objects[i]); + ssid = QCFString::toQString(CFStringRef(objects[i])); } if(!userProfiles.contains(networkName) && !ssid.isEmpty()) { QMap<QString,QString> map; - map.insert(ssid, qt_NSStringToQString(nsInterfaceName)); + map.insert(ssid, QCFString::toQString(CFStringRef(nsInterfaceName))); userProfiles.insert(networkName, map); } } @@ -444,7 +429,7 @@ void QCoreWlanEngine::initialize() QMutexLocker locker(&mutex); NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; - if([[CWInterface supportedInterfaces] count] > 0 && !listener) { + if ([[CWInterface interfaceNames] count] > 0 && !listener) { listener = [[QT_MANGLE_NAMESPACE(QNSListener) alloc] init]; listener.engine = this; hasWifi = true; @@ -479,141 +464,68 @@ void QCoreWlanEngine::connectToId(const QString &id) QString interfaceString = getInterfaceFromId(id); CWInterface *wifiInterface = - [CWInterface interfaceWithName: qt_QStringToNSString(interfaceString)]; + [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)]; - if ([wifiInterface power]) { + if (wifiInterface.powerOn) { NSError *err = nil; - NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0]; - QString wantedSsid; - QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name)); const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name))); - bool using8021X = false; - if (idHash2 != id) { - NSArray *array = [CW8021XProfile allUser8021XProfiles]; - - for (NSUInteger i = 0; i < [array count]; ++i) { - const QString networkNameHashCheck = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString([[array objectAtIndex:i] userDefinedName]))); - - const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString([[array objectAtIndex:i] ssid]))); - - if (id == networkNameHashCheck || id == ssidHash) { - const QString thisName = scanThread->getSsidFromNetworkName(id); - if (thisName.isEmpty()) - wantedSsid = id; - else - wantedSsid = thisName; - - [params setValue: [array objectAtIndex:i] forKey:kCWAssocKey8021XProfile]; - using8021X = true; - break; - } + QString wantedNetwork; + QMapIterator<QString, QMap<QString, QString> > i(scanThread->userProfiles); + while (i.hasNext()) { + i.next(); + wantedNetwork = i.key(); + const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork)); + if (id == networkNameHash) { + wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); + break; } } - if (!using8021X) { - QString wantedNetwork; - QMapIterator<QString, QMap<QString,QString> > i(scanThread->userProfiles); - while (i.hasNext()) { - i.next(); - wantedNetwork = i.key(); - const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork)); - if (id == networkNameHash) { - wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); - break; - } - } - } - NSDictionary *scanParameters = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:YES], kCWScanKeyMerge, - [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, - [NSNumber numberWithInteger:100], kCWScanKeyRestTime, - qt_QStringToNSString(wantedSsid), kCWScanKeySSID, - nil]; - - NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:scanParameters error:&err]; + NSSet *scanSet = [wifiInterface scanForNetworksWithName:(NSString *)QCFString::toCFStringRef(wantedSsid) error:&err]; if(!err) { - for(uint row=0; row < [scanArray count]; row++ ) { - CWNetwork *apNetwork = [scanArray objectAtIndex:row]; - - if(wantedSsid == qt_NSStringToQString([apNetwork ssid])) { - - if(!using8021X) { - SecKeychainAttribute attributes[3]; - - NSString *account = [apNetwork ssid]; - NSString *keyKind = @"AirPort network password"; - NSString *keyName = account; - - attributes[0].tag = kSecAccountItemAttr; - attributes[0].data = (void *)[account UTF8String]; - attributes[0].length = [account length]; - - attributes[1].tag = kSecDescriptionItemAttr; - attributes[1].data = (void *)[keyKind UTF8String]; - attributes[1].length = [keyKind length]; - - attributes[2].tag = kSecLabelItemAttr; - attributes[2].data = (void *)[keyName UTF8String]; - attributes[2].length = [keyName length]; - - SecKeychainAttributeList attributeList = {3,attributes}; - - SecKeychainSearchRef searchRef; - SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef); - - NSString *password = @""; - SecKeychainItemRef searchItem; - - if (SecKeychainSearchCopyNext(searchRef, &searchItem) == noErr) { - UInt32 realPasswordLength; - SecKeychainAttribute attributesW[8]; - attributesW[0].tag = kSecAccountItemAttr; - SecKeychainAttributeList listW = {1,attributesW}; - char *realPassword; - OSStatus status = SecKeychainItemCopyContent(searchItem, NULL, &listW, &realPasswordLength,(void **)&realPassword); - - if (status == noErr) { - if (realPassword != NULL) { - - QByteArray pBuf; - pBuf.resize(realPasswordLength); - pBuf.prepend(realPassword); - pBuf.insert(realPasswordLength,'\0'); - - password = [NSString stringWithUTF8String:pBuf]; - } - SecKeychainItemFreeContent(&listW, realPassword); - } - - CFRelease(searchItem); - } else { - qDebug() << "SecKeychainSearchCopyNext error"; - } - [params setValue: password forKey: kCWAssocKeyPassphrase]; - } // end using8021X - - - bool result = [wifiInterface associateToNetwork: apNetwork parameters:[NSDictionary dictionaryWithDictionary:params] error:&err]; + for (CWNetwork *apNetwork in scanSet) { + CFDataRef ssidData = (CFDataRef)[apNetwork ssidData]; + bool result = false; + + SecIdentityRef identity = 0; + // Check first whether we require IEEE 802.1X authentication for the wanted SSID + if (CWKeychainCopyEAPIdentity(ssidData, &identity) == errSecSuccess) { + CFStringRef username = 0; + CFStringRef password = 0; + if (CWKeychainCopyEAPUsernameAndPassword(ssidData, &username, &password) == errSecSuccess) { + result = [wifiInterface associateToEnterpriseNetwork:apNetwork + identity:identity username:(NSString *)username password:(NSString *)password + error:&err]; + CFRelease(username); + CFRelease(password); + } + CFRelease(identity); + } else { + CFStringRef password = 0; + if (CWKeychainCopyPassword(ssidData, &password) == errSecSuccess) { + result = [wifiInterface associateToNetwork:apNetwork password:(NSString *)password error:&err]; + CFRelease(password); + } + } - if(!err) { - if(!result) { - emit connectionError(id, ConnectError); - } else { - return; - } + if (!err) { + if (!result) { + emit connectionError(id, ConnectError); } else { - qDebug() <<"associate ERROR"<< qt_NSStringToQString([err localizedDescription ]); + return; } + } else { + qDebug() <<"associate ERROR"<< QCFString::toQString(CFStringRef([err localizedDescription ])); } } //end scan network } else { - qDebug() <<"scan ERROR"<< qt_NSStringToQString([err localizedDescription ]); + qDebug() <<"scan ERROR"<< QCFString::toQString(CFStringRef([err localizedDescription ])); } emit connectionError(id, InterfaceLookupError); } @@ -631,10 +543,10 @@ void QCoreWlanEngine::disconnectFromId(const QString &id) NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; CWInterface *wifiInterface = - [CWInterface interfaceWithName: qt_QStringToNSString(interfaceString)]; + [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)]; [wifiInterface disassociate]; - if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) { + if (wifiInterface.serviceActive) { locker.unlock(); emit connectionError(id, DisconnectionError); locker.relock(); @@ -654,9 +566,9 @@ void QCoreWlanEngine::doRequestUpdate() NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; - NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; - for (uint row = 0; row < [wifiInterfaces count]; ++row) { - scanThread->interfaceName = qt_NSStringToQString([wifiInterfaces objectAtIndex:row]); + NSSet *wifiInterfaces = [CWInterface interfaceNames]; + for (NSString *ifName in wifiInterfaces) { + scanThread->interfaceName = QCFString::toQString(CFStringRef(ifName)); scanThread->start(); } locker.unlock(); @@ -669,8 +581,8 @@ bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) bool haswifi = false; if(hasWifi) { NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; - CWInterface *defaultInterface = [CWInterface interfaceWithName: qt_QStringToNSString(wifiDeviceName)]; - if([defaultInterface power]) { + CWInterface *defaultInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(wifiDeviceName)]; + if (defaultInterface.powerOn) { haswifi = true; } [autoreleasepool release]; @@ -898,7 +810,7 @@ quint64 QCoreWlanEngine::startTime(const QString &identifier) bool ok = false; for(int i = 0; i < dictSize; i++) { if([ssidStr isEqualToString:keys[i]]) { - const QString ident = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString(objects[i]))); + const QString ident = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef(objects[i])))); if(ident == identifier) { ok = true; } @@ -944,3 +856,7 @@ quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b) } QT_END_NAMESPACE + +#else // QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE +#include "qcorewlanengine_10_6.mm" +#endif diff --git a/src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm b/src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm new file mode 100644 index 0000000..a3bf615 --- /dev/null +++ b/src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm @@ -0,0 +1,916 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <SystemConfiguration/SCNetworkConfiguration.h> + +@interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject +{ + NSNotificationCenter *notificationCenter; + CWInterface *currentInterface; + QCoreWlanEngine *engine; + NSLock *locker; +} +- (void)notificationHandler;//:(NSNotification *)notification; +- (void)remove; +- (void)setEngine:(QCoreWlanEngine *)coreEngine; +- (QCoreWlanEngine *)engine; +- (void)dealloc; + +@property (assign) QCoreWlanEngine* engine; + +@end + +@implementation QT_MANGLE_NAMESPACE(QNSListener) + +- (id) init +{ + [locker lock]; + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + notificationCenter = [NSNotificationCenter defaultCenter]; + currentInterface = [CWInterface interfaceWithName:nil]; + [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:kCWPowerDidChangeNotification object:nil]; + [locker unlock]; + [autoreleasepool release]; + return self; +} + +-(void)dealloc +{ + [super dealloc]; +} + +-(void)setEngine:(QCoreWlanEngine *)coreEngine +{ + [locker lock]; + if(!engine) + engine = coreEngine; + [locker unlock]; +} + +-(QCoreWlanEngine *)engine +{ + return engine; +} + +-(void)remove +{ + [locker lock]; + [notificationCenter removeObserver:self]; + [locker unlock]; +} + +- (void)notificationHandler//:(NSNotification *)notification +{ + engine->requestUpdate(); +} +@end + +static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; + +QT_BEGIN_NAMESPACE + +void networkChangeCallback(SCDynamicStoreRef/* store*/, CFArrayRef changedKeys, void *info) +{ + for ( long i = 0; i < CFArrayGetCount(changedKeys); i++) { + + QString changed = QCFString::toQString(CFStringRef((CFStringRef)CFArrayGetValueAtIndex(changedKeys, i))); + if( changed.contains("/Network/Global/IPv4")) { + QCoreWlanEngine* wlanEngine = static_cast<QCoreWlanEngine*>(info); + wlanEngine->requestUpdate(); + } + } + return; +} + + +QScanThread::QScanThread(QObject *parent) + :QThread(parent) +{ +} + +QScanThread::~QScanThread() +{ +} + +void QScanThread::quit() +{ + wait(); +} + +void QScanThread::run() +{ + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + QStringList found; + mutex.lock(); + CWInterface *currentInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceName)]; + mutex.unlock(); + + if([currentInterface power]) { + NSError *err = nil; + NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], kCWScanKeyMerge, + [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, + [NSNumber numberWithInteger:100], kCWScanKeyRestTime, nil]; + + NSArray* apArray = [currentInterface scanForNetworksWithParameters:parametersDict error:&err]; + CWNetwork *apNetwork; + + if (!err) { + + for(uint row=0; row < [apArray count]; row++ ) { + apNetwork = [apArray objectAtIndex:row]; + + const QString networkSsid = QCFString::toQString(CFStringRef([apNetwork ssid])); + const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); + found.append(id); + + QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; + bool known = isKnownSsid(networkSsid); + if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { + if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) { + state = QNetworkConfiguration::Active; + } + } + if(state == QNetworkConfiguration::Undefined) { + if(known) { + state = QNetworkConfiguration::Discovered; + } else { + state = QNetworkConfiguration::Undefined; + } + } + QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose; + if([[apNetwork securityMode] intValue] == kCWSecurityModeOpen) { + purpose = QNetworkConfiguration::PublicPurpose; + } else { + purpose = QNetworkConfiguration::PrivatePurpose; + } + + found.append(foundNetwork(id, networkSsid, state, interfaceName, purpose)); + + } + } + } + // add known configurations that are not around. + QMapIterator<QString, QMap<QString,QString> > i(userProfiles); + while (i.hasNext()) { + i.next(); + + QString networkName = i.key(); + const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkName)); + + if(!found.contains(id)) { + QString networkSsid = getSsidFromNetworkName(networkName); + const QString ssidId = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); + QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; + QString interfaceName; + QMapIterator<QString, QString> ij(i.value()); + while (ij.hasNext()) { + ij.next(); + interfaceName = ij.value(); + } + + if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { + if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) { + state = QNetworkConfiguration::Active; + } + } + if(state == QNetworkConfiguration::Undefined) { + if( userProfiles.contains(networkName) + && found.contains(ssidId)) { + state = QNetworkConfiguration::Discovered; + } + } + + if(state == QNetworkConfiguration::Undefined) { + state = QNetworkConfiguration::Defined; + } + + found.append(foundNetwork(id, networkName, state, interfaceName, QNetworkConfiguration::UnknownPurpose)); + } + } + emit networksChanged(); + [autoreleasepool release]; +} + +QStringList QScanThread::foundNetwork(const QString &id, const QString &name, const QNetworkConfiguration::StateFlags state, const QString &interfaceName, const QNetworkConfiguration::Purpose purpose) +{ + QStringList found; + QMutexLocker locker(&mutex); + QNetworkConfigurationPrivate *ptr = new QNetworkConfigurationPrivate; + + ptr->name = name; + ptr->isValid = true; + ptr->id = id; + ptr->state = state; + ptr->type = QNetworkConfiguration::InternetAccessPoint; + ptr->bearerType = QNetworkConfiguration::BearerWLAN; + ptr->purpose = purpose; + + fetchedConfigurations.append( ptr); + configurationInterface.insert(ptr->id, interfaceName); + + locker.unlock(); + locker.relock(); + found.append(id); + return found; +} + +QList<QNetworkConfigurationPrivate *> QScanThread::getConfigurations() +{ + QMutexLocker locker(&mutex); + + QList<QNetworkConfigurationPrivate *> foundConfigurations = fetchedConfigurations; + fetchedConfigurations.clear(); + + return foundConfigurations; +} + +void QScanThread::getUserConfigurations() +{ + QMutexLocker locker(&mutex); + + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + userProfiles.clear(); + + NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; + for(uint row=0; row < [wifiInterfaces count]; row++ ) { + + CWInterface *wifiInterface = [CWInterface interfaceWithName: [wifiInterfaces objectAtIndex:row]]; + if ( ![wifiInterface power] ) + continue; + + NSString *nsInterfaceName = [wifiInterface name]; +// add user configured system networks + SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil); + NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]); + CFRelease(dynRef); + if(airportPlist != nil) { + NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"]; + + NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"]; + for(NSString *ssidkey in thisSsidarray) { + QString thisSsid = QCFString::toQString(CFStringRef(ssidkey)); + if(!userProfiles.contains(thisSsid)) { + QMap <QString,QString> map; + map.insert(thisSsid, QCFString::toQString(CFStringRef(nsInterfaceName))); + userProfiles.insert(thisSsid, map); + } + } + CFRelease(airportPlist); + } + + // 802.1X user profiles + QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist"; + NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile: (NSString *)QCFString::toCFStringRef(userProfilePath)] autorelease]; + if(eapDict != nil) { + NSString *profileStr= @"Profiles"; + NSString *nameStr = @"UserDefinedName"; + NSString *networkSsidStr = @"Wireless Network"; + for (id profileKey in eapDict) { + if ([profileStr isEqualToString:profileKey]) { + NSDictionary *itemDict = [eapDict objectForKey:profileKey]; + for (id itemKey in itemDict) { + + NSInteger dictSize = [itemKey count]; + id objects[dictSize]; + id keys[dictSize]; + + [itemKey getObjects:objects andKeys:keys]; + QString networkName; + QString ssid; + for(int i = 0; i < dictSize; i++) { + if([nameStr isEqualToString:keys[i]]) { + networkName = QCFString::toQString(CFStringRef(objects[i])); + } + if([networkSsidStr isEqualToString:keys[i]]) { + ssid = QCFString::toQString(CFStringRef(objects[i])); + } + if(!userProfiles.contains(networkName) + && !ssid.isEmpty()) { + QMap<QString,QString> map; + map.insert(ssid, QCFString::toQString(CFStringRef(nsInterfaceName))); + userProfiles.insert(networkName, map); + } + } + } + } + } + } + } + [autoreleasepool release]; +} + +QString QScanThread::getSsidFromNetworkName(const QString &name) +{ + QMutexLocker locker(&mutex); + + QMapIterator<QString, QMap<QString,QString> > i(userProfiles); + while (i.hasNext()) { + i.next(); + QMap<QString,QString> map = i.value(); + QMapIterator<QString, QString> ij(i.value()); + while (ij.hasNext()) { + ij.next(); + const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") +i.key())); + if(name == i.key() || name == networkNameHash) { + return ij.key(); + } + } + } + return QString(); +} + +QString QScanThread::getNetworkNameFromSsid(const QString &ssid) +{ + QMutexLocker locker(&mutex); + + QMapIterator<QString, QMap<QString,QString> > i(userProfiles); + while (i.hasNext()) { + i.next(); + QMap<QString,QString> map = i.value(); + QMapIterator<QString, QString> ij(i.value()); + while (ij.hasNext()) { + ij.next(); + if(ij.key() == ssid) { + return i.key(); + } + } + } + return QString(); +} + +bool QScanThread::isKnownSsid(const QString &ssid) +{ + QMutexLocker locker(&mutex); + + QMapIterator<QString, QMap<QString,QString> > i(userProfiles); + while (i.hasNext()) { + i.next(); + QMap<QString,QString> map = i.value(); + if(map.keys().contains(ssid)) { + return true; + } + } + return false; +} + + +QCoreWlanEngine::QCoreWlanEngine(QObject *parent) +: QBearerEngineImpl(parent), scanThread(0) +{ + scanThread = new QScanThread(this); + connect(scanThread, SIGNAL(networksChanged()), + this, SLOT(networksChanged())); +} + +QCoreWlanEngine::~QCoreWlanEngine() +{ + while (!foundConfigurations.isEmpty()) + delete foundConfigurations.takeFirst(); + [listener remove]; + [listener release]; +} + +void QCoreWlanEngine::initialize() +{ + QMutexLocker locker(&mutex); + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + + if([[CWInterface supportedInterfaces] count] > 0 && !listener) { + listener = [[QT_MANGLE_NAMESPACE(QNSListener) alloc] init]; + listener.engine = this; + hasWifi = true; + } else { + hasWifi = false; + } + storeSession = NULL; + + startNetworkChangeLoop(); + [autoreleasepool release]; +} + + +QString QCoreWlanEngine::getInterfaceFromId(const QString &id) +{ + QMutexLocker locker(&mutex); + + return scanThread->configurationInterface.value(id); +} + +bool QCoreWlanEngine::hasIdentifier(const QString &id) +{ + QMutexLocker locker(&mutex); + + return scanThread->configurationInterface.contains(id); +} + +void QCoreWlanEngine::connectToId(const QString &id) +{ + QMutexLocker locker(&mutex); + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + QString interfaceString = getInterfaceFromId(id); + + CWInterface *wifiInterface = + [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)]; + + if ([wifiInterface power]) { + NSError *err = nil; + NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0]; + + QString wantedSsid; + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name)); + const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name))); + + bool using8021X = false; + if (idHash2 != id) { + NSArray *array = [CW8021XProfile allUser8021XProfiles]; + + for (NSUInteger i = 0; i < [array count]; ++i) { + const QString networkNameHashCheck = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef([[array objectAtIndex:i] userDefinedName])))); + + const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef([[array objectAtIndex:i] ssid])))); + + if (id == networkNameHashCheck || id == ssidHash) { + const QString thisName = scanThread->getSsidFromNetworkName(id); + if (thisName.isEmpty()) + wantedSsid = id; + else + wantedSsid = thisName; + + [params setValue: [array objectAtIndex:i] forKey:kCWAssocKey8021XProfile]; + using8021X = true; + break; + } + } + } + + if (!using8021X) { + QString wantedNetwork; + QMapIterator<QString, QMap<QString,QString> > i(scanThread->userProfiles); + while (i.hasNext()) { + i.next(); + wantedNetwork = i.key(); + const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork)); + if (id == networkNameHash) { + wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); + break; + } + } + } + NSDictionary *scanParameters = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], kCWScanKeyMerge, + [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, + [NSNumber numberWithInteger:100], kCWScanKeyRestTime, + (NSString *)QCFString::toCFStringRef(wantedSsid), kCWScanKeySSID, + nil]; + + NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:scanParameters error:&err]; + + if(!err) { + for(uint row=0; row < [scanArray count]; row++ ) { + CWNetwork *apNetwork = [scanArray objectAtIndex:row]; + + if(wantedSsid == QCFString::toQString(CFStringRef([apNetwork ssid]))) { + + if(!using8021X) { + SecKeychainAttribute attributes[3]; + + NSString *account = [apNetwork ssid]; + NSString *keyKind = @"AirPort network password"; + NSString *keyName = account; + + attributes[0].tag = kSecAccountItemAttr; + attributes[0].data = (void *)[account UTF8String]; + attributes[0].length = [account length]; + + attributes[1].tag = kSecDescriptionItemAttr; + attributes[1].data = (void *)[keyKind UTF8String]; + attributes[1].length = [keyKind length]; + + attributes[2].tag = kSecLabelItemAttr; + attributes[2].data = (void *)[keyName UTF8String]; + attributes[2].length = [keyName length]; + + SecKeychainAttributeList attributeList = {3,attributes}; + + SecKeychainSearchRef searchRef; + SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef); + + NSString *password = @""; + SecKeychainItemRef searchItem; + + if (SecKeychainSearchCopyNext(searchRef, &searchItem) == noErr) { + UInt32 realPasswordLength; + SecKeychainAttribute attributesW[8]; + attributesW[0].tag = kSecAccountItemAttr; + SecKeychainAttributeList listW = {1,attributesW}; + char *realPassword; + OSStatus status = SecKeychainItemCopyContent(searchItem, NULL, &listW, &realPasswordLength,(void **)&realPassword); + + if (status == noErr) { + if (realPassword != NULL) { + + QByteArray pBuf; + pBuf.resize(realPasswordLength); + pBuf.prepend(realPassword); + pBuf.insert(realPasswordLength,'\0'); + + password = [NSString stringWithUTF8String:pBuf]; + } + SecKeychainItemFreeContent(&listW, realPassword); + } + + CFRelease(searchItem); + } else { + qDebug() << "SecKeychainSearchCopyNext error"; + } + [params setValue: password forKey: kCWAssocKeyPassphrase]; + } // end using8021X + + + bool result = [wifiInterface associateToNetwork: apNetwork parameters:[NSDictionary dictionaryWithDictionary:params] error:&err]; + + if(!err) { + if(!result) { + emit connectionError(id, ConnectError); + } else { + return; + } + } else { + qDebug() <<"associate ERROR"<< QCFString::toQString(CFStringRef([err localizedDescription ])); + } + } + } //end scan network + } else { + qDebug() <<"scan ERROR"<< QCFString::toQString(CFStringRef([err localizedDescription ])); + } + emit connectionError(id, InterfaceLookupError); + } + + locker.unlock(); + emit connectionError(id, InterfaceLookupError); + [autoreleasepool release]; +} + +void QCoreWlanEngine::disconnectFromId(const QString &id) +{ + QMutexLocker locker(&mutex); + + QString interfaceString = getInterfaceFromId(id); + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + + CWInterface *wifiInterface = + [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)]; + + [wifiInterface disassociate]; + if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) { + locker.unlock(); + emit connectionError(id, DisconnectionError); + locker.relock(); + } + [autoreleasepool release]; +} + +void QCoreWlanEngine::requestUpdate() +{ + scanThread->getUserConfigurations(); + doRequestUpdate(); +} + +void QCoreWlanEngine::doRequestUpdate() +{ + QMutexLocker locker(&mutex); + + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + + NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; + for (uint row = 0; row < [wifiInterfaces count]; ++row) { + scanThread->interfaceName = QCFString::toQString(CFStringRef([wifiInterfaces objectAtIndex:row])); + scanThread->start(); + } + locker.unlock(); + [autoreleasepool release]; +} + +bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) +{ + QMutexLocker locker(&mutex); + bool haswifi = false; + if(hasWifi) { + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + CWInterface *defaultInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(wifiDeviceName)]; + if([defaultInterface power]) { + haswifi = true; + } + [autoreleasepool release]; + } + return haswifi; +} + + +QNetworkSession::State QCoreWlanEngine::sessionStateForId(const QString &id) +{ + QMutexLocker locker(&mutex); + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + if (!ptr) + return QNetworkSession::Invalid; + + if (!ptr->isValid) { + return QNetworkSession::Invalid; + } else if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + return QNetworkSession::Connected; + } else if ((ptr->state & QNetworkConfiguration::Discovered) == + QNetworkConfiguration::Discovered) { + return QNetworkSession::Disconnected; + } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) { + return QNetworkSession::NotAvailable; + } else if ((ptr->state & QNetworkConfiguration::Undefined) == + QNetworkConfiguration::Undefined) { + return QNetworkSession::NotAvailable; + } + + return QNetworkSession::Invalid; +} + +QNetworkConfigurationManager::Capabilities QCoreWlanEngine::capabilities() const +{ + return QNetworkConfigurationManager::ForcedRoaming; +} + +void QCoreWlanEngine::startNetworkChangeLoop() +{ + + SCDynamicStoreContext dynStoreContext = { 0, this/*(void *)storeSession*/, NULL, NULL, NULL }; + storeSession = SCDynamicStoreCreate(NULL, + CFSTR("networkChangeCallback"), + networkChangeCallback, + &dynStoreContext); + if (!storeSession ) { + qWarning() << "could not open dynamic store: error:" << SCErrorString(SCError()); + return; + } + + CFMutableArrayRef notificationKeys; + notificationKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFMutableArrayRef patternsArray; + patternsArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + CFStringRef storeKey; + storeKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, + kSCDynamicStoreDomainState, + kSCEntNetIPv4); + CFArrayAppendValue(notificationKeys, storeKey); + CFRelease(storeKey); + + storeKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, + kSCDynamicStoreDomainState, + kSCCompAnyRegex, + kSCEntNetIPv4); + CFArrayAppendValue(patternsArray, storeKey); + CFRelease(storeKey); + + if (!SCDynamicStoreSetNotificationKeys(storeSession , notificationKeys, patternsArray)) { + qWarning() << "register notification error:"<< SCErrorString(SCError()); + CFRelease(storeSession ); + CFRelease(notificationKeys); + CFRelease(patternsArray); + return; + } + CFRelease(notificationKeys); + CFRelease(patternsArray); + + runloopSource = SCDynamicStoreCreateRunLoopSource(NULL, storeSession , 0); + if (!runloopSource) { + qWarning() << "runloop source error:"<< SCErrorString(SCError()); + CFRelease(storeSession ); + return; + } + + CFRunLoopAddSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode); + return; +} + +QNetworkSessionPrivate *QCoreWlanEngine::createSessionBackend() +{ + return new QNetworkSessionPrivateImpl; +} + +QNetworkConfigurationPrivatePointer QCoreWlanEngine::defaultConfiguration() +{ + return QNetworkConfigurationPrivatePointer(); +} + +bool QCoreWlanEngine::requiresPolling() const +{ + return true; +} + +void QCoreWlanEngine::networksChanged() +{ + QMutexLocker locker(&mutex); + + QStringList previous = accessPointConfigurations.keys(); + + QList<QNetworkConfigurationPrivate *> foundConfigurations = scanThread->getConfigurations(); + while (!foundConfigurations.isEmpty()) { + QNetworkConfigurationPrivate *cpPriv = foundConfigurations.takeFirst(); + + previous.removeAll(cpPriv->id); + + if (accessPointConfigurations.contains(cpPriv->id)) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(cpPriv->id); + + bool changed = false; + + ptr->mutex.lock(); + + if (ptr->isValid != cpPriv->isValid) { + ptr->isValid = cpPriv->isValid; + changed = true; + } + + if (ptr->name != cpPriv->name) { + ptr->name = cpPriv->name; + changed = true; + } + + if (ptr->bearerType != cpPriv->bearerType) { + ptr->bearerType = cpPriv->bearerType; + changed = true; + } + + if (ptr->state != cpPriv->state) { + ptr->state = cpPriv->state; + changed = true; + } + + ptr->mutex.unlock(); + + if (changed) { + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } + + delete cpPriv; + } else { + QNetworkConfigurationPrivatePointer ptr(cpPriv); + + accessPointConfigurations.insert(ptr->id, ptr); + + locker.unlock(); + emit configurationAdded(ptr); + locker.relock(); + } + } + + while (!previous.isEmpty()) { + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.take(previous.takeFirst()); + + locker.unlock(); + emit configurationRemoved(ptr); + locker.relock(); + } + + locker.unlock(); + emit updateCompleted(); + +} + +quint64 QCoreWlanEngine::bytesWritten(const QString &id) +{ + QMutexLocker locker(&mutex); + const QString interfaceStr = getInterfaceFromId(id); + return getBytes(interfaceStr,false); +} + +quint64 QCoreWlanEngine::bytesReceived(const QString &id) +{ + QMutexLocker locker(&mutex); + const QString interfaceStr = getInterfaceFromId(id); + return getBytes(interfaceStr,true); +} + +quint64 QCoreWlanEngine::startTime(const QString &identifier) +{ + QMutexLocker locker(&mutex); + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + quint64 timestamp = 0; + + NSString *filePath = @"/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist"; + NSDictionary* plistDict = [[[NSDictionary alloc] initWithContentsOfFile:filePath] autorelease]; + if(plistDict == nil) + return timestamp; + NSString *input = @"KnownNetworks"; + NSString *timeStampStr = @"_timeStamp"; + + NSString *ssidStr = @"SSID_STR"; + + for (id key in plistDict) { + if ([input isEqualToString:key]) { + + NSDictionary *knownNetworksDict = [plistDict objectForKey:key]; + if(knownNetworksDict == nil) + return timestamp; + for (id networkKey in knownNetworksDict) { + bool isFound = false; + NSDictionary *itemDict = [knownNetworksDict objectForKey:networkKey]; + if(itemDict == nil) + return timestamp; + NSInteger dictSize = [itemDict count]; + id objects[dictSize]; + id keys[dictSize]; + + [itemDict getObjects:objects andKeys:keys]; + bool ok = false; + for(int i = 0; i < dictSize; i++) { + if([ssidStr isEqualToString:keys[i]]) { + const QString ident = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef(objects[i])))); + if(ident == identifier) { + ok = true; + } + } + if(ok && [timeStampStr isEqualToString:keys[i]]) { + timestamp = (quint64)[objects[i] timeIntervalSince1970]; + isFound = true; + break; + } + } + if(isFound) + break; + } + } + } + [autoreleasepool release]; + return timestamp; +} + +quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b) +{ + struct ifaddrs *ifAddressList, *ifAddress; + struct if_data *if_data; + + quint64 bytes = 0; + ifAddressList = nil; + if(getifaddrs(&ifAddressList) == 0) { + for(ifAddress = ifAddressList; ifAddress; ifAddress = ifAddress->ifa_next) { + if(interfaceName == ifAddress->ifa_name) { + if_data = (struct if_data*)ifAddress->ifa_data; + if(b) { + bytes = if_data->ifi_ibytes; + break; + } else { + bytes = if_data->ifi_obytes; + break; + } + } + } + freeifaddrs(ifAddressList); + } + return bytes; +} + +QT_END_NAMESPACE |