Ticket #40852: qt-project-fix-coreWLAN.diff

File qt-project-fix-coreWLAN.diff, 56.1 KB (added by michaelld (Michael Dickens), 7 years ago)
  • src/plugins/bearer/corewlan/qcorewlanengine.mm

    commit ef98098ef34581a473a885badea63d415bcf64f3
    Author: Morten Johan Sørvig <morten.sorvig@digia.com>
    Date:   Sun Oct 27 16:50:22 2013 +0100
    
        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>
    
    diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.mm b/src/plugins/bearer/corewlan/qcorewlanengine.mm
    index 92b2d28..b185809 100644
    a b  
    5252#include <QtCore/qdebug.h>
    5353
    5454#include <QDir>
    55 #include <CoreWLAN/CoreWLAN.h>
    56 #include <CoreWLAN/CWInterface.h>
    57 #include <CoreWLAN/CWNetwork.h>
    58 #include <CoreWLAN/CWNetwork.h>
    59 #include <CoreWLAN/CW8021XProfile.h>
    60 
    61 #include <Foundation/NSEnumerator.h>
    62 #include <Foundation/NSKeyValueObserving.h>
    63 #include <Foundation/NSAutoreleasePool.h>
    64 #include <Foundation/NSLock.h>
    65 
    66 #include <SystemConfiguration/SCNetworkConfiguration.h>
     55
     56extern "C" { // Otherwise it won't find CWKeychain* symbols at link time
     57#import <CoreWLAN/CoreWLAN.h>
     58}
     59
    6760#include "private/qcore_mac_p.h"
    6861
    6962#include <net/if.h>
    7063#include <ifaddrs.h>
    7164
    72 inline QString qt_NSStringToQString(const NSString *nsstr)
    73 { return QCFString::toQString(reinterpret_cast<const CFStringRef>(nsstr)); }
    74 
    75 inline NSString *qt_QStringToNSString(const QString &qstr)
    76 { return [const_cast<NSString *>(reinterpret_cast<const NSString *>(QCFString::toCFStringRef(qstr))) autorelease]; }
    77 
     65#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
    7866
    7967@interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject
    8068{
    inline NSString *qt_QStringToNSString(const QString &qstr) 
    8674- (void)notificationHandler;//:(NSNotification *)notification;
    8775- (void)remove;
    8876- (void)setEngine:(QCoreWlanEngine *)coreEngine;
     77- (QCoreWlanEngine *)engine;
    8978- (void)dealloc;
    9079
    9180@property (assign) QCoreWlanEngine* engine;
    inline NSString *qt_QStringToNSString(const QString &qstr) 
    9382@end
    9483
    9584@implementation QT_MANGLE_NAMESPACE(QNSListener)
    96 @synthesize engine;
    9785
    9886- (id) init
    9987{
    inline NSString *qt_QStringToNSString(const QString &qstr) 
    10189    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
    10290    notificationCenter = [NSNotificationCenter defaultCenter];
    10391    currentInterface = [CWInterface interfaceWithName:nil];
    104     [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:kCWPowerDidChangeNotification object:nil];
     92    [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:CWPowerDidChangeNotification object:nil];
    10593    [locker unlock];
    10694    [autoreleasepool release];
    10795    return self;
    inline NSString *qt_QStringToNSString(const QString &qstr) 
    120108    [locker unlock];
    121109}
    122110
     111-(QCoreWlanEngine *)engine
     112{
     113    return engine;
     114}
     115
    123116-(void)remove
    124117{
    125118    [locker lock];
    inline NSString *qt_QStringToNSString(const QString &qstr) 
    133126}
    134127@end
    135128
    136 QT_MANGLE_NAMESPACE(QNSListener) *listener = 0;
     129static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0;
    137130
    138131QT_BEGIN_NAMESPACE
    139132
    void QScanThread::run() 
    170163    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
    171164    QStringList found;
    172165    mutex.lock();
    173     CWInterface *currentInterface = [CWInterface interfaceWithName:qt_QStringToNSString(interfaceName)];
     166    CWInterface *currentInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceName)];
    174167    mutex.unlock();
    175168
    176     if([currentInterface power]) {
     169    if (currentInterface.powerOn) {
    177170        NSError *err = nil;
    178         NSDictionary *parametersDict =  [NSDictionary dictionaryWithObjectsAndKeys:
    179                                    [NSNumber numberWithBool:YES], kCWScanKeyMerge,
    180                                    [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType,
    181                                    [NSNumber numberWithInteger:100], kCWScanKeyRestTime, nil];
    182171
    183         NSArray* apArray = [currentInterface scanForNetworksWithParameters:parametersDict error:&err];
    184         CWNetwork *apNetwork;
     172        NSSet* apSet = [currentInterface scanForNetworksWithName:nil error:&err];
    185173
    186174        if (!err) {
    187 
    188             for(uint row=0; row < [apArray count]; row++ ) {
    189                 apNetwork = [apArray objectAtIndex:row];
    190 
    191                 const QString networkSsid = qt_NSStringToQString([apNetwork ssid]);
     175            for (CWNetwork *apNetwork in apSet) {
     176                const QString networkSsid = QCFString::toQString(CFStringRef([apNetwork ssid]));
    192177                const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid));
    193178                found.append(id);
    194179
    195180                QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined;
    196181                bool known = isKnownSsid(networkSsid);
    197                 if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) {
    198                     if( networkSsid == qt_NSStringToQString( [currentInterface ssid])) {
     182                if (currentInterface.serviceActive) {
     183                    if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) {
    199184                        state = QNetworkConfiguration::Active;
    200185                    }
    201186                }
    202                 if(state == QNetworkConfiguration::Undefined) {
     187                if (state == QNetworkConfiguration::Undefined) {
    203188                    if(known) {
    204189                        state = QNetworkConfiguration::Discovered;
    205190                    } else {
    void QScanThread::run() 
    207192                    }
    208193                }
    209194                QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose;
    210                 if([[apNetwork securityMode] intValue] == kCWSecurityModeOpen) {
     195                if ([apNetwork supportsSecurity:kCWSecurityNone]) {
    211196                    purpose = QNetworkConfiguration::PublicPurpose;
    212197                } else {
    213198                    purpose = QNetworkConfiguration::PrivatePurpose;
    void QScanThread::run() 
    237222                interfaceName = ij.value();
    238223            }
    239224
    240             if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) {
    241                 if( networkSsid == qt_NSStringToQString([currentInterface ssid])) {
     225            if (currentInterface.serviceActive) {
     226                if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) {
    242227                    state = QNetworkConfiguration::Active;
    243228                }
    244229            }
    void QScanThread::getUserConfigurations() 
    300285    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
    301286    userProfiles.clear();
    302287
    303     NSArray *wifiInterfaces = [CWInterface supportedInterfaces];
    304     for(uint row=0; row < [wifiInterfaces count]; row++ ) {
     288    NSSet *wifiInterfaces = [CWInterface interfaceNames];
     289    for (NSString *ifName in wifiInterfaces) {
    305290
    306         CWInterface *wifiInterface = [CWInterface interfaceWithName: [wifiInterfaces objectAtIndex:row]];
    307         if ( ![wifiInterface power] )
     291        CWInterface *wifiInterface = [CWInterface interfaceWithName: ifName];
     292        if (!wifiInterface.powerOn)
    308293            continue;
    309294
    310         NSString *nsInterfaceName = [wifiInterface name];
     295        NSString *nsInterfaceName = wifiInterface.ssid;
    311296// add user configured system networks
    312297        SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil);
    313298        NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]);
    void QScanThread::getUserConfigurations() 
    316301            NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"];
    317302
    318303            NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"];
    319             for(NSString *ssidkey in thisSsidarray) {
    320                 QString thisSsid = qt_NSStringToQString(ssidkey);
     304            for (NSString *ssidkey in thisSsidarray) {
     305                QString thisSsid = QCFString::toQString(CFStringRef(ssidkey));
    321306                if(!userProfiles.contains(thisSsid)) {
    322307                    QMap <QString,QString> map;
    323                     map.insert(thisSsid, qt_NSStringToQString(nsInterfaceName));
     308                    map.insert(thisSsid, QCFString::toQString(CFStringRef(nsInterfaceName)));
    324309                    userProfiles.insert(thisSsid, map);
    325310                }
    326311            }
    void QScanThread::getUserConfigurations() 
    329314
    330315        // 802.1X user profiles
    331316        QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist";
    332         NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile:qt_QStringToNSString(userProfilePath)] autorelease];
     317        NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile: (NSString *)QCFString::toCFStringRef(userProfilePath)] autorelease];
    333318        if(eapDict != nil) {
    334319            NSString *profileStr= @"Profiles";
    335320            NSString *nameStr = @"UserDefinedName";
    void QScanThread::getUserConfigurations() 
    348333                        QString ssid;
    349334                        for(int i = 0; i < dictSize; i++) {
    350335                            if([nameStr isEqualToString:keys[i]]) {
    351                                 networkName = qt_NSStringToQString(objects[i]);
     336                                networkName = QCFString::toQString(CFStringRef(objects[i]));
    352337                            }
    353338                            if([networkSsidStr isEqualToString:keys[i]]) {
    354                                 ssid = qt_NSStringToQString(objects[i]);
     339                                ssid = QCFString::toQString(CFStringRef(objects[i]));
    355340                            }
    356341                            if(!userProfiles.contains(networkName)
    357342                                && !ssid.isEmpty()) {
    358343                                QMap<QString,QString> map;
    359                                 map.insert(ssid, qt_NSStringToQString(nsInterfaceName));
     344                                map.insert(ssid, QCFString::toQString(CFStringRef(nsInterfaceName)));
    360345                                userProfiles.insert(networkName, map);
    361346                            }
    362347                        }
    void QCoreWlanEngine::initialize() 
    444429    QMutexLocker locker(&mutex);
    445430    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
    446431
    447     if([[CWInterface supportedInterfaces] count] > 0 && !listener) {
     432    if ([[CWInterface interfaceNames] count] > 0 && !listener) {
    448433        listener = [[QT_MANGLE_NAMESPACE(QNSListener) alloc] init];
    449434        listener.engine = this;
    450435        hasWifi = true;
    void QCoreWlanEngine::connectToId(const QString &id) 
    479464    QString interfaceString = getInterfaceFromId(id);
    480465
    481466    CWInterface *wifiInterface =
    482         [CWInterface interfaceWithName: qt_QStringToNSString(interfaceString)];
     467        [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)];
    483468
    484     if ([wifiInterface power]) {
     469    if (wifiInterface.powerOn) {
    485470        NSError *err = nil;
    486         NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
    487 
    488471        QString wantedSsid;
    489 
    490472        QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
    491473
    492474        const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name));
    493475        const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name)));
    494476
    495         bool using8021X = false;
    496         if (idHash2 != id) {
    497             NSArray *array = [CW8021XProfile allUser8021XProfiles];
    498 
    499             for (NSUInteger i = 0; i < [array count]; ++i) {
    500                 const QString networkNameHashCheck = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString([[array objectAtIndex:i] userDefinedName])));
    501 
    502                 const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString([[array objectAtIndex:i] ssid])));
    503 
    504                 if (id == networkNameHashCheck || id == ssidHash) {
    505                     const QString thisName = scanThread->getSsidFromNetworkName(id);
    506                     if (thisName.isEmpty())
    507                         wantedSsid = id;
    508                     else
    509                         wantedSsid = thisName;
    510 
    511                     [params setValue: [array objectAtIndex:i] forKey:kCWAssocKey8021XProfile];
    512                     using8021X = true;
    513                     break;
    514                 }
     477        QString wantedNetwork;
     478        QMapIterator<QString, QMap<QString, QString> > i(scanThread->userProfiles);
     479        while (i.hasNext()) {
     480            i.next();
     481            wantedNetwork = i.key();
     482            const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork));
     483            if (id == networkNameHash) {
     484                wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork);
     485                break;
    515486            }
    516487        }
    517488
    518         if (!using8021X) {
    519             QString wantedNetwork;
    520             QMapIterator<QString, QMap<QString,QString> > i(scanThread->userProfiles);
    521             while (i.hasNext()) {
    522                 i.next();
    523                 wantedNetwork = i.key();
    524                 const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork));
    525                 if (id == networkNameHash) {
    526                     wantedSsid =  scanThread->getSsidFromNetworkName(wantedNetwork);
    527                     break;
    528                 }
    529             }
    530         }
    531         NSDictionary *scanParameters = [NSDictionary dictionaryWithObjectsAndKeys:
    532                                         [NSNumber numberWithBool:YES], kCWScanKeyMerge,
    533                                         [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType,
    534                                         [NSNumber numberWithInteger:100], kCWScanKeyRestTime,
    535                                         qt_QStringToNSString(wantedSsid), kCWScanKeySSID,
    536                                         nil];
    537 
    538         NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:scanParameters error:&err];
     489        NSSet *scanSet = [wifiInterface scanForNetworksWithName:(NSString *)QCFString::toCFStringRef(wantedSsid) error:&err];
    539490
    540491        if(!err) {
    541             for(uint row=0; row < [scanArray count]; row++ ) {
    542                 CWNetwork *apNetwork = [scanArray objectAtIndex:row];
    543 
    544                 if(wantedSsid == qt_NSStringToQString([apNetwork ssid])) {
    545 
    546                     if(!using8021X) {
    547                         SecKeychainAttribute attributes[3];
    548 
    549                         NSString *account = [apNetwork ssid];
    550                         NSString *keyKind = @"AirPort network password";
    551                         NSString *keyName = account;
    552 
    553                         attributes[0].tag = kSecAccountItemAttr;
    554                         attributes[0].data = (void *)[account UTF8String];
    555                         attributes[0].length = [account length];
    556 
    557                         attributes[1].tag = kSecDescriptionItemAttr;
    558                         attributes[1].data = (void *)[keyKind UTF8String];
    559                         attributes[1].length = [keyKind length];
    560 
    561                         attributes[2].tag = kSecLabelItemAttr;
    562                         attributes[2].data = (void *)[keyName UTF8String];
    563                         attributes[2].length = [keyName length];
    564 
    565                         SecKeychainAttributeList attributeList = {3,attributes};
    566 
    567                         SecKeychainSearchRef searchRef;
    568                         SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef);
    569 
    570                         NSString *password = @"";
    571                         SecKeychainItemRef searchItem;
    572 
    573                         if (SecKeychainSearchCopyNext(searchRef, &searchItem) == noErr) {
    574                             UInt32 realPasswordLength;
    575                             SecKeychainAttribute attributesW[8];
    576                             attributesW[0].tag = kSecAccountItemAttr;
    577                             SecKeychainAttributeList listW = {1,attributesW};
    578                             char *realPassword;
    579                             OSStatus status = SecKeychainItemCopyContent(searchItem, NULL, &listW, &realPasswordLength,(void **)&realPassword);
    580 
    581                             if (status == noErr) {
    582                                 if (realPassword != NULL) {
    583 
    584                                     QByteArray pBuf;
    585                                     pBuf.resize(realPasswordLength);
    586                                     pBuf.prepend(realPassword);
    587                                     pBuf.insert(realPasswordLength,'\0');
    588 
    589                                     password = [NSString stringWithUTF8String:pBuf];
    590                                 }
    591                                 SecKeychainItemFreeContent(&listW, realPassword);
    592                             }
    593 
    594                             CFRelease(searchItem);
    595                         } else {
    596                             qDebug() << "SecKeychainSearchCopyNext error";
    597                         }
    598                         [params setValue: password forKey: kCWAssocKeyPassphrase];
    599                     } // end using8021X
    600 
    601 
    602                     bool result = [wifiInterface associateToNetwork: apNetwork parameters:[NSDictionary dictionaryWithDictionary:params] error:&err];
     492            for (CWNetwork *apNetwork in scanSet) {
     493                CFDataRef ssidData = (CFDataRef)[apNetwork ssidData];
     494                bool result = false;
     495
     496                SecIdentityRef identity = 0;
     497                // Check first whether we require IEEE 802.1X authentication for the wanted SSID
     498                if (CWKeychainCopyEAPIdentity(ssidData, &identity) == errSecSuccess) {
     499                    CFStringRef username = 0;
     500                    CFStringRef password = 0;
     501                    if (CWKeychainCopyEAPUsernameAndPassword(ssidData, &username, &password) == errSecSuccess) {
     502                        result = [wifiInterface associateToEnterpriseNetwork:apNetwork
     503                                    identity:identity username:(NSString *)username password:(NSString *)password
     504                                    error:&err];
     505                        CFRelease(username);
     506                        CFRelease(password);
     507                    }
     508                    CFRelease(identity);
     509                } else {
     510                    CFStringRef password = 0;
     511                    if (CWKeychainCopyPassword(ssidData, &password) == errSecSuccess) {
     512                        result = [wifiInterface associateToNetwork:apNetwork password:(NSString *)password error:&err];
     513                        CFRelease(password);
     514                    }
     515                }
    603516
    604                     if(!err) {
    605                         if(!result) {
    606                             emit connectionError(id, ConnectError);
    607                         } else {
    608                             return;
    609                         }
     517                if (!err) {
     518                    if (!result) {
     519                        emit connectionError(id, ConnectError);
    610520                    } else {
    611                         qDebug() <<"associate ERROR"<<  qt_NSStringToQString([err localizedDescription ]);
     521                        return;
    612522                    }
     523                } else {
     524                    qDebug() <<"associate ERROR"<<  QCFString::toQString(CFStringRef([err localizedDescription ]));
    613525                }
    614526            } //end scan network
    615527        } else {
    616             qDebug() <<"scan ERROR"<<  qt_NSStringToQString([err localizedDescription ]);
     528            qDebug() <<"scan ERROR"<<  QCFString::toQString(CFStringRef([err localizedDescription ]));
    617529        }
    618530        emit connectionError(id, InterfaceLookupError);
    619531    }
    void QCoreWlanEngine::disconnectFromId(const QString &id) 
    631543    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
    632544
    633545    CWInterface *wifiInterface =
    634         [CWInterface interfaceWithName: qt_QStringToNSString(interfaceString)];
     546        [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)];
    635547
    636548    [wifiInterface disassociate];
    637     if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) {
     549    if (wifiInterface.serviceActive) {
    638550        locker.unlock();
    639551        emit connectionError(id, DisconnectionError);
    640552        locker.relock();
    void QCoreWlanEngine::doRequestUpdate() 
    654566
    655567    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
    656568
    657     NSArray *wifiInterfaces = [CWInterface supportedInterfaces];
    658     for (uint row = 0; row < [wifiInterfaces count]; ++row) {
    659             scanThread->interfaceName = qt_NSStringToQString([wifiInterfaces objectAtIndex:row]);
     569    NSSet *wifiInterfaces = [CWInterface interfaceNames];
     570    for (NSString *ifName in wifiInterfaces) {
     571            scanThread->interfaceName = QCFString::toQString(CFStringRef(ifName));
    660572            scanThread->start();
    661573    }
    662574    locker.unlock();
    bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) 
    669581    bool haswifi = false;
    670582    if(hasWifi) {
    671583        NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
    672         CWInterface *defaultInterface = [CWInterface interfaceWithName: qt_QStringToNSString(wifiDeviceName)];
    673         if([defaultInterface power]) {
     584        CWInterface *defaultInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(wifiDeviceName)];
     585        if (defaultInterface.powerOn) {
    674586            haswifi = true;
    675587        }
    676588        [autoreleasepool release];
    quint64 QCoreWlanEngine::startTime(const QString &identifier) 
    898810                bool ok = false;
    899811                for(int i = 0; i < dictSize; i++) {
    900812                    if([ssidStr isEqualToString:keys[i]]) {
    901                         const QString ident = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString(objects[i])));
     813                        const QString ident = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef(objects[i]))));
    902814                        if(ident == identifier) {
    903815                            ok = true;
    904816                        }
    quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b) 
    944856}
    945857
    946858QT_END_NAMESPACE
     859
     860#else // QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE
     861#include "qcorewlanengine_10_6.mm"
     862#endif
  • new file src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm

    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
    - +  
     1/****************************************************************************
     2**
     3** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
     4** Contact: http://www.qt-project.org/legal
     5**
     6** This file is part of the plugins of the Qt Toolkit.
     7**
     8** $QT_BEGIN_LICENSE:LGPL$
     9** Commercial License Usage
     10** Licensees holding valid commercial Qt licenses may use this file in
     11** accordance with the commercial license agreement provided with the
     12** Software or, alternatively, in accordance with the terms contained in
     13** a written agreement between you and Digia.  For licensing terms and
     14** conditions see http://qt.digia.com/licensing.  For further information
     15** use the contact form at http://qt.digia.com/contact-us.
     16**
     17** GNU Lesser General Public License Usage
     18** Alternatively, this file may be used under the terms of the GNU Lesser
     19** General Public License version 2.1 as published by the Free Software
     20** Foundation and appearing in the file LICENSE.LGPL included in the
     21** packaging of this file.  Please review the following information to
     22** ensure the GNU Lesser General Public License version 2.1 requirements
     23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
     24**
     25** In addition, as a special exception, Digia gives you certain additional
     26** rights.  These rights are described in the Digia Qt LGPL Exception
     27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
     28**
     29** GNU General Public License Usage
     30** Alternatively, this file may be used under the terms of the GNU
     31** General Public License version 3.0 as published by the Free Software
     32** Foundation and appearing in the file LICENSE.GPL included in the
     33** packaging of this file.  Please review the following information to
     34** ensure the GNU General Public License version 3.0 requirements will be
     35** met: http://www.gnu.org/copyleft/gpl.html.
     36**
     37**
     38** $QT_END_LICENSE$
     39**
     40****************************************************************************/
     41
     42#include <SystemConfiguration/SCNetworkConfiguration.h>
     43
     44@interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject
     45{
     46    NSNotificationCenter *notificationCenter;
     47    CWInterface *currentInterface;
     48    QCoreWlanEngine *engine;
     49    NSLock *locker;
     50}
     51- (void)notificationHandler;//:(NSNotification *)notification;
     52- (void)remove;
     53- (void)setEngine:(QCoreWlanEngine *)coreEngine;
     54- (QCoreWlanEngine *)engine;
     55- (void)dealloc;
     56
     57@property (assign) QCoreWlanEngine* engine;
     58
     59@end
     60
     61@implementation QT_MANGLE_NAMESPACE(QNSListener)
     62
     63- (id) init
     64{
     65    [locker lock];
     66    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
     67    notificationCenter = [NSNotificationCenter defaultCenter];
     68    currentInterface = [CWInterface interfaceWithName:nil];
     69    [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:kCWPowerDidChangeNotification object:nil];
     70    [locker unlock];
     71    [autoreleasepool release];
     72    return self;
     73}
     74
     75-(void)dealloc
     76{
     77    [super dealloc];
     78}
     79
     80-(void)setEngine:(QCoreWlanEngine *)coreEngine
     81{
     82    [locker lock];
     83    if(!engine)
     84        engine = coreEngine;
     85    [locker unlock];
     86}
     87
     88-(QCoreWlanEngine *)engine
     89{
     90    return engine;
     91}
     92
     93-(void)remove
     94{
     95    [locker lock];
     96    [notificationCenter removeObserver:self];
     97    [locker unlock];
     98}
     99
     100- (void)notificationHandler//:(NSNotification *)notification
     101{
     102    engine->requestUpdate();
     103}
     104@end
     105
     106static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0;
     107
     108QT_BEGIN_NAMESPACE
     109
     110void networkChangeCallback(SCDynamicStoreRef/* store*/, CFArrayRef changedKeys, void *info)
     111{
     112    for ( long i = 0; i < CFArrayGetCount(changedKeys); i++) {
     113
     114        QString changed =  QCFString::toQString(CFStringRef((CFStringRef)CFArrayGetValueAtIndex(changedKeys, i)));
     115        if( changed.contains("/Network/Global/IPv4")) {
     116            QCoreWlanEngine* wlanEngine = static_cast<QCoreWlanEngine*>(info);
     117            wlanEngine->requestUpdate();
     118        }
     119    }
     120    return;
     121}
     122
     123
     124QScanThread::QScanThread(QObject *parent)
     125    :QThread(parent)
     126{
     127}
     128
     129QScanThread::~QScanThread()
     130{
     131}
     132
     133void QScanThread::quit()
     134{
     135    wait();
     136}
     137
     138void QScanThread::run()
     139{
     140    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
     141    QStringList found;
     142    mutex.lock();
     143    CWInterface *currentInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceName)];
     144    mutex.unlock();
     145
     146    if([currentInterface power]) {
     147        NSError *err = nil;
     148        NSDictionary *parametersDict =  [NSDictionary dictionaryWithObjectsAndKeys:
     149                                   [NSNumber numberWithBool:YES], kCWScanKeyMerge,
     150                                   [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType,
     151                                   [NSNumber numberWithInteger:100], kCWScanKeyRestTime, nil];
     152
     153        NSArray* apArray = [currentInterface scanForNetworksWithParameters:parametersDict error:&err];
     154        CWNetwork *apNetwork;
     155
     156        if (!err) {
     157
     158            for(uint row=0; row < [apArray count]; row++ ) {
     159                apNetwork = [apArray objectAtIndex:row];
     160
     161                const QString networkSsid = QCFString::toQString(CFStringRef([apNetwork ssid]));
     162                const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid));
     163                found.append(id);
     164
     165                QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined;
     166                bool known = isKnownSsid(networkSsid);
     167                if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) {
     168                    if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) {
     169                        state = QNetworkConfiguration::Active;
     170                    }
     171                }
     172                if(state == QNetworkConfiguration::Undefined) {
     173                    if(known) {
     174                        state = QNetworkConfiguration::Discovered;
     175                    } else {
     176                        state = QNetworkConfiguration::Undefined;
     177                    }
     178                }
     179                QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose;
     180                if([[apNetwork securityMode] intValue] == kCWSecurityModeOpen) {
     181                    purpose = QNetworkConfiguration::PublicPurpose;
     182                } else {
     183                    purpose = QNetworkConfiguration::PrivatePurpose;
     184                }
     185
     186                found.append(foundNetwork(id, networkSsid, state, interfaceName, purpose));
     187
     188            }
     189        }
     190    }
     191    // add known configurations that are not around.
     192    QMapIterator<QString, QMap<QString,QString> > i(userProfiles);
     193    while (i.hasNext()) {
     194        i.next();
     195
     196        QString networkName = i.key();
     197        const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkName));
     198
     199        if(!found.contains(id)) {
     200            QString networkSsid = getSsidFromNetworkName(networkName);
     201            const QString ssidId = QString::number(qHash(QLatin1String("corewlan:") + networkSsid));
     202            QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined;
     203            QString interfaceName;
     204            QMapIterator<QString, QString> ij(i.value());
     205            while (ij.hasNext()) {
     206                ij.next();
     207                interfaceName = ij.value();
     208            }
     209
     210            if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) {
     211                if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) {
     212                    state = QNetworkConfiguration::Active;
     213                }
     214            }
     215            if(state == QNetworkConfiguration::Undefined) {
     216                if( userProfiles.contains(networkName)
     217                    && found.contains(ssidId)) {
     218                    state = QNetworkConfiguration::Discovered;
     219                }
     220            }
     221
     222            if(state == QNetworkConfiguration::Undefined) {
     223                state = QNetworkConfiguration::Defined;
     224            }
     225
     226            found.append(foundNetwork(id, networkName, state, interfaceName, QNetworkConfiguration::UnknownPurpose));
     227        }
     228    }
     229    emit networksChanged();
     230    [autoreleasepool release];
     231}
     232
     233QStringList QScanThread::foundNetwork(const QString &id, const QString &name, const QNetworkConfiguration::StateFlags state, const QString &interfaceName, const QNetworkConfiguration::Purpose purpose)
     234{
     235    QStringList found;
     236    QMutexLocker locker(&mutex);
     237        QNetworkConfigurationPrivate *ptr = new QNetworkConfigurationPrivate;
     238
     239        ptr->name = name;
     240        ptr->isValid = true;
     241        ptr->id = id;
     242        ptr->state = state;
     243        ptr->type = QNetworkConfiguration::InternetAccessPoint;
     244        ptr->bearerType = QNetworkConfiguration::BearerWLAN;
     245        ptr->purpose = purpose;
     246
     247        fetchedConfigurations.append( ptr);
     248        configurationInterface.insert(ptr->id, interfaceName);
     249
     250        locker.unlock();
     251        locker.relock();
     252       found.append(id);
     253    return found;
     254}
     255
     256QList<QNetworkConfigurationPrivate *> QScanThread::getConfigurations()
     257{
     258    QMutexLocker locker(&mutex);
     259
     260    QList<QNetworkConfigurationPrivate *> foundConfigurations = fetchedConfigurations;
     261    fetchedConfigurations.clear();
     262
     263    return foundConfigurations;
     264}
     265
     266void QScanThread::getUserConfigurations()
     267{
     268    QMutexLocker locker(&mutex);
     269
     270    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
     271    userProfiles.clear();
     272
     273    NSArray *wifiInterfaces = [CWInterface supportedInterfaces];
     274    for(uint row=0; row < [wifiInterfaces count]; row++ ) {
     275
     276        CWInterface *wifiInterface = [CWInterface interfaceWithName: [wifiInterfaces objectAtIndex:row]];
     277        if ( ![wifiInterface power] )
     278            continue;
     279
     280        NSString *nsInterfaceName = [wifiInterface name];
     281// add user configured system networks
     282        SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil);
     283        NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]);
     284        CFRelease(dynRef);
     285        if(airportPlist != nil) {
     286            NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"];
     287
     288            NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"];
     289            for(NSString *ssidkey in thisSsidarray) {
     290                QString thisSsid = QCFString::toQString(CFStringRef(ssidkey));
     291                if(!userProfiles.contains(thisSsid)) {
     292                    QMap <QString,QString> map;
     293                    map.insert(thisSsid, QCFString::toQString(CFStringRef(nsInterfaceName)));
     294                    userProfiles.insert(thisSsid, map);
     295                }
     296            }
     297            CFRelease(airportPlist);
     298        }
     299
     300        // 802.1X user profiles
     301        QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist";
     302        NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile: (NSString *)QCFString::toCFStringRef(userProfilePath)] autorelease];
     303        if(eapDict != nil) {
     304            NSString *profileStr= @"Profiles";
     305            NSString *nameStr = @"UserDefinedName";
     306            NSString *networkSsidStr = @"Wireless Network";
     307            for (id profileKey in eapDict) {
     308                if ([profileStr isEqualToString:profileKey]) {
     309                    NSDictionary *itemDict = [eapDict objectForKey:profileKey];
     310                    for (id itemKey in itemDict) {
     311
     312                        NSInteger dictSize = [itemKey count];
     313                        id objects[dictSize];
     314                        id keys[dictSize];
     315
     316                        [itemKey getObjects:objects andKeys:keys];
     317                        QString networkName;
     318                        QString ssid;
     319                        for(int i = 0; i < dictSize; i++) {
     320                            if([nameStr isEqualToString:keys[i]]) {
     321                                networkName = QCFString::toQString(CFStringRef(objects[i]));
     322                            }
     323                            if([networkSsidStr isEqualToString:keys[i]]) {
     324                                ssid = QCFString::toQString(CFStringRef(objects[i]));
     325                            }
     326                            if(!userProfiles.contains(networkName)
     327                                && !ssid.isEmpty()) {
     328                                QMap<QString,QString> map;
     329                                map.insert(ssid, QCFString::toQString(CFStringRef(nsInterfaceName)));
     330                                userProfiles.insert(networkName, map);
     331                            }
     332                        }
     333                    }
     334                }
     335            }
     336        }
     337    }
     338    [autoreleasepool release];
     339}
     340
     341QString QScanThread::getSsidFromNetworkName(const QString &name)
     342{
     343    QMutexLocker locker(&mutex);
     344
     345    QMapIterator<QString, QMap<QString,QString> > i(userProfiles);
     346    while (i.hasNext()) {
     347        i.next();
     348        QMap<QString,QString> map = i.value();
     349        QMapIterator<QString, QString> ij(i.value());
     350         while (ij.hasNext()) {
     351             ij.next();
     352             const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") +i.key()));
     353             if(name == i.key() || name == networkNameHash) {
     354                 return ij.key();
     355             }
     356        }
     357    }
     358    return QString();
     359}
     360
     361QString QScanThread::getNetworkNameFromSsid(const QString &ssid)
     362{
     363    QMutexLocker locker(&mutex);
     364
     365    QMapIterator<QString, QMap<QString,QString> > i(userProfiles);
     366    while (i.hasNext()) {
     367        i.next();
     368        QMap<QString,QString> map = i.value();
     369        QMapIterator<QString, QString> ij(i.value());
     370         while (ij.hasNext()) {
     371             ij.next();
     372             if(ij.key() == ssid) {
     373                 return i.key();
     374             }
     375         }
     376    }
     377    return QString();
     378}
     379
     380bool QScanThread::isKnownSsid(const QString &ssid)
     381{
     382    QMutexLocker locker(&mutex);
     383
     384    QMapIterator<QString, QMap<QString,QString> > i(userProfiles);
     385    while (i.hasNext()) {
     386        i.next();
     387        QMap<QString,QString> map = i.value();
     388        if(map.keys().contains(ssid)) {
     389            return true;
     390        }
     391    }
     392    return false;
     393}
     394
     395
     396QCoreWlanEngine::QCoreWlanEngine(QObject *parent)
     397:   QBearerEngineImpl(parent), scanThread(0)
     398{
     399    scanThread = new QScanThread(this);
     400    connect(scanThread, SIGNAL(networksChanged()),
     401            this, SLOT(networksChanged()));
     402}
     403
     404QCoreWlanEngine::~QCoreWlanEngine()
     405{
     406    while (!foundConfigurations.isEmpty())
     407        delete foundConfigurations.takeFirst();
     408    [listener remove];
     409    [listener release];
     410}
     411
     412void QCoreWlanEngine::initialize()
     413{
     414    QMutexLocker locker(&mutex);
     415    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
     416
     417    if([[CWInterface supportedInterfaces] count] > 0 && !listener) {
     418        listener = [[QT_MANGLE_NAMESPACE(QNSListener) alloc] init];
     419        listener.engine = this;
     420        hasWifi = true;
     421    } else {
     422        hasWifi = false;
     423    }
     424    storeSession = NULL;
     425
     426    startNetworkChangeLoop();
     427    [autoreleasepool release];
     428}
     429
     430
     431QString QCoreWlanEngine::getInterfaceFromId(const QString &id)
     432{
     433    QMutexLocker locker(&mutex);
     434
     435    return scanThread->configurationInterface.value(id);
     436}
     437
     438bool QCoreWlanEngine::hasIdentifier(const QString &id)
     439{
     440    QMutexLocker locker(&mutex);
     441
     442    return scanThread->configurationInterface.contains(id);
     443}
     444
     445void QCoreWlanEngine::connectToId(const QString &id)
     446{
     447    QMutexLocker locker(&mutex);
     448    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
     449    QString interfaceString = getInterfaceFromId(id);
     450
     451    CWInterface *wifiInterface =
     452        [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)];
     453
     454    if ([wifiInterface power]) {
     455        NSError *err = nil;
     456        NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
     457
     458        QString wantedSsid;
     459
     460        QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
     461
     462        const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name));
     463        const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name)));
     464
     465        bool using8021X = false;
     466        if (idHash2 != id) {
     467            NSArray *array = [CW8021XProfile allUser8021XProfiles];
     468
     469            for (NSUInteger i = 0; i < [array count]; ++i) {
     470                const QString networkNameHashCheck = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef([[array objectAtIndex:i] userDefinedName]))));
     471
     472                const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef([[array objectAtIndex:i] ssid]))));
     473
     474                if (id == networkNameHashCheck || id == ssidHash) {
     475                    const QString thisName = scanThread->getSsidFromNetworkName(id);
     476                    if (thisName.isEmpty())
     477                        wantedSsid = id;
     478                    else
     479                        wantedSsid = thisName;
     480
     481                    [params setValue: [array objectAtIndex:i] forKey:kCWAssocKey8021XProfile];
     482                    using8021X = true;
     483                    break;
     484                }
     485            }
     486        }
     487
     488        if (!using8021X) {
     489            QString wantedNetwork;
     490            QMapIterator<QString, QMap<QString,QString> > i(scanThread->userProfiles);
     491            while (i.hasNext()) {
     492                i.next();
     493                wantedNetwork = i.key();
     494                const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork));
     495                if (id == networkNameHash) {
     496                    wantedSsid =  scanThread->getSsidFromNetworkName(wantedNetwork);
     497                    break;
     498                }
     499            }
     500        }
     501        NSDictionary *scanParameters = [NSDictionary dictionaryWithObjectsAndKeys:
     502                                        [NSNumber numberWithBool:YES], kCWScanKeyMerge,
     503                                        [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType,
     504                                        [NSNumber numberWithInteger:100], kCWScanKeyRestTime,
     505                                        (NSString *)QCFString::toCFStringRef(wantedSsid), kCWScanKeySSID,
     506                                        nil];
     507
     508        NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:scanParameters error:&err];
     509
     510        if(!err) {
     511            for(uint row=0; row < [scanArray count]; row++ ) {
     512                CWNetwork *apNetwork = [scanArray objectAtIndex:row];
     513
     514                if(wantedSsid == QCFString::toQString(CFStringRef([apNetwork ssid]))) {
     515
     516                    if(!using8021X) {
     517                        SecKeychainAttribute attributes[3];
     518
     519                        NSString *account = [apNetwork ssid];
     520                        NSString *keyKind = @"AirPort network password";
     521                        NSString *keyName = account;
     522
     523                        attributes[0].tag = kSecAccountItemAttr;
     524                        attributes[0].data = (void *)[account UTF8String];
     525                        attributes[0].length = [account length];
     526
     527                        attributes[1].tag = kSecDescriptionItemAttr;
     528                        attributes[1].data = (void *)[keyKind UTF8String];
     529                        attributes[1].length = [keyKind length];
     530
     531                        attributes[2].tag = kSecLabelItemAttr;
     532                        attributes[2].data = (void *)[keyName UTF8String];
     533                        attributes[2].length = [keyName length];
     534
     535                        SecKeychainAttributeList attributeList = {3,attributes};
     536
     537                        SecKeychainSearchRef searchRef;
     538                        SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef);
     539
     540                        NSString *password = @"";
     541                        SecKeychainItemRef searchItem;
     542
     543                        if (SecKeychainSearchCopyNext(searchRef, &searchItem) == noErr) {
     544                            UInt32 realPasswordLength;
     545                            SecKeychainAttribute attributesW[8];
     546                            attributesW[0].tag = kSecAccountItemAttr;
     547                            SecKeychainAttributeList listW = {1,attributesW};
     548                            char *realPassword;
     549                            OSStatus status = SecKeychainItemCopyContent(searchItem, NULL, &listW, &realPasswordLength,(void **)&realPassword);
     550
     551                            if (status == noErr) {
     552                                if (realPassword != NULL) {
     553
     554                                    QByteArray pBuf;
     555                                    pBuf.resize(realPasswordLength);
     556                                    pBuf.prepend(realPassword);
     557                                    pBuf.insert(realPasswordLength,'\0');
     558
     559                                    password = [NSString stringWithUTF8String:pBuf];
     560                                }
     561                                SecKeychainItemFreeContent(&listW, realPassword);
     562                            }
     563
     564                            CFRelease(searchItem);
     565                        } else {
     566                            qDebug() << "SecKeychainSearchCopyNext error";
     567                        }
     568                        [params setValue: password forKey: kCWAssocKeyPassphrase];
     569                    } // end using8021X
     570
     571
     572                    bool result = [wifiInterface associateToNetwork: apNetwork parameters:[NSDictionary dictionaryWithDictionary:params] error:&err];
     573
     574                    if(!err) {
     575                        if(!result) {
     576                            emit connectionError(id, ConnectError);
     577                        } else {
     578                            return;
     579                        }
     580                    } else {
     581                        qDebug() <<"associate ERROR"<<  QCFString::toQString(CFStringRef([err localizedDescription ]));
     582                    }
     583                }
     584            } //end scan network
     585        } else {
     586            qDebug() <<"scan ERROR"<<  QCFString::toQString(CFStringRef([err localizedDescription ]));
     587        }
     588        emit connectionError(id, InterfaceLookupError);
     589    }
     590
     591    locker.unlock();
     592    emit connectionError(id, InterfaceLookupError);
     593    [autoreleasepool release];
     594}
     595
     596void QCoreWlanEngine::disconnectFromId(const QString &id)
     597{
     598    QMutexLocker locker(&mutex);
     599
     600    QString interfaceString = getInterfaceFromId(id);
     601    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
     602
     603    CWInterface *wifiInterface =
     604        [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)];
     605
     606    [wifiInterface disassociate];
     607    if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) {
     608        locker.unlock();
     609        emit connectionError(id, DisconnectionError);
     610        locker.relock();
     611    }
     612    [autoreleasepool release];
     613}
     614
     615void QCoreWlanEngine::requestUpdate()
     616{
     617    scanThread->getUserConfigurations();
     618    doRequestUpdate();
     619}
     620
     621void QCoreWlanEngine::doRequestUpdate()
     622{
     623    QMutexLocker locker(&mutex);
     624
     625    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
     626
     627    NSArray *wifiInterfaces = [CWInterface supportedInterfaces];
     628    for (uint row = 0; row < [wifiInterfaces count]; ++row) {
     629            scanThread->interfaceName = QCFString::toQString(CFStringRef([wifiInterfaces objectAtIndex:row]));
     630            scanThread->start();
     631    }
     632    locker.unlock();
     633    [autoreleasepool release];
     634}
     635
     636bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName)
     637{
     638    QMutexLocker locker(&mutex);
     639    bool haswifi = false;
     640    if(hasWifi) {
     641        NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
     642        CWInterface *defaultInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(wifiDeviceName)];
     643        if([defaultInterface power]) {
     644            haswifi = true;
     645        }
     646        [autoreleasepool release];
     647    }
     648    return haswifi;
     649}
     650
     651
     652QNetworkSession::State QCoreWlanEngine::sessionStateForId(const QString &id)
     653{
     654    QMutexLocker locker(&mutex);
     655    QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
     656
     657    if (!ptr)
     658        return QNetworkSession::Invalid;
     659
     660    if (!ptr->isValid) {
     661        return QNetworkSession::Invalid;
     662    } else if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
     663        return QNetworkSession::Connected;
     664    } else if ((ptr->state & QNetworkConfiguration::Discovered) ==
     665                QNetworkConfiguration::Discovered) {
     666        return QNetworkSession::Disconnected;
     667    } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) {
     668        return QNetworkSession::NotAvailable;
     669    } else if ((ptr->state & QNetworkConfiguration::Undefined) ==
     670                QNetworkConfiguration::Undefined) {
     671        return QNetworkSession::NotAvailable;
     672    }
     673
     674    return QNetworkSession::Invalid;
     675}
     676
     677QNetworkConfigurationManager::Capabilities QCoreWlanEngine::capabilities() const
     678{
     679    return QNetworkConfigurationManager::ForcedRoaming;
     680}
     681
     682void QCoreWlanEngine::startNetworkChangeLoop()
     683{
     684
     685    SCDynamicStoreContext dynStoreContext = { 0, this/*(void *)storeSession*/, NULL, NULL, NULL };
     686    storeSession = SCDynamicStoreCreate(NULL,
     687                                 CFSTR("networkChangeCallback"),
     688                                 networkChangeCallback,
     689                                 &dynStoreContext);
     690    if (!storeSession ) {
     691        qWarning() << "could not open dynamic store: error:" << SCErrorString(SCError());
     692        return;
     693    }
     694
     695    CFMutableArrayRef notificationKeys;
     696    notificationKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
     697    CFMutableArrayRef patternsArray;
     698    patternsArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
     699
     700    CFStringRef storeKey;
     701    storeKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
     702                                                     kSCDynamicStoreDomainState,
     703                                                     kSCEntNetIPv4);
     704    CFArrayAppendValue(notificationKeys, storeKey);
     705    CFRelease(storeKey);
     706
     707    storeKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
     708                                                      kSCDynamicStoreDomainState,
     709                                                      kSCCompAnyRegex,
     710                                                      kSCEntNetIPv4);
     711    CFArrayAppendValue(patternsArray, storeKey);
     712    CFRelease(storeKey);
     713
     714    if (!SCDynamicStoreSetNotificationKeys(storeSession , notificationKeys, patternsArray)) {
     715        qWarning() << "register notification error:"<< SCErrorString(SCError());
     716        CFRelease(storeSession );
     717        CFRelease(notificationKeys);
     718        CFRelease(patternsArray);
     719        return;
     720    }
     721    CFRelease(notificationKeys);
     722    CFRelease(patternsArray);
     723
     724    runloopSource = SCDynamicStoreCreateRunLoopSource(NULL, storeSession , 0);
     725    if (!runloopSource) {
     726        qWarning() << "runloop source error:"<< SCErrorString(SCError());
     727        CFRelease(storeSession );
     728        return;
     729    }
     730
     731    CFRunLoopAddSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode);
     732    return;
     733}
     734
     735QNetworkSessionPrivate *QCoreWlanEngine::createSessionBackend()
     736{
     737    return new QNetworkSessionPrivateImpl;
     738}
     739
     740QNetworkConfigurationPrivatePointer QCoreWlanEngine::defaultConfiguration()
     741{
     742    return QNetworkConfigurationPrivatePointer();
     743}
     744
     745bool QCoreWlanEngine::requiresPolling() const
     746{
     747    return true;
     748}
     749
     750void QCoreWlanEngine::networksChanged()
     751{
     752    QMutexLocker locker(&mutex);
     753
     754    QStringList previous = accessPointConfigurations.keys();
     755
     756    QList<QNetworkConfigurationPrivate *> foundConfigurations = scanThread->getConfigurations();
     757    while (!foundConfigurations.isEmpty()) {
     758        QNetworkConfigurationPrivate *cpPriv = foundConfigurations.takeFirst();
     759
     760        previous.removeAll(cpPriv->id);
     761
     762        if (accessPointConfigurations.contains(cpPriv->id)) {
     763            QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(cpPriv->id);
     764
     765            bool changed = false;
     766
     767            ptr->mutex.lock();
     768
     769            if (ptr->isValid != cpPriv->isValid) {
     770                ptr->isValid = cpPriv->isValid;
     771                changed = true;
     772            }
     773
     774            if (ptr->name != cpPriv->name) {
     775                ptr->name = cpPriv->name;
     776                changed = true;
     777            }
     778
     779            if (ptr->bearerType != cpPriv->bearerType) {
     780                ptr->bearerType = cpPriv->bearerType;
     781                changed = true;
     782            }
     783
     784            if (ptr->state != cpPriv->state) {
     785                ptr->state = cpPriv->state;
     786                changed = true;
     787            }
     788
     789            ptr->mutex.unlock();
     790
     791            if (changed) {
     792                locker.unlock();
     793                emit configurationChanged(ptr);
     794                locker.relock();
     795            }
     796
     797            delete cpPriv;
     798        } else {
     799            QNetworkConfigurationPrivatePointer ptr(cpPriv);
     800
     801            accessPointConfigurations.insert(ptr->id, ptr);
     802
     803            locker.unlock();
     804            emit configurationAdded(ptr);
     805            locker.relock();
     806        }
     807    }
     808
     809    while (!previous.isEmpty()) {
     810        QNetworkConfigurationPrivatePointer ptr =
     811            accessPointConfigurations.take(previous.takeFirst());
     812
     813        locker.unlock();
     814        emit configurationRemoved(ptr);
     815        locker.relock();
     816    }
     817
     818    locker.unlock();
     819    emit updateCompleted();
     820
     821}
     822
     823quint64 QCoreWlanEngine::bytesWritten(const QString &id)
     824{
     825    QMutexLocker locker(&mutex);
     826    const QString interfaceStr = getInterfaceFromId(id);
     827    return getBytes(interfaceStr,false);
     828}
     829
     830quint64 QCoreWlanEngine::bytesReceived(const QString &id)
     831{
     832    QMutexLocker locker(&mutex);
     833    const QString interfaceStr = getInterfaceFromId(id);
     834    return getBytes(interfaceStr,true);
     835}
     836
     837quint64 QCoreWlanEngine::startTime(const QString &identifier)
     838{
     839    QMutexLocker locker(&mutex);
     840    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
     841    quint64 timestamp = 0;
     842
     843    NSString *filePath = @"/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist";
     844    NSDictionary* plistDict = [[[NSDictionary alloc] initWithContentsOfFile:filePath] autorelease];
     845    if(plistDict == nil)
     846        return timestamp;
     847    NSString *input = @"KnownNetworks";
     848    NSString *timeStampStr = @"_timeStamp";
     849
     850    NSString *ssidStr = @"SSID_STR";
     851
     852    for (id key in plistDict) {
     853        if ([input isEqualToString:key]) {
     854
     855            NSDictionary *knownNetworksDict = [plistDict objectForKey:key];
     856            if(knownNetworksDict == nil)
     857                return timestamp;
     858            for (id networkKey in knownNetworksDict) {
     859                bool isFound = false;
     860                NSDictionary *itemDict = [knownNetworksDict objectForKey:networkKey];
     861                if(itemDict == nil)
     862                    return timestamp;
     863                NSInteger dictSize = [itemDict count];
     864                id objects[dictSize];
     865                id keys[dictSize];
     866
     867                [itemDict getObjects:objects andKeys:keys];
     868                bool ok = false;
     869                for(int i = 0; i < dictSize; i++) {
     870                    if([ssidStr isEqualToString:keys[i]]) {
     871                        const QString ident = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef(objects[i]))));
     872                        if(ident == identifier) {
     873                            ok = true;
     874                        }
     875                    }
     876                    if(ok && [timeStampStr isEqualToString:keys[i]]) {
     877                        timestamp = (quint64)[objects[i] timeIntervalSince1970];
     878                        isFound = true;
     879                        break;
     880                    }
     881                }
     882                if(isFound)
     883                    break;
     884            }
     885        }
     886    }
     887    [autoreleasepool release];
     888    return timestamp;
     889}
     890
     891quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b)
     892{
     893    struct ifaddrs *ifAddressList, *ifAddress;
     894    struct if_data *if_data;
     895
     896    quint64 bytes = 0;
     897    ifAddressList = nil;
     898    if(getifaddrs(&ifAddressList) == 0) {
     899        for(ifAddress = ifAddressList; ifAddress; ifAddress = ifAddress->ifa_next) {
     900            if(interfaceName == ifAddress->ifa_name) {
     901                if_data = (struct if_data*)ifAddress->ifa_data;
     902                if(b) {
     903                    bytes = if_data->ifi_ibytes;
     904                    break;
     905                } else {
     906                    bytes = if_data->ifi_obytes;
     907                    break;
     908                }
     909            }
     910        }
     911        freeifaddrs(ifAddressList);
     912    }
     913    return bytes;
     914}
     915
     916QT_END_NAMESPACE