diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-08-14 09:05:42 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-08-14 09:06:31 +0200 |
commit | 5c23199d4e8ff21661dfa5aacc13149178e78cab (patch) | |
tree | 322aee61581d7c85f1ccb65e47d1e79eba1ba6c9 /src/plugins/bearer | |
parent | 252bad7c589e03d3e12df02354b00a84d8e3159a (diff) | |
parent | c8d9b17367cfdcb034d11f8a168ca4ae3993e7c3 (diff) |
Merge remote-tracking branch 'origin/stable' into dev
Conflicts:
configure
mkspecs/macx-xcode/Info.plist.app
mkspecs/macx-xcode/Info.plist.lib
qmake/doc/qmake.qdocconf
src/corelib/global/qglobal.h
tests/auto/other/exceptionsafety/exceptionsafety.pro
tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
Change-Id: I3c769a4a82dc2e99a12c69123fbf17613fd2ac2a
Diffstat (limited to 'src/plugins/bearer')
-rw-r--r-- | src/plugins/bearer/corewlan/qcorewlanengine.mm | 228 | ||||
-rw-r--r-- | src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm | 916 |
2 files changed, 989 insertions, 155 deletions
diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.mm b/src/plugins/bearer/corewlan/qcorewlanengine.mm index 7549b4a9f7..b0ed4076da 100644 --- a/src/plugins/bearer/corewlan/qcorewlanengine.mm +++ b/src/plugins/bearer/corewlan/qcorewlanengine.mm @@ -52,23 +52,18 @@ #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> +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_NA) + @interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject { NSNotificationCenter *notificationCenter; @@ -94,7 +89,7 @@ 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; @@ -131,7 +126,7 @@ } @end -QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; +static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; QT_BEGIN_NAMESPACE @@ -171,33 +166,25 @@ void QScanThread::run() CWInterface *currentInterface = [CWInterface interfaceWithName: QCFString::toNSString(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]; - + for (CWNetwork *apNetwork in apSet) { const QString networkSsid = QCFString::toQString([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 (currentInterface.serviceActive) { if( networkSsid == QCFString::toQString( [currentInterface ssid])) { state = QNetworkConfiguration::Active; } } - if(state == QNetworkConfiguration::Undefined) { + if (state == QNetworkConfiguration::Undefined) { if(known) { state = QNetworkConfiguration::Discovered; } else { @@ -205,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; @@ -235,7 +222,7 @@ void QScanThread::run() interfaceName = ij.value(); } - if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { + if (currentInterface.serviceActive) { if( networkSsid == QCFString::toQString([currentInterface ssid])) { state = QNetworkConfiguration::Active; } @@ -298,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]); @@ -314,7 +301,7 @@ void QScanThread::getUserConfigurations() NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"]; NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"]; - for(NSString *ssidkey in thisSsidarray) { + for (NSString *ssidkey in thisSsidarray) { QString thisSsid = QCFString::toQString(ssidkey); if(!userProfiles.contains(thisSsid)) { QMap <QString,QString> map; @@ -442,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,135 +466,62 @@ void QCoreWlanEngine::connectToId(const QString &id) CWInterface *wifiInterface = [CWInterface interfaceWithName: QCFString::toNSString(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:") + QCFString::toQString([[array objectAtIndex:i] userDefinedName]))); - - const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString([[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, - QCFString::toNSString(wantedSsid), kCWScanKeySSID, - nil]; - - NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:scanParameters error:&err]; + NSSet *scanSet = [wifiInterface scanForNetworksWithName:QCFString::toNSString(wantedSsid) error:&err]; if(!err) { - for(uint row=0; row < [scanArray count]; row++ ) { - CWNetwork *apNetwork = [scanArray objectAtIndex:row]; - - if(wantedSsid == QCFString::toQString([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"<< QCFString::toQString([err localizedDescription ]); + return; } + } else { + qDebug() <<"associate ERROR"<< QCFString::toQString([err localizedDescription ]); } } //end scan network } else { @@ -632,7 +546,7 @@ void QCoreWlanEngine::disconnectFromId(const QString &id) [CWInterface interfaceWithName: QCFString::toNSString(interfaceString)]; [wifiInterface disassociate]; - if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) { + if (wifiInterface.serviceActive) { locker.unlock(); emit connectionError(id, DisconnectionError); locker.relock(); @@ -652,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 = QCFString::toQString([wifiInterfaces objectAtIndex:row]); + NSSet *wifiInterfaces = [CWInterface interfaceNames]; + for (NSString *ifName in wifiInterfaces) { + scanThread->interfaceName = QCFString::toQString(ifName); scanThread->start(); } locker.unlock(); @@ -668,7 +582,7 @@ bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) if(hasWifi) { NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; CWInterface *defaultInterface = [CWInterface interfaceWithName: QCFString::toNSString(wifiDeviceName)]; - if([defaultInterface power]) { + if (defaultInterface.powerOn) { haswifi = true; } [autoreleasepool release]; @@ -942,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 0000000000..1b95ae29ad --- /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)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: QCFString::toNSString(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([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( [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([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(ssidkey); + if(!userProfiles.contains(thisSsid)) { + QMap <QString,QString> map; + map.insert(thisSsid, QCFString::toQString(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: QCFString::toNSString(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(objects[i]); + } + if([networkSsidStr isEqualToString:keys[i]]) { + ssid = QCFString::toQString(objects[i]); + } + if(!userProfiles.contains(networkName) + && !ssid.isEmpty()) { + QMap<QString,QString> map; + map.insert(ssid, QCFString::toQString(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: QCFString::toNSString(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([[array objectAtIndex:i] userDefinedName]))); + + const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString([[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, + QCFString::toNSString(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([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([err localizedDescription ]); + } + } + } //end scan network + } else { + qDebug() <<"scan ERROR"<< QCFString::toQString([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: QCFString::toNSString(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([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: QCFString::toNSString(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(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 |