blob: 5be84581c2364656044463d0ed2ea5c60614e090 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia 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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qcorewlanengine.h"
#include "../qnetworksession_impl.h"
#include <QtNetwork/private/qnetworkconfiguration_p.h>
#include <QtCore/qthread.h>
#include <QtCore/qmutex.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qstringlist.h>
#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>
#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 [reinterpret_cast<const NSString *>(QCFString::toCFStringRef(qstr)) autorelease]; }
@interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject
{
NSNotificationCenter *notificationCenter;
CWInterface *currentInterface;
QCoreWlanEngine *engine;
NSLock *locker;
}
- (void)notificationHandler;//:(NSNotification *)notification;
- (void)remove;
- (void)setEngine:(QCoreWlanEngine *)coreEngine;
- (void)dealloc;
@property (assign) QCoreWlanEngine* engine;
@end
@implementation QT_MANGLE_NAMESPACE(QNSListener)
@synthesize engine;
- (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];
}
-(void)remove
{
[locker lock];
[notificationCenter removeObserver:self];
[locker unlock];
}
- (void)notificationHandler//:(NSNotification *)notification
{
engine->requestUpdate();
}
@end
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:qt_QStringToNSString(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 = qt_NSStringToQString([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])) {
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 == qt_NSStringToQString([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 = qt_NSStringToQString(ssidkey);
if(!userProfiles.contains(thisSsid)) {
QMap <QString,QString> map;
map.insert(thisSsid, qt_NSStringToQString(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:qt_QStringToNSString(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 = qt_NSStringToQString(objects[i]);
}
if([networkSsidStr isEqualToString:keys[i]]) {
ssid = qt_NSStringToQString(objects[i]);
}
if(!userProfiles.contains(networkName)
&& !ssid.isEmpty()) {
QMap<QString,QString> map;
map.insert(ssid, qt_NSStringToQString(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: qt_QStringToNSString(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:") + 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;
}
}
}
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];
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];
if(!err) {
if(!result) {
emit connectionError(id, ConnectError);
} else {
return;
}
} else {
qDebug() <<"associate ERROR"<< qt_NSStringToQString([err localizedDescription ]);
}
}
} //end scan network
} else {
qDebug() <<"scan ERROR"<< qt_NSStringToQString([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: qt_QStringToNSString(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 = qt_NSStringToQString([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: qt_QStringToNSString(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 &id)
{
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:") + qt_NSStringToQString(objects[i])));
if(ident == id) {
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