diff options
Diffstat (limited to 'src/plugins')
141 files changed, 22992 insertions, 4338 deletions
diff --git a/src/plugins/accessible/widgets/complexwidgets.cpp b/src/plugins/accessible/widgets/complexwidgets.cpp index 8be1560..803786f 100644 --- a/src/plugins/accessible/widgets/complexwidgets.cpp +++ b/src/plugins/accessible/widgets/complexwidgets.cpp @@ -1512,10 +1512,14 @@ QString QAccessibleTabBar::text(Text t, int child) const default: break; } - } else if (child > 0) { + } else { switch (t) { case Name: - return qt_accStripAmp(tabBar()->tabText(child - 1)); + if (child > 0) + return qt_accStripAmp(tabBar()->tabText(child - 1)); + else if (tabBar()->currentIndex() != -1) + return qt_accStripAmp(tabBar()->tabText(tabBar()->currentIndex())); + break; default: break; } diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp index ad33d0b..662663d 100644 --- a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp +++ b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp @@ -176,7 +176,7 @@ static inline QWidget *mdiAreaNavigate(QWidget *area, int minimumDistance = INT_MAX; QWidget *target = 0; - foreach (QWidget *candidate, candidates.values()) { + foreach (QWidget *candidate, candidates) { switch (relation) { case QAccessible::Up: case QAccessible::Down: @@ -984,7 +984,7 @@ int QAccessibleDockWidget::childCount() const int QAccessibleDockWidget::indexOfChild(const QAccessibleInterface *child) const { if (child) { - if (qobject_cast<QDockWidget *>(child->object()) == dockWidget() && child->role(0) == TitleBar) { + if (child->role(0) == TitleBar) { return 1; } else { return 2; //### @@ -1214,7 +1214,7 @@ int QAccessibleTitleBar::childAt(int x, int y) const QObject *QAccessibleTitleBar::object() const { - return m_dockWidget; + return 0; } QDockWidgetLayout *QAccessibleTitleBar::dockWidgetLayout() const diff --git a/src/plugins/accessible/widgets/simplewidgets.cpp b/src/plugins/accessible/widgets/simplewidgets.cpp index daa827e..4a3acbb 100644 --- a/src/plugins/accessible/widgets/simplewidgets.cpp +++ b/src/plugins/accessible/widgets/simplewidgets.cpp @@ -602,13 +602,17 @@ int QAccessibleDisplay::navigate(RelationFlag rel, int entry, QAccessibleInterfa return QAccessibleWidgetEx::navigate(rel, entry, target); } -/*! \reimp */ +/*! \internal */ QString QAccessibleDisplay::imageDescription() { +#ifndef QT_NO_TOOLTIP return widget()->toolTip(); +#else + return QString::null; +#endif } -/*! \reimp */ +/*! \internal */ QSize QAccessibleDisplay::imageSize() { QLabel *label = qobject_cast<QLabel *>(widget()); @@ -620,7 +624,7 @@ QSize QAccessibleDisplay::imageSize() return pixmap->size(); } -/*! \reimp */ +/*! \internal */ QRect QAccessibleDisplay::imagePosition(QAccessible2::CoordinateType coordType) { QLabel *label = qobject_cast<QLabel *>(widget()); diff --git a/src/plugins/bearer/bearer.pro b/src/plugins/bearer/bearer.pro new file mode 100644 index 0000000..d1d75f0 --- /dev/null +++ b/src/plugins/bearer/bearer.pro @@ -0,0 +1,19 @@ +TEMPLATE = subdirs + +contains(QT_CONFIG, dbus) { + contains(QT_CONFIG, icd) { + SUBDIRS += icd + } else:linux* { + SUBDIRS += generic + SUBDIRS += connman networkmanager + } +} + +#win32:SUBDIRS += nla +win32:SUBDIRS += generic +win32:!wince*:SUBDIRS += nativewifi +macx:contains(QT_CONFIG, corewlan):SUBDIRS += corewlan +macx:SUBDIRS += generic +symbian:SUBDIRS += symbian + +isEmpty(SUBDIRS):SUBDIRS = generic diff --git a/src/plugins/bearer/connman/connman.pro b/src/plugins/bearer/connman/connman.pro new file mode 100644 index 0000000..dec408c --- /dev/null +++ b/src/plugins/bearer/connman/connman.pro @@ -0,0 +1,21 @@ +TARGET = qconnmanbearer +include(../../qpluginbase.pri) + +QT = core network dbus + +HEADERS += qconnmanservice_linux_p.h \ + qofonoservice_linux_p.h \ + qconnmanengine.h \ + ../qnetworksession_impl.h \ + ../qbearerengine_impl.h + +SOURCES += main.cpp \ + qconnmanservice_linux.cpp \ + qofonoservice_linux.cpp \ + qconnmanengine.cpp \ + ../qnetworksession_impl.cpp + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/bearer +target.path += $$[QT_INSTALL_PLUGINS]/bearer +INSTALLS += target + diff --git a/src/plugins/imageformats/mng/qmnghandler.h b/src/plugins/bearer/connman/main.cpp index 65243be..d483cf0 100644 --- a/src/plugins/imageformats/mng/qmnghandler.h +++ b/src/plugins/bearer/connman/main.cpp @@ -38,46 +38,56 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "qconnmanengine.h" -#ifndef QMNGHANDLER_H -#define QMNGHANDLER_H +#include <QtNetwork/private/qbearerplugin_p.h> -#include <QtCore/qscopedpointer.h> -#include <QtGui/qimageiohandler.h> +#include <QtCore/qdebug.h> -QT_BEGIN_NAMESPACE +#ifndef QT_NO_BEARERMANAGEMENT +#ifndef QT_NO_DBUS -class QImage; -class QByteArray; -class QIODevice; -class QVariant; -class QMngHandlerPrivate; +QT_BEGIN_NAMESPACE -class QMngHandler : public QImageIOHandler +class QConnmanEnginePlugin : public QBearerEnginePlugin { - public: - QMngHandler(); - ~QMngHandler(); - virtual bool canRead() const; - virtual QByteArray name() const; - virtual bool read(QImage *image); - virtual bool write(const QImage &image); - virtual int currentImageNumber() const; - virtual int imageCount() const; - virtual bool jumpToImage(int imageNumber); - virtual bool jumpToNextImage(); - virtual int loopCount() const; - virtual int nextImageDelay() const; - static bool canRead(QIODevice *device); - virtual QVariant option(ImageOption option) const; - virtual void setOption(ImageOption option, const QVariant & value); - virtual bool supportsOption(ImageOption option) const; +public: + QConnmanEnginePlugin(); + ~QConnmanEnginePlugin(); - private: - Q_DECLARE_PRIVATE(QMngHandler) - QScopedPointer<QMngHandlerPrivate> d_ptr; + QStringList keys() const; + QBearerEngine *create(const QString &key) const; }; +QConnmanEnginePlugin::QConnmanEnginePlugin() +{ +} + +QConnmanEnginePlugin::~QConnmanEnginePlugin() +{ +} + +QStringList QConnmanEnginePlugin::keys() const +{ + return QStringList() << QLatin1String("connman"); +} + +QBearerEngine *QConnmanEnginePlugin::create(const QString &key) const +{ + if (key == QLatin1String("connman")) { + QConnmanEngine *engine = new QConnmanEngine; + if (engine->connmanAvailable()) + return engine; + else + delete engine; + } + return 0; +} + +Q_EXPORT_STATIC_PLUGIN(QConnmanEnginePlugin) +Q_EXPORT_PLUGIN2(qconnmanbearer, QConnmanEnginePlugin) + QT_END_NAMESPACE -#endif // QMNGHANDLER_H +#endif +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/connman/qconnmanengine.cpp b/src/plugins/bearer/connman/qconnmanengine.cpp new file mode 100644 index 0000000..184ceb4 --- /dev/null +++ b/src/plugins/bearer/connman/qconnmanengine.cpp @@ -0,0 +1,810 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qconnmanengine.h" +#include "qconnmanservice_linux_p.h" +#include "qofonoservice_linux_p.h" +#include "../qnetworksession_impl.h" + +#include <QtNetwork/private/qnetworkconfiguration_p.h> + +#include <QtNetwork/qnetworksession.h> + +#include <QtCore/qdebug.h> + +#include <QtDBus/QtDBus> +#include <QtDBus/QDBusConnection> +#include <QtDBus/QDBusInterface> +#include <QtDBus/QDBusMessage> +#include <QtDBus/QDBusReply> + +#ifndef QT_NO_BEARERMANAGEMENT +#ifndef QT_NO_DBUS + +QT_BEGIN_NAMESPACE + +QConnmanEngine::QConnmanEngine(QObject *parent) +: QBearerEngineImpl(parent), + connmanManager(new QConnmanManagerInterface(this)) +{ +} + +QConnmanEngine::~QConnmanEngine() +{ +} + +bool QConnmanEngine::connmanAvailable() const +{ + QMutexLocker locker(&mutex); + return connmanManager->isValid(); +} + +void QConnmanEngine::initialize() +{ + connect(connmanManager,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), + this,SLOT(propertyChangedContext(QString,QString,QDBusVariant))); + + foreach(const QString techPath, connmanManager->getTechnologies()) { + QConnmanTechnologyInterface *tech; + tech = new QConnmanTechnologyInterface(techPath, this); + + connect(tech,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), + this,SLOT(technologyPropertyChangedContext(QString,QString,QDBusVariant))); + + foreach(const QString devicePath,tech->getDevices()) { + QConnmanDeviceInterface *dev; + dev = new QConnmanDeviceInterface(devicePath); + if(!deviceMap.value(techPath).contains(devicePath)) { + connect(dev,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), + this,SLOT(devicePropertyChangedContext(QString,QString,QDBusVariant))); + deviceMap.insert(techPath,QStringList() << devicePath); + foreach(const QString network,dev->getNetworks()) { + serviceNetworks.insert(getServiceForNetwork(network),network); + } + } + } + } + + // Get current list of access points. + getConfigurations(); +} + +QList<QNetworkConfigurationPrivate *> QConnmanEngine::getConfigurations() +{ + QMutexLocker locker(&mutex); + getNetworkListing(); + QList<QNetworkConfigurationPrivate *> fetchedConfigurations; + QNetworkConfigurationPrivate* cpPriv = 0; + + for (int i = 0; i < foundConfigurations.count(); ++i) { + QNetworkConfigurationPrivate *config = new QNetworkConfigurationPrivate; + cpPriv = foundConfigurations.at(i); + + config->name = cpPriv->name; + config->isValid = cpPriv->isValid; + config->id = cpPriv->id; + config->state = cpPriv->state; + config->type = cpPriv->type; + config->roamingSupported = cpPriv->roamingSupported; + config->purpose = cpPriv->purpose; + config->bearerType = cpPriv->bearerType; + + fetchedConfigurations.append(config); + delete config; + } + return fetchedConfigurations; +} + +void QConnmanEngine::getNetworkListing() +{ + QMutexLocker locker(&mutex); + QMapIterator<QString,QStringList> i(deviceMap); + while(i.hasNext()) { + i.next(); + QConnmanDeviceInterface dev(i.value().at(0)); + if(dev.isValid()) { + foreach(const QString network,dev.getNetworks()) { + addNetworkConfiguration(network); + } + } + } +} + +void QConnmanEngine::doRequestUpdate() +{ + connmanManager->requestScan(""); + getConfigurations(); + emit updateCompleted(); +} + +QString QConnmanEngine::getInterfaceFromId(const QString &id) +{ + QMutexLocker locker(&mutex); + return configInterfaces.value(id); +} + +bool QConnmanEngine::hasIdentifier(const QString &id) +{ + QMutexLocker locker(&mutex); + return accessPointConfigurations.contains(id); +} + +void QConnmanEngine::connectToId(const QString &id) +{ + QMutexLocker locker(&mutex); + QString servicePath = serviceFromId(id); + QConnmanServiceInterface serv(servicePath); + if(!serv.isValid()) { + emit connectionError(id, QBearerEngineImpl::InterfaceLookupError); + } else { + if(serv.getType() != "cellular") { + + serv.connect(); + } else { + QOfonoManagerInterface ofonoManager(0); + QString modemPath = ofonoManager.currentModem().path(); + QOfonoDataConnectionManagerInterface dc(modemPath,0); + foreach(const QDBusObjectPath dcPath,dc.getPrimaryContexts()) { + if(dcPath.path().contains(servicePath.section("_",-1))) { + QOfonoPrimaryDataContextInterface primaryContext(dcPath.path(),0); + primaryContext.setActive(true); + } + } + } + } +} + +void QConnmanEngine::disconnectFromId(const QString &id) +{ + QMutexLocker locker(&mutex); + QString servicePath = serviceFromId(id); + QConnmanServiceInterface serv(servicePath); + if(!serv.isValid()) { + emit connectionError(id, DisconnectionError); + } else { + if(serv.getType() != "cellular") { + serv.disconnect(); + } else { + QOfonoManagerInterface ofonoManager(0); + QString modemPath = ofonoManager.currentModem().path(); + QOfonoDataConnectionManagerInterface dc(modemPath,0); + foreach(const QDBusObjectPath dcPath,dc.getPrimaryContexts()) { + if(dcPath.path().contains(servicePath.section("_",-1))) { + QOfonoPrimaryDataContextInterface primaryContext(dcPath.path(),0); + primaryContext.setActive(false); + } + } + } + } +} + +void QConnmanEngine::requestUpdate() +{ + QMutexLocker locker(&mutex); + QTimer::singleShot(0, this, SLOT(doRequestUpdate())); +} + +QString QConnmanEngine::serviceFromId(const QString &id) +{ + QMutexLocker locker(&mutex); + foreach(const QString service, serviceNetworks.keys()) { + if (id == QString::number(qHash(service))) + return service; + } + + return QString(); +} + +QNetworkSession::State QConnmanEngine::sessionStateForId(const QString &id) +{ + QMutexLocker locker(&mutex); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + if (!ptr) + return QNetworkSession::Invalid; + + if (!ptr->isValid) { + return QNetworkSession::Invalid; + + } + QString service = serviceFromId(id); + QConnmanServiceInterface serv(service); + QString servState = serv.getState(); + + if(serv.isFavorite() && (servState == "idle" || servState == "failure")) { + return QNetworkSession::Disconnected; + } + + if(servState == "association" || servState == "configuration" || servState == "login") { + return QNetworkSession::Connecting; + } + if(servState == "ready" || servState == "online") { + return QNetworkSession::Connected; + } + + 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; +} + +quint64 QConnmanEngine::bytesWritten(const QString &id) +{//TODO use connman counter API + QMutexLocker locker(&mutex); + quint64 result = 0; + QString devFile = getInterfaceFromId(id); + QFile tx("/sys/class/net/"+devFile+"/statistics/tx_bytes"); + if(tx.exists() && tx.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&tx); + in >> result; + tx.close(); + } + + return result; +} + +quint64 QConnmanEngine::bytesReceived(const QString &id) +{//TODO use connman counter API + QMutexLocker locker(&mutex); + quint64 result = 0; + QString devFile = getInterfaceFromId(id); + QFile rx("/sys/class/net/"+devFile+"/statistics/rx_bytes"); + if(rx.exists() && rx.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&rx); + in >> result; + rx.close(); + } + return result; +} + +quint64 QConnmanEngine::startTime(const QString &/*id*/) +{ + // TODO + QMutexLocker locker(&mutex); + if (activeTime.isNull()) { + return 0; + } + return activeTime.secsTo(QDateTime::currentDateTime()); +} + +QNetworkConfigurationManager::Capabilities QConnmanEngine::capabilities() const +{ + return QNetworkConfigurationManager::ForcedRoaming | + QNetworkConfigurationManager::DataStatistics | + QNetworkConfigurationManager::CanStartAndStopInterfaces; +} + +QNetworkSessionPrivate *QConnmanEngine::createSessionBackend() +{ + return new QNetworkSessionPrivateImpl; +} + +QNetworkConfigurationPrivatePointer QConnmanEngine::defaultConfiguration() +{ + return QNetworkConfigurationPrivatePointer(); +} + + +QString QConnmanEngine::getServiceForNetwork(const QString &netPath) +{ + QMutexLocker locker(&mutex); + QConnmanNetworkInterface network(netPath, this); + foreach(QString service,connmanManager->getServices()) { + + QString devicePath = netPath.section("/",5,5); + + QConnmanServiceInterface serv(service,this); + if(serv.getName() == network.getName() + && network.getSignalStrength() == serv.getSignalStrength()) { + return service; + } + } + return QString(); +} + +void QConnmanEngine::propertyChangedContext(const QString &path,const QString &item, const QDBusVariant &value) +{ + Q_UNUSED(path); + + QMutexLocker locker(&mutex); + if(item == "Services") { + QDBusArgument arg = qvariant_cast<QDBusArgument>(value.variant()); + QStringList list = qdbus_cast<QStringList>(arg); + + if(list.count() > accessPointConfigurations.count()) { + foreach(const QString service, list) { + addServiceConfiguration(service); + } + } + } + + if(item == "Technologies") { + QDBusArgument arg = qvariant_cast<QDBusArgument>(value.variant()); + QStringList newlist = qdbus_cast<QStringList>(arg); + if(newlist.count() > 0) { + QMap<QString,QConnmanTechnologyInterface *> oldtech = technologies; + + foreach(const QString listPath, newlist) { + if(!oldtech.contains(listPath)) { + QConnmanTechnologyInterface *tech; + tech = new QConnmanTechnologyInterface(listPath,this); + connect(tech,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), + this,SLOT(technologyPropertyChangedContext(QString,QString,QDBusVariant))); + technologies.insert(listPath, tech); + } + } + } + } + if(item == "State") { +// qDebug() << value.variant(); + } +} + +void QConnmanEngine::servicePropertyChangedContext(const QString &path,const QString &item, const QDBusVariant &value) +{ + QMutexLocker locker(&mutex); + if(item == "State") { + configurationChange(QString::number(qHash(path))); + + if(value.variant().toString() == "failure") { + QConnmanServiceInterface serv(path); + emit connectionError(QString::number(qHash(path)), ConnectError); + } + } +} + +void QConnmanEngine::networkPropertyChangedContext(const QString &/*path*/,const QString &/*item*/, const QDBusVariant &/*value*/) +{ + QMutexLocker locker(&mutex); +} + +void QConnmanEngine::devicePropertyChangedContext(const QString &devpath,const QString &item,const QDBusVariant &value) +{ + QMutexLocker locker(&mutex); + if(item == "Networks") { + + QConnmanNetworkInterface network(devpath, this); + + QDBusArgument arg = qvariant_cast<QDBusArgument>(value.variant()); + QStringList remainingNetworks = qdbus_cast<QStringList>(arg); + QString devicetype; + QMapIterator<QString,QStringList> i(deviceMap); + while(i.hasNext()) { + i.next(); + if(i.value().contains(devpath)) { + devicetype = i.key().section("/",-1); + } + } + + QStringList oldnetworks = knownNetworks[devicetype]; + + if(remainingNetworks.count() > oldnetworks.count()) { + foreach(const QString netPath, remainingNetworks) { + if(!oldnetworks.contains(netPath)) { + addNetworkConfiguration(netPath); + } + } + } else { + foreach(const QString netPath, oldnetworks) { + QString servicePath = serviceNetworks.key(netPath); + if(!remainingNetworks.contains(netPath)) { + if(servicePath.isEmpty()) { + removeConfiguration(QString::number(qHash(netPath))); + } else { + removeConfiguration(QString::number(qHash(servicePath))); + } + knownNetworks[devicetype].removeAll(netPath); + } + } + } + } +} + +void QConnmanEngine::technologyPropertyChangedContext(const QString & path, const QString &item, const QDBusVariant &value) +{ + if(item == "Devices") { + QDBusArgument arg = qvariant_cast<QDBusArgument>(value.variant()); + QStringList list = qdbus_cast<QStringList>(arg); + } + if(item == "State") { + + if(value.variant().toString() == "available") { + QConnmanTechnologyInterface tech(connmanManager->getPathForTechnology(path)); + foreach(const QString devPath, tech.getDevices()) { + + if(!deviceMap.value(path).contains(devPath)) { + QConnmanDeviceInterface *dev; + dev = new QConnmanDeviceInterface(devPath,this); + connect(dev,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), + this,SLOT(devicePropertyChangedContext(QString,QString,QDBusVariant))); + deviceMap.insert(path,QStringList() << devPath); + } + } + } + if(value.variant().toString() == "offline") { + deviceMap.remove(path); + QConnmanTechnologyInterface tech(path); + disconnect(&tech,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), + this,SLOT(technologyPropertyChangedContext(QString,QString,QDBusVariant))); + + technologies.remove(path); + getNetworkListing(); + } + } +} + +void QConnmanEngine::configurationChange(const QString &id) +{ + QMutexLocker locker(&mutex); + + if (accessPointConfigurations.contains(id)) { + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + QString servicePath = serviceFromId(id); + QConnmanServiceInterface *serv; + serv = new QConnmanServiceInterface(servicePath); + QString networkName = serv->getName(); + + QNetworkConfiguration::StateFlags curState = getStateForService(servicePath); + + ptr->mutex.lock(); + + if (!ptr->isValid) { + ptr->isValid = true; + } + + if (ptr->name != networkName) { + ptr->name = networkName; + } + + if (ptr->state != curState) { + ptr->state = curState; + } + + ptr->mutex.unlock(); + + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + + } + locker.unlock(); + emit updateCompleted(); +} + +QNetworkConfiguration::StateFlags QConnmanEngine::getStateForService(const QString &service) +{ + QMutexLocker locker(&mutex); + QConnmanServiceInterface serv(service); + QNetworkConfiguration::StateFlags flag = QNetworkConfiguration::Defined; + if( serv.getType() == "cellular") { + if(serv.isSetupRequired()) { + flag = ( flag | QNetworkConfiguration::Defined); + } else { + flag = ( flag | QNetworkConfiguration::Discovered); + } + } else { + if(serv.isFavorite()) { + flag = ( flag | QNetworkConfiguration::Discovered); + } else { + flag = QNetworkConfiguration::Undefined; + } + } + + if(serv.getState() == "ready" || serv.getState() == "online") { + flag = ( flag | QNetworkConfiguration::Active); + } + + return flag; +} + +QNetworkConfiguration::BearerType QConnmanEngine::typeToBearer(const QString &type) +{ + if (type == "wifi") + return QNetworkConfiguration::BearerWLAN; + if (type == "ethernet") + return QNetworkConfiguration::BearerEthernet; + if (type == "bluetooth") + return QNetworkConfiguration::BearerBluetooth; + if (type == "cellular") { + return ofonoTechToBearerType(type); + } + if (type == "wimax") + return QNetworkConfiguration::BearerWiMAX; + +// if(type == "gps") +// if(type == "vpn") + + return QNetworkConfiguration::BearerUnknown; +} + +QNetworkConfiguration::BearerType QConnmanEngine::ofonoTechToBearerType(const QString &/*type*/) +{ + QOfonoManagerInterface ofonoManager(this); + QOfonoNetworkRegistrationInterface ofonoNetwork(ofonoManager.currentModem().path(),this); + + if(ofonoNetwork.isValid()) { + foreach(const QDBusObjectPath op,ofonoNetwork.getOperators() ) { + QOfonoNetworkOperatorInterface opIface(op.path(),this); + + foreach(const QString opTech, opIface.getTechnologies()) { + + if(opTech == "gsm") { + return QNetworkConfiguration::Bearer2G; + } + if(opTech == "edge"){ + return QNetworkConfiguration::BearerCDMA2000; //wrong, I know + } + if(opTech == "umts"){ + return QNetworkConfiguration::BearerWCDMA; + } + if(opTech == "hspa"){ + return QNetworkConfiguration::BearerHSPA; + } + if(opTech == "lte"){ + return QNetworkConfiguration::BearerWiMAX; //not exact + } + } + } + } + return QNetworkConfiguration::BearerUnknown; +} + +bool QConnmanEngine::isRoamingAllowed(const QString &context) +{ + QOfonoManagerInterface ofonoManager(this); + QString modemPath = ofonoManager.currentModem().path(); + QOfonoDataConnectionManagerInterface dc(modemPath,this); + foreach(const QDBusObjectPath dcPath,dc.getPrimaryContexts()) { + if(dcPath.path().contains(context.section("_",-1))) { + return dc.isRoamingAllowed(); + } + } + return false; +} + +void QConnmanEngine::removeConfiguration(const QString &id) +{ + QMutexLocker locker(&mutex); + + if (accessPointConfigurations.contains(id)) { + + QString service = serviceFromId(id); + QConnmanServiceInterface serv(service); + + disconnect(&serv,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), + this,SLOT(servicePropertyChangedContext(QString,QString, QDBusVariant))); + + QString netPath = serviceNetworks.value(service); + serviceNetworks.remove(service); + + QConnmanServiceInterface network(netPath); + disconnect(&network,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), + this,SLOT(networkPropertyChangedContext(QString,QString, QDBusVariant))); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(id); + locker.unlock(); + emit configurationRemoved(ptr); + locker.relock(); + } +} + +void QConnmanEngine::addServiceConfiguration(const QString &servicePath) +{ + QMutexLocker locker(&mutex); + QConnmanServiceInterface *serv; + serv = new QConnmanServiceInterface(servicePath); + const QString netPath = serviceNetworks.value(servicePath); + + QConnmanNetworkInterface *network; + network = new QConnmanNetworkInterface(netPath, this); + + + const QString id = QString::number(qHash(servicePath)); + + if (!accessPointConfigurations.contains(id)) { + QConnmanDeviceInterface device(netPath.section("/",0,5),this); + + serviceNetworks.insert(servicePath,netPath); + + knownNetworks[device.getType()].append(netPath); + + connect(serv,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), + this,SLOT(servicePropertyChangedContext(QString,QString, QDBusVariant))); + QNetworkConfigurationPrivate* cpPriv = new QNetworkConfigurationPrivate(); + + QString networkName = serv->getName(); + + const QString connectionType = serv->getType(); + if (connectionType == "ethernet") { + cpPriv->bearerType = QNetworkConfiguration::BearerEthernet; + } else if (connectionType == "wifi") { + cpPriv->bearerType = QNetworkConfiguration::BearerWLAN; + } else if (connectionType == "cellular") { + cpPriv->bearerType = ofonoTechToBearerType("cellular"); + if(servicePath.isEmpty()) { + networkName = serv->getAPN(); + if(networkName.isEmpty()) { + networkName = serv->getName(); + } + } + cpPriv->roamingSupported = isRoamingAllowed(servicePath); + } else if (connectionType == "wimax") { + cpPriv->bearerType = QNetworkConfiguration::BearerWiMAX; + } else { + cpPriv->bearerType = QNetworkConfiguration::BearerUnknown; + } + + cpPriv->name = networkName; + cpPriv->isValid = true; + cpPriv->id = id; + cpPriv->type = QNetworkConfiguration::InternetAccessPoint; + + if(serv->getSecurity() == "none") { + cpPriv->purpose = QNetworkConfiguration::PublicPurpose; + } else { + cpPriv->purpose = QNetworkConfiguration::PrivatePurpose; + } + + connect(network,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), + this,SLOT(networkPropertyChangedContext(QString,QString, QDBusVariant))); + + cpPriv->state = getStateForService(servicePath); + + QNetworkConfigurationPrivatePointer ptr(cpPriv); + accessPointConfigurations.insert(ptr->id, ptr); + foundConfigurations.append(cpPriv); + configInterfaces[cpPriv->id] = device.getInterface(); + + locker.unlock(); + emit configurationAdded(ptr); + locker.relock(); + emit updateCompleted(); + } +} + +void QConnmanEngine::addNetworkConfiguration(const QString &networkPath) +{ + QMutexLocker locker(&mutex); + if(networkPath.isNull()) + return; + + QConnmanNetworkInterface *network; + network = new QConnmanNetworkInterface(networkPath, this); + QString servicePath = getServiceForNetwork(networkPath); + QConnmanServiceInterface *serv; + + QString id; + QConnmanDeviceInterface device(networkPath.section("/",0,5),this); + + if(servicePath.isEmpty()) { + id = QString::number(qHash(networkPath)); + } else { + id = QString::number(qHash(servicePath)); + serv = new QConnmanServiceInterface(servicePath,this); + connect(serv,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), + this,SLOT(servicePropertyChangedContext(QString,QString, QDBusVariant))); + } + + if (!id.isEmpty() && !accessPointConfigurations.contains(id)) { + + knownNetworks[device.getType()].append(networkPath); + + serviceNetworks.insert(servicePath,networkPath); + + connect(network,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), + this,SLOT(networkPropertyChangedContext(QString,QString, QDBusVariant))); + + QNetworkConfigurationPrivate* cpPriv = new QNetworkConfigurationPrivate(); + + QString networkName = network->getName(); + + if(networkName.isEmpty()) + networkName = "Hidden Network"; + + QNetworkConfiguration::BearerType bearerType; + + if(servicePath.isEmpty()) { + QString devicePath = networkPath.section("/",0,5); + + QConnmanDeviceInterface device(devicePath,this); + bearerType = typeToBearer(device.getType()); + } else { + if(serv->getType() == "cellular") { + bearerType = ofonoTechToBearerType("cellular"); + if(servicePath.isEmpty()) { + networkName = serv->getName(); + } + cpPriv->roamingSupported = isRoamingAllowed(servicePath); + } else { + bearerType = typeToBearer(serv->getType()); + } + } + + cpPriv->name = networkName; + cpPriv->isValid = true; + cpPriv->id = id; + cpPriv->type = QNetworkConfiguration::InternetAccessPoint; + cpPriv->bearerType = bearerType; + + if(network->getWifiSecurity() == "none") { + cpPriv->purpose = QNetworkConfiguration::PublicPurpose; + } else { + cpPriv->purpose = QNetworkConfiguration::PrivatePurpose; + } + + if(servicePath.isEmpty()) + cpPriv->state = QNetworkConfiguration::Undefined; + else + cpPriv->state = getStateForService(servicePath); + + QNetworkConfigurationPrivatePointer ptr(cpPriv); + accessPointConfigurations.insert(ptr->id, ptr); + foundConfigurations.append(cpPriv); + configInterfaces[cpPriv->id] = device.getInterface(); + + locker.unlock(); + emit configurationAdded(ptr); + locker.relock(); + emit updateCompleted(); + } /*else { + qDebug() << "Not added~~~~~~~~~~~"; + }*/ +} + +bool QConnmanEngine::requiresPolling() const +{ + return false; +} + +QT_END_NAMESPACE + +#endif // QT_NO_DBUS +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/connman/qconnmanengine.h b/src/plugins/bearer/connman/qconnmanengine.h new file mode 100644 index 0000000..2a2308f --- /dev/null +++ b/src/plugins/bearer/connman/qconnmanengine.h @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCONNMANENGINE_P_H +#define QCONNMANENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "../qbearerengine_impl.h" + +#include "qconnmanservice_linux_p.h" + +#include <QMap> +#include <QVariant> + +#ifndef QT_NO_BEARERMANAGEMENT +#ifndef QT_NO_DBUS + +QT_BEGIN_NAMESPACE + +class QConnmanEngine : public QBearerEngineImpl +{ + Q_OBJECT + +public: + QConnmanEngine(QObject *parent = 0); + ~QConnmanEngine(); + + bool connmanAvailable() const; + + virtual QString getInterfaceFromId(const QString &id); + bool hasIdentifier(const QString &id); + + virtual void connectToId(const QString &id); + virtual void disconnectFromId(const QString &id); + + Q_INVOKABLE void initialize(); + Q_INVOKABLE void requestUpdate(); + + QNetworkSession::State sessionStateForId(const QString &id); + QNetworkSessionPrivate *createSessionBackend(); + + virtual quint64 bytesWritten(const QString &id); + virtual quint64 bytesReceived(const QString &id); + virtual quint64 startTime(const QString &id); + + + virtual QNetworkConfigurationManager::Capabilities capabilities() const; + virtual QNetworkConfigurationPrivatePointer defaultConfiguration(); + + void configurationChange(const QString &id); + QList<QNetworkConfigurationPrivate *> getConfigurations(); + + +private Q_SLOTS: + + void doRequestUpdate(); + void servicePropertyChangedContext(const QString &,const QString &,const QDBusVariant &); + void networkPropertyChangedContext(const QString &,const QString &,const QDBusVariant &); + void devicePropertyChangedContext(const QString &,const QString &,const QDBusVariant &); + void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); + void technologyPropertyChangedContext(const QString &,const QString &, const QDBusVariant &); + +private: + QConnmanManagerInterface *connmanManager; + + QList<QNetworkConfigurationPrivate *> foundConfigurations; + + void getNetworkListing(); + + QString getServiceForNetwork(const QString &network); + + QString serviceFromId(const QString &id); + QString networkFromId(const QString &id); + + QNetworkConfiguration::StateFlags getStateForService(const QString &service); + QNetworkConfiguration::BearerType typeToBearer(const QString &type); + + void removeConfiguration(const QString &servicePath); + void addServiceConfiguration(const QString &servicePath); + void addNetworkConfiguration(const QString &worknetPath); + QDateTime activeTime; + + + QMap<QString,QConnmanTechnologyInterface *> technologies; // techpath, tech interface + QMap<QString,QString> configInterfaces; // id, interface name + QMap<QString,QStringList> knownNetworks; //device path, net paths list + QMap<QString,QStringList> deviceMap; //tech path, device path + QMap<QString, QString> serviceNetworks; //service, network + + QNetworkConfiguration::BearerType ofonoTechToBearerType(const QString &type); + bool isRoamingAllowed(const QString &context); +protected: + bool requiresPolling() const; +}; + + +QT_END_NAMESPACE + +#endif // QT_NO_DBUS +#endif // QT_NO_BEARERMANAGEMENT + +#endif + diff --git a/src/plugins/bearer/connman/qconnmanservice_linux.cpp b/src/plugins/bearer/connman/qconnmanservice_linux.cpp new file mode 100644 index 0000000..952a444 --- /dev/null +++ b/src/plugins/bearer/connman/qconnmanservice_linux.cpp @@ -0,0 +1,1164 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QObject> +#include <QList> +#include <QtDBus/QtDBus> +#include <QtDBus/QDBusConnection> +#include <QtDBus/QDBusError> +#include <QtDBus/QDBusInterface> +#include <QtDBus/QDBusMessage> +#include <QtDBus/QDBusReply> +#include <QtDBus/QDBusPendingCallWatcher> +#include <QtDBus/QDBusObjectPath> +#include <QtDBus/QDBusPendingCall> + +#include "qconnmanservice_linux_p.h" + +#ifndef QT_NO_BEARERMANAGEMENT +#ifndef QT_NO_DBUS + +QT_BEGIN_NAMESPACE +static QDBusConnection dbusConnection = QDBusConnection::systemBus(); + + +QConnmanManagerInterface::QConnmanManagerInterface( QObject *parent) + : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), + QLatin1String(CONNMAN_MANAGER_PATH), + CONNMAN_MANAGER_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QConnmanManagerInterface::~QConnmanManagerInterface() +{ +} + +void QConnmanManagerInterface::connectNotify(const char *signal) +{ +if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + if(!connection().connect(QLatin1String(CONNMAN_SERVICE), + QLatin1String(CONNMAN_MANAGER_PATH), + QLatin1String(CONNMAN_MANAGER_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(const QString &, const QDBusVariant & )))) { + qWarning() << "PropertyCHanged not connected"; + } + } + + if (QLatin1String(signal) == SIGNAL(stateChanged(QString))) { + if (!connection().connect(QLatin1String(CONNMAN_SERVICE), + QLatin1String(CONNMAN_MANAGER_PATH), + QLatin1String(CONNMAN_MANAGER_INTERFACE), + QLatin1String("StateChanged"), + this,SIGNAL(stateChanged(const QString&)))) { + qWarning() << "StateChanged not connected"; + + } + } + if (QLatin1String(signal) == SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))) { + QConnmanDBusHelper *helper; + helper = new QConnmanDBusHelper(this); + + dbusConnection.connect(QLatin1String(CONNMAN_SERVICE), + QLatin1String(CONNMAN_MANAGER_PATH), + QLatin1String(CONNMAN_MANAGER_INTERFACE), + QLatin1String("PropertyChanged"), + helper,SLOT(propertyChanged(QString,QDBusVariant))); + + + QObject::connect(helper,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), + this,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), Qt::UniqueConnection); + } +} + +void QConnmanManagerInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QVariant))) { + + } +} + +QVariant QConnmanManagerInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) { + var = map.value(property); + } else { + qDebug() << "does not contain" << property; + } + return var; +} + +QVariantMap QConnmanManagerInterface::getProperties() +{ + if(this->isValid()) { + QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); + return reply.value(); + } else return QVariantMap(); +} + +QString QConnmanManagerInterface::getState() +{ + QDBusReply<QString > reply = this->call("GetState"); + return reply.value(); +} + +bool QConnmanManagerInterface::setProperty(const QString &name, const QDBusVariant &value) +{ + Q_UNUSED(name); + Q_UNUSED(value); + return false; +} + +QDBusObjectPath QConnmanManagerInterface::createProfile(const QString &/*name*/) +{ + return QDBusObjectPath(); +} + +bool QConnmanManagerInterface::removeProfile(QDBusObjectPath /*path*/) +{ + return false; +} + +bool QConnmanManagerInterface::requestScan(const QString &type) +{ + QDBusReply<QString> reply = this->call(QLatin1String("RequestScan"), QVariant::fromValue(type)); + + bool ok = true; + if(reply.error().type() == QDBusError::InvalidArgs) { + qWarning() << reply.error().message(); + ok = false; + } + return ok; +} + +bool QConnmanManagerInterface::enableTechnology(const QString &type) +{ + QDBusReply<QList<QDBusObjectPath> > reply = this->call(QLatin1String("EnableTechnology"), QVariant::fromValue(type)); + bool ok = true; + if(reply.error().type() == QDBusError::InvalidArgs) { + qWarning() << reply.error().message(); + ok = false; + } + return ok; +} + +bool QConnmanManagerInterface::disableTechnology(const QString &type) +{ + QDBusReply<QList<QDBusObjectPath> > reply = this->call(QLatin1String("DisableTechnology"), QVariant::fromValue(type)); + bool ok = true; + if(reply.error().type() == QDBusError::InvalidArgs) { + qWarning() << reply.error().message(); + ok = false; + } + return ok; +} + +QDBusObjectPath QConnmanManagerInterface::connectService(QVariantMap &map) +{ + QDBusReply<QDBusObjectPath > reply = this->call(QLatin1String("ConnectService"), QVariant::fromValue(map)); + if(!reply.isValid()) { + qDebug() << reply.error().message(); + + } + return reply; +} + +void QConnmanManagerInterface::registerAgent(QDBusObjectPath &/*path*/) +{ +} + +void QConnmanManagerInterface::unregisterAgent(QDBusObjectPath /*path*/) +{ +} + +void QConnmanManagerInterface::registerCounter(const QString &path, quint32 interval) +{ QDBusReply<QList<QDBusObjectPath> > reply = this->call(QLatin1String("RegisterCounter"), + QVariant::fromValue(path), + QVariant::fromValue(interval)); + bool ok = true; + if(reply.error().type() == QDBusError::InvalidArgs) { + qWarning() << reply.error().message(); + } +} + +void QConnmanManagerInterface::unregisterCounter(const QString &path) +{ QDBusReply<QList<QDBusObjectPath> > reply = this->call(QLatin1String("UnregisterCounter"), + QVariant::fromValue(path)); + bool ok = true; + if(reply.error().type() == QDBusError::InvalidArgs) { + qWarning() << reply.error().message(); + } +} + +QString QConnmanManagerInterface::requestSession(const QString &bearerName) +{ + QDBusReply<QList<QDBusObjectPath> > reply = this->call(QLatin1String("RequestSession"), + QVariant::fromValue(bearerName)); + return QString(); +} + +void QConnmanManagerInterface::releaseSession() +{ + QDBusReply<QList<QDBusObjectPath> > reply = this->call(QLatin1String("ReleaseSession")); +} + + +QDBusObjectPath QConnmanManagerInterface::lookupService(const QString &service) +{ + QDBusReply<QDBusObjectPath > reply = this->call(QLatin1String("LookupService"), QVariant::fromValue(service)); + if(!reply.isValid()) { + qDebug() << reply.error().message(); + } + return reply; +} + +// properties + +QStringList QConnmanManagerInterface::getAvailableTechnologies() +{ + QVariant var = getProperty("AvailableTechnologies"); + return qdbus_cast<QStringList>(var); +} + +QStringList QConnmanManagerInterface::getEnabledTechnologies() +{ + QVariant var = getProperty("EnabledTechnologies"); + return qdbus_cast<QStringList>(var); +} + +QStringList QConnmanManagerInterface::getConnectedTechnologies() +{ + QVariant var = getProperty("ConnectedTechnologies"); + return qdbus_cast<QStringList>(var); +} + +QString QConnmanManagerInterface::getDefaultTechnology() +{ + QVariant var = getProperty("DefaultTechnology"); + return qdbus_cast<QString>(var); +} + +bool QConnmanManagerInterface::getOfflineMode() +{ + QVariant var = getProperty("OfflineMode"); + return qdbus_cast<bool>(var); +} + +QString QConnmanManagerInterface::getActiveProfile() +{ + QVariant var = getProperty("ActiveProfile"); + return qdbus_cast<QString>(var); +} + +QStringList QConnmanManagerInterface::getProfiles() +{ + QVariant var = getProperty("Profiles"); + return qdbus_cast<QStringList>(var); +} + +QStringList QConnmanManagerInterface::getTechnologies() +{ + QVariant var = getProperty("Technologies"); + return qdbus_cast<QStringList >(var); +} + +QStringList QConnmanManagerInterface::getServices() +{ + QVariant var = getProperty("Services"); + return qdbus_cast<QStringList >(var); +} + +QString QConnmanManagerInterface::getPathForTechnology(const QString &name) +{ + foreach(const QString path, getTechnologies()) { + if(path.contains(name)) { + return path; + } + } + return ""; +} + +QConnmanNetworkInterface::QConnmanNetworkInterface(const QString &dbusPathName, QObject *parent) + : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), + dbusPathName, + CONNMAN_NETWORK_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QConnmanNetworkInterface::~QConnmanNetworkInterface() +{ +} + +void QConnmanNetworkInterface::connectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + if(!connection().connect(QLatin1String(CONNMAN_SERVICE), + this->path(), + QLatin1String(CONNMAN_NETWORK_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(QString,QDBusVariant)))) { + qWarning() << "network properties not connected"; + } + } + if (QLatin1String(signal) == SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))) { + QConnmanDBusHelper *helper; + helper = new QConnmanDBusHelper(this); + + dbusConnection.connect(QLatin1String(CONNMAN_SERVICE), + this->path(), + QLatin1String(CONNMAN_NETWORK_INTERFACE), + QLatin1String("PropertyChanged"), + helper,SLOT(propertyChanged(QString,QDBusVariant))); + + QObject::connect(helper,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), + this,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), Qt::UniqueConnection); + } +} + +void QConnmanNetworkInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + + } +} + +QVariantMap QConnmanNetworkInterface::getProperties() +{ + QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); + return reply.value(); +} + +QVariant QConnmanNetworkInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) { + var = map.value(property); + } + return var; +} + +//properties + +QString QConnmanNetworkInterface::getAddress() +{ + QVariant var = getProperty("Address"); + return qdbus_cast<QString>(var); +} + +QString QConnmanNetworkInterface::getName() +{ + QVariant var = getProperty("Name"); + return qdbus_cast<QString>(var); +} + +bool QConnmanNetworkInterface::isConnected() +{ + QVariant var = getProperty("Connected"); + return qdbus_cast<bool>(var); +} + +quint8 QConnmanNetworkInterface::getSignalStrength() +{ + QVariant var = getProperty("Strength"); + return qdbus_cast<quint8>(var); +} + +QString QConnmanNetworkInterface::getDevice() +{ + QVariant var = getProperty("Device"); + return qdbus_cast<QString>(var); +} + +QString QConnmanNetworkInterface::getWifiSsid() +{ + QVariant var = getProperty("WiFi.SSID"); + return qdbus_cast<QString>(var); +} + +QString QConnmanNetworkInterface::getWifiMode() +{ + QVariant var = getProperty("WiFi.Mode"); + return qdbus_cast<QString>(var); +} + +QString QConnmanNetworkInterface::getWifiSecurity() +{ + QVariant var = getProperty("WiFi.Security"); + return qdbus_cast<QString>(var); +} + +QString QConnmanNetworkInterface::getWifiPassphrase() +{ + QVariant var = getProperty("WiFi.Passphrase"); + return qdbus_cast<QString>(var); +} + + +////////////////////////// + +QConnmanProfileInterface::QConnmanProfileInterface(const QString &dbusPathName,QObject *parent) + : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), + dbusPathName, + CONNMAN_PROFILE_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QConnmanProfileInterface::~QConnmanProfileInterface() +{ +} + +void QConnmanProfileInterface::connectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + dbusConnection.connect(QLatin1String(CONNMAN_SERVICE), + this->path(), + QLatin1String(CONNMAN_PROFILE_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(QString,QDBusVariant))); + } +} + +void QConnmanProfileInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString, QVariant))) { + + } +} + +QVariantMap QConnmanProfileInterface::getProperties() +{ + QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); + return reply.value(); +} + +QVariant QConnmanProfileInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) { + var = map.value(property); + } + return var; +} + +// properties +QString QConnmanProfileInterface::getName() +{ + + QVariant var = getProperty("Name"); + return qdbus_cast<QString>(var); +} + +bool QConnmanProfileInterface::isOfflineMode() +{ + QVariant var = getProperty("OfflineMode"); + return qdbus_cast<bool>(var); +} + +QStringList QConnmanProfileInterface::getServices() +{ + QVariant var = getProperty("Services"); + return qdbus_cast<QStringList>(var); +} + +/////////////////////////// +QConnmanServiceInterface::QConnmanServiceInterface(const QString &dbusPathName,QObject *parent) + : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), + dbusPathName, + CONNMAN_SERVICE_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QConnmanServiceInterface::~QConnmanServiceInterface() +{ +} + +void QConnmanServiceInterface::connectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + dbusConnection.connect(QLatin1String(CONNMAN_SERVICE), + this->path(), + QLatin1String(CONNMAN_SERVICE_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(QString,QDBusVariant))); + } + if (QLatin1String(signal) == SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))) { + QConnmanDBusHelper *helper; + helper = new QConnmanDBusHelper(this); + + dbusConnection.connect(QLatin1String(CONNMAN_SERVICE), + this->path(), + QLatin1String(CONNMAN_SERVICE_INTERFACE), + QLatin1String("PropertyChanged"), + helper,SLOT(propertyChanged(QString,QDBusVariant))); + + QObject::connect(helper,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), + this,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), Qt::UniqueConnection); + } +} + +void QConnmanServiceInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QVariant))) { + + } +} + +QVariantMap QConnmanServiceInterface::getProperties() +{ + if(this->isValid()) { + QDBusReply<QVariantMap> reply = this->call(QLatin1String("GetProperties")); + return reply.value(); + } + else + return QVariantMap(); +} + +QVariant QConnmanServiceInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) { + var = map.value(property); + } + return var; +} + +void QConnmanServiceInterface::connect() +{ + this->asyncCall(QLatin1String("Connect")); +} + +void QConnmanServiceInterface::disconnect() +{ + QDBusReply<QVariantMap> reply = this->call(QLatin1String("Disconnect")); +} + +void QConnmanServiceInterface::remove() +{ + QDBusReply<QVariantMap> reply = this->call(QLatin1String("Remove")); +} + +// void moveBefore(QDBusObjectPath &service); +// void moveAfter(QDBusObjectPath &service); + +// properties +QString QConnmanServiceInterface::getState() +{ + QVariant var = getProperty("State"); + return qdbus_cast<QString>(var); +} + +QString QConnmanServiceInterface::getError() +{ + QVariant var = getProperty("Error"); + return qdbus_cast<QString>(var); +} + +QString QConnmanServiceInterface::getName() +{ + QVariant var = getProperty("Name"); + return qdbus_cast<QString>(var); +} + +QString QConnmanServiceInterface::getType() +{ + QVariant var = getProperty("Type"); + return qdbus_cast<QString>(var); +} + +QString QConnmanServiceInterface::getMode() +{ + QVariant var = getProperty("Mode"); + return qdbus_cast<QString>(var); +} + +QString QConnmanServiceInterface::getSecurity() +{ + QVariant var = getProperty("Security"); + return qdbus_cast<QString>(var); +} + +QString QConnmanServiceInterface::getPassphrase() +{ + QVariant var = getProperty("Passphrase"); + return qdbus_cast<QString>(var); +} + +bool QConnmanServiceInterface::isPassphraseRequired() +{ + QVariant var = getProperty("PassphraseRequired"); + return qdbus_cast<bool>(var); +} + +quint8 QConnmanServiceInterface::getSignalStrength() +{ + QVariant var = getProperty("Strength"); + return qdbus_cast<quint8>(var); +} + +bool QConnmanServiceInterface::isFavorite() +{ + QVariant var = getProperty("Favorite"); + return qdbus_cast<bool>(var); +} + +bool QConnmanServiceInterface::isImmutable() +{ + QVariant var = getProperty("Immutable"); + return qdbus_cast<bool>(var); +} + +bool QConnmanServiceInterface::isAutoConnect() +{ + QVariant var = getProperty("AutoConnect"); + return qdbus_cast<bool>(var); +} + +bool QConnmanServiceInterface::isSetupRequired() +{ + QVariant var = getProperty("SetupRequired"); + return qdbus_cast<bool>(var); +} + +QString QConnmanServiceInterface::getAPN() +{ + QVariant var = getProperty("APN"); + return qdbus_cast<QString>(var); +} + +QString QConnmanServiceInterface::getMCC() +{ + QVariant var = getProperty("MCC"); + return qdbus_cast<QString>(var); +} + +QString QConnmanServiceInterface::getMNC() +{ + QVariant var = getProperty("MNC"); + return qdbus_cast<QString>(var); +} + +bool QConnmanServiceInterface::isRoaming() +{ + QVariant var = getProperty("Roaming"); + return qdbus_cast<bool>(var); +} + +QStringList QConnmanServiceInterface::getNameservers() +{ + QVariant var = getProperty("NameServers"); + return qdbus_cast<QStringList>(var); +} + +QStringList QConnmanServiceInterface::getDomains() +{ + QVariant var = getProperty("Domains"); + return qdbus_cast<QStringList>(var); +} + +QVariantMap QConnmanServiceInterface::getIPv4() +{ + QVariant var = getProperty("IPv4"); + return qdbus_cast<QVariantMap >(var); +} + +QVariantMap QConnmanServiceInterface::getIPv4Configuration() +{ + QVariant var = getProperty("IPv4.Configuration"); + return qdbus_cast<QVariantMap >(var); +} + +QVariantMap QConnmanServiceInterface::getProxy() +{ + QVariant var = getProperty("Proxy"); + return qdbus_cast<QVariantMap >(var); +} + +QVariantMap QConnmanServiceInterface::getEthernet() +{ + QVariant var = getProperty("Ethernet"); + return qdbus_cast<QVariantMap >(var); +} + +QString QConnmanServiceInterface::getMethod() +{ + QVariant var; + QVariantMap map = getEthernet(); + QMapIterator<QString,QVariant> it(map); + while(it.hasNext()) { + it.next(); + if(it.key() == "Method") { + return it.value().toString(); + } + } + return QString(); +} + +QString QConnmanServiceInterface::getInterface() +{ + QVariant var; + QVariantMap map = getEthernet(); + + QMapIterator<QString,QVariant> it(map); + while(it.hasNext()) { + it.next(); + if(it.key() == "Interface") { + return it.value().toString(); + } + } + + return QString(); +} + +QString QConnmanServiceInterface::getMacAddress() +{ + QVariant var; + QVariantMap map = getEthernet(); + + QMapIterator<QString,QVariant> it(map); + while(it.hasNext()) { + it.next(); + if(it.key() == "Address") { + return it.value().toString(); + } + } + return QString(); +} + +quint16 QConnmanServiceInterface::getMtu() +{ + quint16 mtu=0; + QVariant var; + QVariantMap map = getEthernet(); + + QMapIterator<QString,QVariant> it(map); + while(it.hasNext()) { + it.next(); + if(it.key() == "MTU") { + return it.value().toUInt(); + } + } + return mtu; +} + +quint16 QConnmanServiceInterface::getSpeed() +{ + quint16 speed=0; + QVariant var; + QVariantMap map = getEthernet(); + + QMapIterator<QString,QVariant> it(map); + while(it.hasNext()) { + it.next(); + if(it.key() == "Speed") { + return it.value().toUInt(); + } + } + return speed; +} + +QString QConnmanServiceInterface::getDuplex() +{ + QVariant var; + QVariantMap map = getEthernet(); + + QMapIterator<QString,QVariant> it(map); + while(it.hasNext()) { + it.next(); + if(it.key() == "Duplex") { + return it.value().toString(); + } + } + return QString(); +} + + +bool QConnmanServiceInterface::isOfflineMode() +{ + QVariant var = getProperty("OfflineMode"); + return qdbus_cast<bool>(var); +} + +QStringList QConnmanServiceInterface::getServices() +{ + QVariant var = getProperty("Services"); + return qdbus_cast<QStringList>(var); +} + + +////////////////////////// +QConnmanTechnologyInterface::QConnmanTechnologyInterface(const QString &dbusPathName,QObject *parent) + : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), + dbusPathName, + CONNMAN_TECHNOLOGY_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QConnmanTechnologyInterface::~QConnmanTechnologyInterface() +{ +} + +void QConnmanTechnologyInterface::connectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + dbusConnection.connect(QLatin1String(CONNMAN_SERVICE), + this->path(), + QLatin1String(CONNMAN_TECHNOLOGY_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(QString,QDBusVariant))); + } + if (QLatin1String(signal) == SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))) { + QConnmanDBusHelper *helper; + helper = new QConnmanDBusHelper(this); + + dbusConnection.connect(QLatin1String(CONNMAN_SERVICE), + this->path(), + QLatin1String(CONNMAN_TECHNOLOGY_INTERFACE), + QLatin1String("PropertyChanged"), + helper,SLOT(propertyChanged(QString,QDBusVariant))); + + QObject::connect(helper,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), + this,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), Qt::UniqueConnection); + } +} + +void QConnmanTechnologyInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QVariant))) { + + } +} + +QVariantMap QConnmanTechnologyInterface::getProperties() +{ + QDBusReply<QVariantMap> reply = this->call(QLatin1String("GetProperties")); + return reply.value(); +} + +QVariant QConnmanTechnologyInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) { + var = map.value(property); + } + return var; +} + +// properties +QString QConnmanTechnologyInterface::getState() +{ + QVariant var = getProperty("State"); + return qdbus_cast<QString>(var); +} + +QString QConnmanTechnologyInterface::getName() +{ + QVariant var = getProperty("Name"); + return qdbus_cast<QString>(var); +} + +QString QConnmanTechnologyInterface::getType() +{ + QVariant var = getProperty("Type"); + return qdbus_cast<QString>(var); +} + + +QStringList QConnmanTechnologyInterface::getDevices() +{ + QVariant var = getProperty("Devices"); + return qdbus_cast<QStringList>(var); +} + + +////////////////////////////////// +QConnmanAgentInterface::QConnmanAgentInterface(const QString &dbusPathName, QObject *parent) + : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), + dbusPathName, + CONNMAN_AGENT_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QConnmanAgentInterface::~QConnmanAgentInterface() +{ +} + +void QConnmanAgentInterface::connectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { +// dbusConnection.connect(QLatin1String(CONNMAN_SERVICE), +// this->path(), +// QLatin1String(CONNMAN_NETWORK_INTERFACE), +// QLatin1String("PropertyChanged"), +// this,SIGNAL(propertyChanged(const QString &, QVariant &))); + } +} + +void QConnmanAgentInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString, QDBusVariant))) { + + } +} + + +void QConnmanAgentInterface::release() +{ +} + +void QConnmanAgentInterface::reportError(QDBusObjectPath &/*path*/, const QString &/*error*/) +{ +} + +//dict QConnmanAgentInterface::requestInput(QDBusObjectPath &path, dict fields) +//{ +//} + +void QConnmanAgentInterface::cancel() +{ +} + + +///////////////////////////////////////// +QConnmanCounterInterface::QConnmanCounterInterface(const QString &dbusPathName,QObject *parent) + : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), + dbusPathName, + CONNMAN_COUNTER_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QConnmanCounterInterface::~QConnmanCounterInterface() +{ +} + +quint32 QConnmanCounterInterface::getReceivedByteCount() +{ + return 0; +} + +quint32 QConnmanCounterInterface::getTransmittedByteCount() +{ + return 0; +} + +quint64 QConnmanCounterInterface::getTimeOnline() +{ + return 0; +} + +///////////////////////////////////////// +QConnmanDeviceInterface::QConnmanDeviceInterface(const QString &dbusPathName,QObject *parent) + : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), + dbusPathName, + CONNMAN_DEVICE_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QConnmanDeviceInterface::~QConnmanDeviceInterface() +{ +} + +void QConnmanDeviceInterface::connectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + dbusConnection.connect(QLatin1String(CONNMAN_SERVICE), + this->path(), + QLatin1String(CONNMAN_DEVICE_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(QString,QDBusVariant))); + + } + if (QLatin1String(signal) == SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))) { + QConnmanDBusHelper *helper; + helper = new QConnmanDBusHelper(this); + + dbusConnection.connect(QLatin1String(CONNMAN_SERVICE), + this->path(), + QLatin1String(CONNMAN_DEVICE_INTERFACE), + QLatin1String("PropertyChanged"), + helper,SLOT(propertyChanged(QString,QDBusVariant))); + + QObject::connect(helper,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), + this,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), Qt::UniqueConnection); + } +} + +void QConnmanDeviceInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QVariant))) { + + } +} + +QVariantMap QConnmanDeviceInterface::getProperties() +{ + QDBusReply<QVariantMap> reply = this->call(QLatin1String("GetProperties")); + return reply.value(); +} + +bool QConnmanDeviceInterface::setProperty(const QString &name, const QDBusVariant &value) +{ + QDBusMessage reply = this->call(QLatin1String("SetProperty"),name, qVariantFromValue(value)); + return true; +} + +void QConnmanDeviceInterface::scan() +{ + QDBusReply<QVariantMap> reply = this->call(QLatin1String("ProposeScan")); + if(!reply.isValid()) { + qDebug() << reply.error().message(); + } +} + +QVariant QConnmanDeviceInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) { + var = map.value(property); + } + return var; +} + +//properties +QString QConnmanDeviceInterface::getAddress() +{ + QVariant var = getProperty("Address"); + return qdbus_cast<QString>(var); +} + +QString QConnmanDeviceInterface::getName() +{ + QVariant var = getProperty("Name"); + return qdbus_cast<QString>(var); +} + +QString QConnmanDeviceInterface::getType() +{ + QVariant var = getProperty("Type"); + return qdbus_cast<QString>(var); +} + +QString QConnmanDeviceInterface::getInterface() +{ + QVariant var = getProperty("Interface"); + return qdbus_cast<QString>(var); +} + +bool QConnmanDeviceInterface::isPowered() +{ + QVariant var = getProperty("Powered"); + return qdbus_cast<bool>(var); +} + +quint16 QConnmanDeviceInterface::getScanInterval() +{ + QVariant var = getProperty("ScanInterval"); + return qdbus_cast<quint16>(var); +} + +bool QConnmanDeviceInterface::setScanInterval(const QString & interval) +{ +// QList<QVariant> args; +// args << qVariantFromValue(name) +// << value.variant(); + +// QDBusMessage reply = this->callWithArgumentList(QDBus::AutoDetect,QLatin1String("SetProperty"),args); + + return setProperty("ScanInterval", QDBusVariant(interval)); +} + +bool QConnmanDeviceInterface::isScanning() +{ + QVariant var = getProperty("Scanning"); + return qdbus_cast<bool>(var); +} + +QStringList QConnmanDeviceInterface::getNetworks() +{ + QVariant var = getProperty("Networks"); + return qdbus_cast<QStringList>(var); +} + +bool QConnmanDeviceInterface::setEnabled(bool powered) +{ + QList<QVariant> args; + args << qVariantFromValue(QString("Powered")) + << qVariantFromValue(QDBusVariant(powered)); + + QDBusMessage reply = this->callWithArgumentList(QDBus::AutoDetect,QLatin1String("SetProperty"),args); + return true; +} + +QConnmanDBusHelper::QConnmanDBusHelper(QObject * parent) + : QObject(parent) +{ +} + +QConnmanDBusHelper::~QConnmanDBusHelper() +{ +} + +void QConnmanDBusHelper::propertyChanged(const QString &item, const QDBusVariant &var) +{ + QDBusMessage msg = this->message(); + Q_EMIT propertyChangedContext(msg.path() ,item, var); +} + +///////////////// +QT_END_NAMESPACE + +#endif // QT_NO_DBUS +#endif // QT_NO_BEARERMANAGEMENT + diff --git a/src/plugins/bearer/connman/qconnmanservice_linux_p.h b/src/plugins/bearer/connman/qconnmanservice_linux_p.h new file mode 100644 index 0000000..6e6b702 --- /dev/null +++ b/src/plugins/bearer/connman/qconnmanservice_linux_p.h @@ -0,0 +1,395 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCONNMANSERVICE_H +#define QCONNMANSERVICE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtDBus/QtDBus> +#include <QtDBus/QDBusConnection> +#include <QtDBus/QDBusError> +#include <QtDBus/QDBusInterface> +#include <QtDBus/QDBusMessage> +#include <QtDBus/QDBusReply> + +#include <QtDBus/QDBusPendingCallWatcher> +#include <QtDBus/QDBusObjectPath> +#include <QtDBus/QDBusContext> +#include <QMap> + +#ifndef QT_NO_BEARERMANAGEMENT +#ifndef QT_NO_DBUS + +#ifndef __CONNMAN_DBUS_H + +#define CONNMAN_SERVICE "org.moblin.connman" +#define CONNMAN_PATH "/org/moblin/connman" + +#define CONNMAN_DEBUG_INTERFACE CONNMAN_SERVICE ".Debug" +#define CONNMAN_ERROR_INTERFACE CONNMAN_SERVICE ".Error" +#define CONNMAN_AGENT_INTERFACE CONNMAN_SERVICE ".Agent" +#define CONNMAN_COUNTER_INTERFACE CONNMAN_SERVICE ".Counter" + +#define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager" +#define CONNMAN_MANAGER_PATH "/" + +#define CONNMAN_TASK_INTERFACE CONNMAN_SERVICE ".Task" +#define CONNMAN_PROFILE_INTERFACE CONNMAN_SERVICE ".Profile" +#define CONNMAN_SERVICE_INTERFACE CONNMAN_SERVICE ".Service" +#define CONNMAN_DEVICE_INTERFACE CONNMAN_SERVICE ".Device" +#define CONNMAN_NETWORK_INTERFACE CONNMAN_SERVICE ".Network" +#define CONNMAN_PROVIDER_INTERFACE CONNMAN_SERVICE ".Provider" +#define CONNMAN_TECHNOLOGY_INTERFACE CONNMAN_SERVICE ".Technology" +#endif + +QT_BEGIN_NAMESPACE + +QT_END_NAMESPACE + + +QT_BEGIN_NAMESPACE + +class QConnmanManagerInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QConnmanManagerInterface( QObject *parent = 0); + ~QConnmanManagerInterface(); + + QDBusObjectPath path() const; + + QVariantMap getProperties(); + bool setProperty(const QString &name, const QDBusVariant &value); + QDBusObjectPath createProfile(const QString &name); + bool removeProfile(QDBusObjectPath path); + bool requestScan(const QString &type); + bool enableTechnology(const QString &type); + bool disableTechnology(const QString &type); + QDBusObjectPath connectService(QVariantMap &map); + void registerAgent(QDBusObjectPath &path); + void unregisterAgent(QDBusObjectPath path); + void registerCounter(const QString &path, quint32 interval); + void unregisterCounter(const QString &path); + + QString requestSession(const QString &bearerName); + void releaseSession(); + + // properties + QString getState(); + QStringList getAvailableTechnologies(); + QStringList getEnabledTechnologies(); + QStringList getConnectedTechnologies(); + QString getDefaultTechnology(); + bool getOfflineMode(); + QString getActiveProfile(); + QStringList getProfiles(); + QStringList getTechnologies(); + QStringList getServices(); + QDBusObjectPath lookupService(const QString &); + + QString getPathForTechnology(const QString &tech); + + +Q_SIGNALS: + void propertyChanged(const QString &, const QDBusVariant &value); + void stateChanged(const QString &); + void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); + +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); +}; + + +class QConnmanNetworkInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QConnmanNetworkInterface(const QString &dbusPathName, QObject *parent = 0); + ~QConnmanNetworkInterface(); + + QVariantMap getProperties(); + + //properties + QString getAddress(); + QString getName(); + bool isConnected(); + quint8 getSignalStrength(); + QString getDevice(); + QString getWifiSsid(); + QString getWifiMode(); + QString getWifiSecurity(); + QString getWifiPassphrase(); + +Q_SIGNALS: + void propertyChanged(const QString &, const QDBusVariant &value); + void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); +}; + +class QConnmanProfileInterfacePrivate; +class QConnmanProfileInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QConnmanProfileInterface(const QString &dbusPathName,QObject *parent = 0); + ~QConnmanProfileInterface(); + + QVariantMap getProperties(); +// properties + QString getName(); + bool isOfflineMode(); + QStringList getServices(); + +Q_SIGNALS: + void propertyChanged(const QString &, const QDBusVariant &value); +private: + QConnmanProfileInterfacePrivate *d; + +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); +}; + +class QConnmanServiceInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QConnmanServiceInterface(const QString &dbusPathName,QObject *parent = 0); + ~QConnmanServiceInterface(); + + QVariantMap getProperties(); + // clearProperty + void connect(); + void disconnect(); + void remove(); + // void moveBefore(QDBusObjectPath &service); + // void moveAfter(QDBusObjectPath &service); + +// properties + QString getState(); + QString getError(); + QString getName(); + QString getType(); + QString getMode(); + QString getSecurity(); + QString getPassphrase(); + bool isPassphraseRequired(); + quint8 getSignalStrength(); + bool isFavorite(); + bool isImmutable(); + bool isAutoConnect(); + bool isSetupRequired(); + QString getAPN(); + QString getMCC(); + QString getMNC(); + bool isRoaming(); + QStringList getNameservers(); + QStringList getDomains(); + QVariantMap getIPv4(); + QVariantMap getIPv4Configuration(); + QVariantMap getProxy(); + QVariantMap getEthernet(); + + QString getMethod(); + QString getInterface(); + QString getMacAddress(); + quint16 getMtu(); + quint16 getSpeed(); + QString getDuplex(); + + bool isOfflineMode(); + QStringList getServices(); + +Q_SIGNALS: + void propertyChanged(const QString &, const QDBusVariant &value); + void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); + +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); +}; + +class QConnmanTechnologyInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QConnmanTechnologyInterface(const QString &dbusPathName,QObject *parent = 0); + ~QConnmanTechnologyInterface(); + + QVariantMap getProperties(); +// properties + QString getState(); + QString getName(); + QString getType(); + + QStringList getDevices(); + +Q_SIGNALS: + void propertyChanged(const QString &, const QDBusVariant &value); + void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); + +}; + +class QConnmanAgentInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QConnmanAgentInterface(const QString &dbusPathName,QObject *parent = 0); + ~QConnmanAgentInterface(); + + void release(); + void reportError(QDBusObjectPath &path, const QString &error); +// dict requestInput(QDBusObjectPath &path, dict fields); + void cancel(); +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); +}; + +class QConnmanCounterInterfacePrivate; +class QConnmanCounterInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QConnmanCounterInterface(const QString &dbusPathName, QObject *parent = 0); + ~QConnmanCounterInterface(); + +// void release(); + QString getInterface(); + quint32 getReceivedByteCount(); + quint32 getTransmittedByteCount(); + quint64 getTimeOnline(); + +private: + QConnmanCounterInterfacePrivate *d; +}; + +class QConnmanDeviceInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QConnmanDeviceInterface(const QString &dbusPathName,QObject *parent = 0); + ~QConnmanDeviceInterface(); + + QVariantMap getProperties(); + void scan(); + +//properties + QString getAddress(); + QString getName(); + QString getType(); + QString getInterface(); + bool isPowered(); + quint16 getScanInterval(); + bool setScanInterval(const QString &interval); + + bool isScanning(); + QStringList getNetworks(); + bool setEnabled(bool powered); + bool setProperty(const QString &name, const QDBusVariant &value); + +Q_SIGNALS: + void propertyChanged(const QString &, const QDBusVariant &value); + void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); + +}; + +class QConnmanDBusHelper: public QObject, protected QDBusContext + { + Q_OBJECT + public: + QConnmanDBusHelper(QObject *parent = 0); + ~QConnmanDBusHelper(); + + public slots: + void propertyChanged(const QString &, const QDBusVariant &); + +Q_SIGNALS: + void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_DBUS +#endif // QT_NO_BEARERMANAGEMENT + +#endif //QCONNMANSERVICE_H diff --git a/src/plugins/bearer/connman/qofonoservice_linux.cpp b/src/plugins/bearer/connman/qofonoservice_linux.cpp new file mode 100644 index 0000000..52f596b --- /dev/null +++ b/src/plugins/bearer/connman/qofonoservice_linux.cpp @@ -0,0 +1,940 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QObject> +#include <QList> +#include <QtDBus/QtDBus> +#include <QtDBus/QDBusConnection> +#include <QtDBus/QDBusError> +#include <QtDBus/QDBusInterface> +#include <QtDBus/QDBusMessage> +#include <QtDBus/QDBusReply> +#include <QtDBus/QDBusPendingCallWatcher> +#include <QtDBus/QDBusObjectPath> +#include <QtDBus/QDBusPendingCall> + +#include "qofonoservice_linux_p.h" + + +QT_BEGIN_NAMESPACE +static QDBusConnection dbusConnection = QDBusConnection::systemBus(); + + +QOfonoManagerInterface::QOfonoManagerInterface( QObject *parent) + : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), + QLatin1String(OFONO_MANAGER_PATH), + OFONO_MANAGER_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QOfonoManagerInterface::~QOfonoManagerInterface() +{ +} + +QList <QDBusObjectPath> QOfonoManagerInterface::getModems() +{ + QVariant var = getProperty("Modems"); + return qdbus_cast<QList<QDBusObjectPath> >(var); +} + +QDBusObjectPath QOfonoManagerInterface::currentModem() +{ + QList<QDBusObjectPath> modems = getModems(); + foreach(const QDBusObjectPath modem, modems) { + QOfonoModemInterface device(modem.path()); + if(device.isPowered() && device.isOnline()) + return modem;; + } + return QDBusObjectPath(); +} + + +void QOfonoManagerInterface::connectNotify(const char *signal) +{ +if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + if(!connection().connect(QLatin1String(OFONO_SERVICE), + QLatin1String(OFONO_MANAGER_PATH), + QLatin1String(OFONO_MANAGER_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(const QString &, const QDBusVariant & )))) { + qWarning() << "PropertyCHanged not connected"; + } + } + + if (QLatin1String(signal) == SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))) { + QOfonoDBusHelper *helper; + helper = new QOfonoDBusHelper(this); + + dbusConnection.connect(QLatin1String(OFONO_SERVICE), + QLatin1String(OFONO_MANAGER_PATH), + QLatin1String(OFONO_MANAGER_INTERFACE), + QLatin1String("PropertyChanged"), + helper,SLOT(propertyChanged(QString,QDBusVariant))); + + + QObject::connect(helper,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), + this,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &))); + } +} + +void QOfonoManagerInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QVariant))) { + + } +} + +QVariant QOfonoManagerInterface::getProperty(const QString &property) +{ + QVariantMap map = getProperties(); + if (map.contains(property)) { + return map.value(property); + } else { + qDebug() << Q_FUNC_INFO << "does not contain" << property; + } + return QVariant(); +} + +QVariantMap QOfonoManagerInterface::getProperties() +{ + QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); + if(reply.isValid()) + return reply.value(); + else + return QVariantMap(); +} + +QOfonoDBusHelper::QOfonoDBusHelper(QObject * parent) + : QObject(parent) +{ +} + +QOfonoDBusHelper::~QOfonoDBusHelper() +{ +} + +void QOfonoDBusHelper::propertyChanged(const QString &item, const QDBusVariant &var) +{ + QDBusMessage msg = this->message(); + Q_EMIT propertyChangedContext(msg.path() ,item, var); +} + + +QOfonoModemInterface::QOfonoModemInterface(const QString &dbusPathName, QObject *parent) + : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), + dbusPathName, + OFONO_MODEM_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QOfonoModemInterface::~QOfonoModemInterface() +{ +} + +bool QOfonoModemInterface::isPowered() +{ + QVariant var = getProperty("Powered"); + return qdbus_cast<bool>(var); +} + +bool QOfonoModemInterface::isOnline() +{ + QVariant var = getProperty("Online"); + return qdbus_cast<bool>(var); +} + +QString QOfonoModemInterface::getName() +{ + QVariant var = getProperty("Name"); + return qdbus_cast<QString>(var); +} + +QString QOfonoModemInterface::getManufacturer() +{ + QVariant var = getProperty("Manufacturer"); + return qdbus_cast<QString>(var); + +} + +QString QOfonoModemInterface::getModel() +{ + + QVariant var = getProperty("Model"); + return qdbus_cast<QString>(var); +} + +QString QOfonoModemInterface::getRevision() +{ + QVariant var = getProperty("Revision"); + return qdbus_cast<QString>(var); + +} +QString QOfonoModemInterface::getSerial() +{ + QVariant var = getProperty("Serial"); + return qdbus_cast<QString>(var); + +} + +QStringList QOfonoModemInterface::getFeatures() +{ + //sms, sim + QVariant var = getProperty("Features"); + return qdbus_cast<QStringList>(var); +} + +QStringList QOfonoModemInterface::getInterfaces() +{ + QVariant var = getProperty("Interfaces"); + return qdbus_cast<QStringList>(var); +} + +QString QOfonoModemInterface::defaultInterface() +{ + foreach(const QString &modem,getInterfaces()) { + return modem; + } + return QString(); +} + + +void QOfonoModemInterface::connectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + if(!connection().connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_MODEM_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(const QString &, const QDBusVariant & )))) { + qWarning() << "PropertyCHanged not connected"; + } + } + + if (QLatin1String(signal) == SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))) { + QOfonoDBusHelper *helper; + helper = new QOfonoDBusHelper(this); + + dbusConnection.connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_MODEM_INTERFACE), + QLatin1String("PropertyChanged"), + helper,SLOT(propertyChanged(QString,QDBusVariant))); + + + QObject::connect(helper,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), + this,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), Qt::UniqueConnection); + }} + +void QOfonoModemInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QVariant))) { + + } +} + +QVariantMap QOfonoModemInterface::getProperties() +{ + QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); + return reply.value(); +} + +QVariant QOfonoModemInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) { + var = map.value(property); + } else { + qDebug() << Q_FUNC_INFO << "does not contain" << property; + } + return var; +} + + +QOfonoNetworkRegistrationInterface::QOfonoNetworkRegistrationInterface(const QString &dbusPathName, QObject *parent) + : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), + dbusPathName, + OFONO_NETWORK_REGISTRATION_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QOfonoNetworkRegistrationInterface::~QOfonoNetworkRegistrationInterface() +{ +} + +QString QOfonoNetworkRegistrationInterface::getStatus() +{ + /* + "unregistered" Not registered to any network + "registered" Registered to home network + "searching" Not registered, but searching + "denied" Registration has been denied + "unknown" Status is unknown + "roaming" Registered, but roaming*/ + QVariant var = getProperty("Status"); + return qdbus_cast<QString>(var); +} + +quint16 QOfonoNetworkRegistrationInterface::getLac() +{ + QVariant var = getProperty("LocationAreaCode"); + return var.value<quint16>(); +} + + +quint32 QOfonoNetworkRegistrationInterface::getCellId() +{ + QVariant var = getProperty("CellId"); + return var.value<quint32>(); +} + +QString QOfonoNetworkRegistrationInterface::getTechnology() +{ + // "gsm", "edge", "umts", "hspa","lte" + QVariant var = getProperty("Technology"); + return qdbus_cast<QString>(var); +} + +QString QOfonoNetworkRegistrationInterface::getOperatorName() +{ + QVariant var = getProperty("Name"); + return qdbus_cast<QString>(var); +} + +int QOfonoNetworkRegistrationInterface::getSignalStrength() +{ + QVariant var = getProperty("Strength"); + return qdbus_cast<int>(var); + +} + +QString QOfonoNetworkRegistrationInterface::getBaseStation() +{ + QVariant var = getProperty("BaseStation"); + return qdbus_cast<QString>(var); +} + +QList <QDBusObjectPath> QOfonoNetworkRegistrationInterface::getOperators() +{ + QVariant var = getProperty("Operators"); + return qdbus_cast<QList <QDBusObjectPath> >(var); +} + +void QOfonoNetworkRegistrationInterface::connectNotify(const char *signal) +{ +if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + if(!connection().connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_NETWORK_REGISTRATION_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(const QString &, const QDBusVariant & )))) { + qWarning() << "PropertyCHanged not connected"; + } + } + + if (QLatin1String(signal) == SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))) { + QOfonoDBusHelper *helper; + helper = new QOfonoDBusHelper(this); + + dbusConnection.connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_NETWORK_REGISTRATION_INTERFACE), + QLatin1String("PropertyChanged"), + helper,SLOT(propertyChanged(QString,QDBusVariant))); + + + QObject::connect(helper,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), + this,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), Qt::UniqueConnection); + } +} + +void QOfonoNetworkRegistrationInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QVariant))) { + + } +} + +QVariant QOfonoNetworkRegistrationInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) { + var = map.value(property); + } else { + qDebug() << Q_FUNC_INFO << "does not contain" << property; + } + return var; +} + +QVariantMap QOfonoNetworkRegistrationInterface::getProperties() +{ + QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); + return reply.value(); +} + + + +QOfonoNetworkOperatorInterface::QOfonoNetworkOperatorInterface(const QString &dbusPathName, QObject *parent) + : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), + dbusPathName, + OFONO_NETWORK_OPERATOR_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QOfonoNetworkOperatorInterface::~QOfonoNetworkOperatorInterface() +{ +} + +QString QOfonoNetworkOperatorInterface::getName() +{ + QVariant var = getProperty("Name"); + return qdbus_cast<QString>(var); +} + +QString QOfonoNetworkOperatorInterface::getStatus() +{ + // "unknown", "available", "current" and "forbidden" + QVariant var = getProperty("Status"); + return qdbus_cast<QString>(var); +} + +QString QOfonoNetworkOperatorInterface::getMcc() +{ + QVariant var = getProperty("MobileCountryCode"); + return qdbus_cast<QString>(var); +} + +QString QOfonoNetworkOperatorInterface::getMnc() +{ + QVariant var = getProperty("MobileNetworkCode"); + return qdbus_cast<QString>(var); +} + +QStringList QOfonoNetworkOperatorInterface::getTechnologies() +{ + QVariant var = getProperty("Technologies"); + return qdbus_cast<QStringList>(var); +} + +void QOfonoNetworkOperatorInterface::connectNotify(const char *signal) +{ +if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + if(!connection().connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_NETWORK_OPERATOR_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(const QString &, const QDBusVariant & )))) { + qWarning() << "PropertyCHanged not connected"; + } + } + + if (QLatin1String(signal) == SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))) { + QOfonoDBusHelper *helper; + helper = new QOfonoDBusHelper(this); + + dbusConnection.connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_NETWORK_OPERATOR_INTERFACE), + QLatin1String("PropertyChanged"), + helper,SLOT(propertyChanged(QString,QDBusVariant))); + + + QObject::connect(helper,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), + this,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), Qt::UniqueConnection); + } +} + +void QOfonoNetworkOperatorInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QVariant))) { + + } +} + +QVariant QOfonoNetworkOperatorInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) { + var = map.value(property); + } else { + qDebug() << Q_FUNC_INFO << "does not contain" << property; + } + return var; +} + +QVariantMap QOfonoNetworkOperatorInterface::getProperties() +{ + QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); + return reply.value(); +} + +QOfonoSimInterface::QOfonoSimInterface(const QString &dbusPathName, QObject *parent) + : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), + dbusPathName, + OFONO_SIM_MANAGER_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QOfonoSimInterface::~QOfonoSimInterface() +{ +} + +bool QOfonoSimInterface::isPresent() +{ + QVariant var = getProperty("Present"); + return qdbus_cast<bool>(var); +} + +QString QOfonoSimInterface::getHomeMcc() +{ + QVariant var = getProperty("MobileCountryCode"); + return qdbus_cast<QString>(var); +} + +QString QOfonoSimInterface::getHomeMnc() +{ + QVariant var = getProperty("MobileNetworkCode"); + return qdbus_cast<QString>(var); +} + +// QStringList subscriberNumbers(); +// QMap<QString,QString> serviceNumbers(); +QString QOfonoSimInterface::pinRequired() +{ + QVariant var = getProperty("PinRequired"); + return qdbus_cast<QString>(var); +} + +QString QOfonoSimInterface::lockedPins() +{ + QVariant var = getProperty("LockedPins"); + return qdbus_cast<QString>(var); +} + +QString QOfonoSimInterface::cardIdentifier() +{ + QVariant var = getProperty("CardIdentifier"); + return qdbus_cast<QString>(var); +} + +void QOfonoSimInterface::connectNotify(const char *signal) +{ +if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + if(!connection().connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_SIM_MANAGER_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(const QString &, const QDBusVariant & )))) { + qWarning() << "PropertyCHanged not connected"; + } + } + + if (QLatin1String(signal) == SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))) { + QOfonoDBusHelper *helper; + helper = new QOfonoDBusHelper(this); + + dbusConnection.connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_SIM_MANAGER_INTERFACE), + QLatin1String("PropertyChanged"), + helper,SLOT(propertyChanged(QString,QDBusVariant))); + + + QObject::connect(helper,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), + this,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), Qt::UniqueConnection); + } +} + +void QOfonoSimInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QVariant))) { + + } +} + +QVariant QOfonoSimInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) { + var = map.value(property); + } else { + qDebug() << Q_FUNC_INFO << "does not contain" << property; + } + return var; +} + +QVariantMap QOfonoSimInterface::getProperties() +{ + QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); + return reply.value(); +} + +QOfonoDataConnectionManagerInterface::QOfonoDataConnectionManagerInterface(const QString &dbusPathName, QObject *parent) + : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), + dbusPathName, + OFONO_DATA_CONNECTION_MANAGER_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QOfonoDataConnectionManagerInterface::~QOfonoDataConnectionManagerInterface() +{ +} + +QList<QDBusObjectPath> QOfonoDataConnectionManagerInterface::getPrimaryContexts() +{ + QVariant var = getProperty("PrimaryContexts"); + return qdbus_cast<QList<QDBusObjectPath> >(var); +} + +bool QOfonoDataConnectionManagerInterface::isAttached() +{ + QVariant var = getProperty("Attached"); + return qdbus_cast<bool>(var); +} + +bool QOfonoDataConnectionManagerInterface::isRoamingAllowed() +{ + QVariant var = getProperty("RoamingAllowed"); + return qdbus_cast<bool>(var); +} + +bool QOfonoDataConnectionManagerInterface::isPowered() +{ + QVariant var = getProperty("Powered"); + return qdbus_cast<bool>(var); +} + +void QOfonoDataConnectionManagerInterface::connectNotify(const char *signal) +{ +if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + if(!connection().connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_DATA_CONNECTION_MANAGER_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(const QString &, const QDBusVariant & )))) { + qWarning() << "PropertyCHanged not connected"; + } + } + + if (QLatin1String(signal) == SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))) { + QOfonoDBusHelper *helper; + helper = new QOfonoDBusHelper(this); + + dbusConnection.connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_DATA_CONNECTION_MANAGER_INTERFACE), + QLatin1String("PropertyChanged"), + helper,SLOT(propertyChanged(QString,QDBusVariant))); + + + QObject::connect(helper,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), + this,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), Qt::UniqueConnection); + } +} + +void QOfonoDataConnectionManagerInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QVariant))) { + + } +} + +QVariant QOfonoDataConnectionManagerInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) { + var = map.value(property); + } else { + qDebug() << Q_FUNC_INFO << "does not contain" << property; + } + return var; +} + +QVariantMap QOfonoDataConnectionManagerInterface::getProperties() +{ + QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); + return reply.value(); +} + +QOfonoPrimaryDataContextInterface::QOfonoPrimaryDataContextInterface(const QString &dbusPathName, QObject *parent) + : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), + dbusPathName, + OFONO_DATA_CONTEXT_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QOfonoPrimaryDataContextInterface::~QOfonoPrimaryDataContextInterface() +{ +} + +bool QOfonoPrimaryDataContextInterface::isActive() +{ + QVariant var = getProperty("Active"); + return qdbus_cast<bool>(var); +} + +QString QOfonoPrimaryDataContextInterface::getApName() +{ + QVariant var = getProperty("AccessPointName"); + return qdbus_cast<QString>(var); +} + +QString QOfonoPrimaryDataContextInterface::getType() +{ + QVariant var = getProperty("Type"); + return qdbus_cast<QString>(var); +} + +QString QOfonoPrimaryDataContextInterface::getName() +{ + QVariant var = getProperty("Name"); + return qdbus_cast<QString>(var); +} + +QVariantMap QOfonoPrimaryDataContextInterface::getSettings() +{ + QVariant var = getProperty("Settings"); + return qdbus_cast<QVariantMap>(var); +} + +QString QOfonoPrimaryDataContextInterface::getInterface() +{ + QVariant var = getProperty("Interface"); + return qdbus_cast<QString>(var); +} + +QString QOfonoPrimaryDataContextInterface::getAddress() +{ + QVariant var = getProperty("Address"); + return qdbus_cast<QString>(var); +} + +bool QOfonoPrimaryDataContextInterface::setActive(bool on) +{ +// this->setProperty("Active", QVariant(on)); + + return setProp("Active", qVariantFromValue(on)); +} + +bool QOfonoPrimaryDataContextInterface::setApn(const QString &name) +{ + return setProp("AccessPointName", QVariant::fromValue(name)); +} + +void QOfonoPrimaryDataContextInterface::connectNotify(const char *signal) +{ +if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + if(!connection().connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_DATA_CONTEXT_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(const QString &, const QDBusVariant & )))) { + qWarning() << "PropertyCHanged not connected"; + } + } + + if (QLatin1String(signal) == SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))) { + QOfonoDBusHelper *helper; + helper = new QOfonoDBusHelper(this); + + dbusConnection.connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_DATA_CONTEXT_INTERFACE), + QLatin1String("PropertyChanged"), + helper,SLOT(propertyChanged(QString,QDBusVariant))); + + + QObject::connect(helper,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), + this,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), Qt::UniqueConnection); + } +} + +void QOfonoPrimaryDataContextInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QVariant))) { + + } +} + +QVariant QOfonoPrimaryDataContextInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) { + var = map.value(property); + } else { + qDebug() << Q_FUNC_INFO << "does not contain" << property; + } + return var; +} + +QVariantMap QOfonoPrimaryDataContextInterface::getProperties() +{ + QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); + return reply.value(); +} + +bool QOfonoPrimaryDataContextInterface::setProp(const QString &property, const QVariant &var) +{ + QList<QVariant> args; + args << qVariantFromValue(property) << qVariantFromValue(QDBusVariant(var)); + + QDBusMessage reply = this->callWithArgumentList(QDBus::AutoDetect, + QLatin1String("SetProperty"), + args); + bool ok = true; + if(reply.type() != QDBusMessage::ReplyMessage) { + qWarning() << reply.errorMessage(); + ok = false; + } + qWarning() << reply.errorMessage(); + return ok; +} + +QOfonoSmsInterface::QOfonoSmsInterface(const QString &dbusPathName, QObject *parent) + : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), + dbusPathName, + OFONO_SMS_MANAGER_INTERFACE, + QDBusConnection::systemBus(), parent) +{ +} + +QOfonoSmsInterface::~QOfonoSmsInterface() +{ +} + +void QOfonoSmsInterface::connectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QDBusVariant))) { + if(!connection().connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_SMS_MANAGER_INTERFACE), + QLatin1String("PropertyChanged"), + this,SIGNAL(propertyChanged(const QString &, const QDBusVariant & )))) { + qWarning() << "PropertyCHanged not connected"; + } + } + + if (QLatin1String(signal) == SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))) { + QOfonoDBusHelper *helper; + helper = new QOfonoDBusHelper(this); + + dbusConnection.connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_SMS_MANAGER_INTERFACE), + QLatin1String("PropertyChanged"), + helper,SLOT(propertyChanged(QString,QDBusVariant))); + + + QObject::connect(helper,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &)), + this,SIGNAL(propertyChangedContext(const QString &,const QString &,const QDBusVariant &))); + } + + if (QLatin1String(signal) == SIGNAL(immediateMessage(QString,QVariantMap))) { + if(!connection().connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_SMS_MANAGER_INTERFACE), + QLatin1String("ImmediateMessage"), + this,SIGNAL(immediateMessage(QString,QVariantMap )))) { + qWarning() << "PropertyCHanged not connected"; + } + } + + if (QLatin1String(signal) == SIGNAL(incomingMessage(QString,QVariantMap))) { + if(!connection().connect(QLatin1String(OFONO_SERVICE), + this->path(), + QLatin1String(OFONO_SMS_MANAGER_INTERFACE), + QLatin1String("IncomingMessage"), + this,SIGNAL(incomingMessage(QString,QVariantMap)))) { + qWarning() << "PropertyCHanged not connected"; + } + } +} + +void QOfonoSmsInterface::disconnectNotify(const char *signal) +{ + if (QLatin1String(signal) == SIGNAL(propertyChanged(QString,QVariant))) { + + } +} + +QVariant QOfonoSmsInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) { + var = map.value(property); + } else { + qDebug() << Q_FUNC_INFO << "does not contain" << property; + } + return var; +} + +QVariantMap QOfonoSmsInterface::getProperties() +{ + QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); + return reply.value(); +} + +void QOfonoSmsInterface::sendMessage(const QString &to, const QString &message) +{ + QDBusReply<QString> reply = this->call(QLatin1String("SendMessage"), + QVariant::fromValue(to), + QVariant::fromValue(message)); + bool ok = true; + if(reply.error().type() == QDBusError::InvalidArgs) { + qWarning() << reply.error().message(); + ok = false; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/bearer/connman/qofonoservice_linux_p.h b/src/plugins/bearer/connman/qofonoservice_linux_p.h new file mode 100644 index 0000000..0ac1e4a --- /dev/null +++ b/src/plugins/bearer/connman/qofonoservice_linux_p.h @@ -0,0 +1,334 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOFONOSERVICE_H +#define QOFONOSERVICE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtDBus/QtDBus> +#include <QtDBus/QDBusConnection> +#include <QtDBus/QDBusError> +#include <QtDBus/QDBusInterface> +#include <QtDBus/QDBusMessage> +#include <QtDBus/QDBusReply> + +#include <QtDBus/QDBusPendingCallWatcher> +#include <QtDBus/QDBusObjectPath> +#include <QtDBus/QDBusContext> +#include <QMap> + +#define OFONO_SERVICE "org.ofono" +#define OFONO_MANAGER_INTERFACE "org.ofono.Manager" +#define OFONO_MANAGER_PATH "/" +#define OFONO_MODEM_INTERFACE "org.ofono.Modem" +#define OFONO_NETWORK_REGISTRATION_INTERFACE "org.ofono.NetworkRegistration" +#define OFONO_NETWORK_OPERATOR_INTERFACE "org.ofono.NetworkOperator" +#define OFONO_DATA_CONNECTION_MANAGER_INTERFACE "org.ofono.DataConnectionManager" +#define OFONO_SIM_MANAGER_INTERFACE "org.ofono.SimManager" +#define OFONO_DATA_CONTEXT_INTERFACE "org.ofono.PrimaryDataContext" + +#define OFONO_SMS_MANAGER_INTERFACE "org.ofono.SmsManager" +#define OFONO_PHONEBOOK_INTERFACE "org.ofono.Phonebook" +#define OFONO_MESSAGE_WAITING_INTERFACE "org.ofono.MessageWaiting" + + + +QT_BEGIN_NAMESPACE + +QT_END_NAMESPACE + + +QT_BEGIN_NAMESPACE + +class QOfonoManagerInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QOfonoManagerInterface( QObject *parent = 0); + ~QOfonoManagerInterface(); + + QDBusObjectPath path() const; + + QVariantMap getProperties(); + bool setProperty(const QString &name, const QDBusVariant &value); + QList <QDBusObjectPath> getModems(); + QDBusObjectPath currentModem(); + +Q_SIGNALS: + void propertyChanged(const QString &, const QDBusVariant &value); + void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); + +}; + + +class QOfonoDBusHelper: public QObject, protected QDBusContext + { + Q_OBJECT + public: + QOfonoDBusHelper(QObject *parent = 0); + ~QOfonoDBusHelper(); + + public slots: + void propertyChanged(const QString &, const QDBusVariant &); + Q_SIGNALS: + void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); +}; + +class QOfonoModemInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QOfonoModemInterface(const QString &dbusModemPathName, QObject *parent = 0); + ~QOfonoModemInterface(); + + QVariantMap getProperties(); + //properties + bool isPowered(); + bool isOnline(); + QString getName(); + QString getManufacturer(); + QString getModel(); + QString getRevision(); + QString getSerial(); + + QStringList getFeatures(); //sms, sim + QStringList getInterfaces(); + QString defaultInterface(); + +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); +Q_SIGNALS: + void propertyChanged(const QString &, const QDBusVariant &value); + void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); +}; + + +class QOfonoNetworkRegistrationInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QOfonoNetworkRegistrationInterface(const QString &dbusModemPathName, QObject *parent = 0); + ~QOfonoNetworkRegistrationInterface(); + + QVariantMap getProperties(); + + //properties + QString getStatus(); + quint16 getLac(); + quint32 getCellId(); + QString getTechnology(); + QString getOperatorName(); + int getSignalStrength(); + QString getBaseStation(); + QList <QDBusObjectPath> getOperators(); + +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); +Q_SIGNALS: + void propertyChanged(const QString &, const QDBusVariant &value); + void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); + +}; + +class QOfonoNetworkOperatorInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: +//modem or operator paths + QOfonoNetworkOperatorInterface(const QString &dbusPathName, QObject *parent = 0); + ~QOfonoNetworkOperatorInterface(); + + QVariantMap getProperties(); + + //properties + QString getName(); + QString getStatus();// "unknown", "available", "current" and "forbidden" + QString getMcc(); + QString getMnc(); + QStringList getTechnologies(); + +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); +}; + +class QOfonoSimInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QOfonoSimInterface(const QString &dbusModemPathName, QObject *parent = 0); + ~QOfonoSimInterface(); + + QVariantMap getProperties(); + + //properties + bool isPresent(); + QString getHomeMcc(); + QString getHomeMnc(); +// QStringList subscriberNumbers(); +// QMap<QString,QString> serviceNumbers(); + QString pinRequired(); + QString lockedPins(); + QString cardIdentifier(); + +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); +}; + + +class QOfonoDataConnectionManagerInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QOfonoDataConnectionManagerInterface(const QString &dbusPathName, QObject *parent = 0); + ~QOfonoDataConnectionManagerInterface(); + + QVariantMap getProperties(); + + //properties + QList<QDBusObjectPath> getPrimaryContexts(); + bool isAttached(); + bool isRoamingAllowed(); + bool isPowered(); + + bool setPower(bool on); + +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); +}; + + +class QOfonoPrimaryDataContextInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QOfonoPrimaryDataContextInterface(const QString &dbusPathName, QObject *parent = 0); + ~QOfonoPrimaryDataContextInterface(); + + QVariantMap getProperties(); + + //properties + bool isActive(); + QString getApName(); + QString getType(); + QString getName(); + QVariantMap getSettings(); + QString getInterface(); + QString getAddress(); + + bool setActive(bool on); + bool setApn(const QString &name); + +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); + bool setProp(const QString &, const QVariant &var); +}; + +class QOfonoSmsInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + QOfonoSmsInterface(const QString &dbusModemPathName, QObject *parent = 0); + ~QOfonoSmsInterface(); + + QVariantMap getProperties(); + void sendMessage(const QString &to, const QString &message); + + //properties + QString serviceCenterAddress(); + bool useDeliveryReports(); + QString bearer(); + +protected: + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + QVariant getProperty(const QString &); + +Q_SIGNALS: + void propertyChanged(const QString &, const QDBusVariant &value); + void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); + void immediateMessage(const QString &message, const QVariantMap &info); + void incomingMessage(const QString &message, const QVariantMap &info); +}; + +QT_END_NAMESPACE + +#endif //QOFONOSERVICE_H diff --git a/src/plugins/bearer/corewlan/corewlan.pro b/src/plugins/bearer/corewlan/corewlan.pro new file mode 100644 index 0000000..9cb3955 --- /dev/null +++ b/src/plugins/bearer/corewlan/corewlan.pro @@ -0,0 +1,24 @@ +TARGET = qcorewlanbearer +include(../../qpluginbase.pri) + +QT = core network +LIBS += -framework Foundation -framework SystemConfiguration + +contains(QT_CONFIG, corewlan) { + isEmpty(QMAKE_MAC_SDK)|contains(QMAKE_MAC_SDK, "/Developer/SDKs/MacOSX10.6.sdk") { + LIBS += -framework CoreWLAN -framework Security + DEFINES += MAC_SDK_10_6 + } +} + +HEADERS += qcorewlanengine.h \ + ../qnetworksession_impl.h \ + ../qbearerengine_impl.h + +SOURCES += main.cpp \ + qcorewlanengine.mm \ + ../qnetworksession_impl.cpp + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/bearer +target.path += $$[QT_INSTALL_PLUGINS]/bearer +INSTALLS += target diff --git a/src/plugins/bearer/corewlan/main.cpp b/src/plugins/bearer/corewlan/main.cpp new file mode 100644 index 0000000..628ec61 --- /dev/null +++ b/src/plugins/bearer/corewlan/main.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcorewlanengine.h" + +#include <QtNetwork/private/qbearerplugin_p.h> + +#include <QtCore/qdebug.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +class QCoreWlanEnginePlugin : public QBearerEnginePlugin +{ +public: + QCoreWlanEnginePlugin(); + ~QCoreWlanEnginePlugin(); + + QStringList keys() const; + QBearerEngine *create(const QString &key) const; +}; + +QCoreWlanEnginePlugin::QCoreWlanEnginePlugin() +{ +} + +QCoreWlanEnginePlugin::~QCoreWlanEnginePlugin() +{ +} + +QStringList QCoreWlanEnginePlugin::keys() const +{ + return QStringList() << QLatin1String("corewlan"); +} + +QBearerEngine *QCoreWlanEnginePlugin::create(const QString &key) const +{ + if (key == QLatin1String("corewlan")) + return new QCoreWlanEngine; + else + return 0; +} + +Q_EXPORT_STATIC_PLUGIN(QCoreWlanEnginePlugin) +Q_EXPORT_PLUGIN2(qcorewlanbearer, QCoreWlanEnginePlugin) + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.h b/src/plugins/bearer/corewlan/qcorewlanengine.h new file mode 100644 index 0000000..56da66a --- /dev/null +++ b/src/plugins/bearer/corewlan/qcorewlanengine.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOREWLANENGINE_H +#define QCOREWLANENGINE_H + +#include "../qbearerengine_impl.h" + +#include <QMap> +#include <QTimer> +#include <SystemConfiguration/SystemConfiguration.h> +#include <QThread> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +class QNetworkConfigurationPrivate; +class QScanThread; + +class QCoreWlanEngine : public QBearerEngineImpl +{ + friend class QScanThread; + Q_OBJECT + +public: + QCoreWlanEngine(QObject *parent = 0); + ~QCoreWlanEngine(); + + QString getInterfaceFromId(const QString &id); + bool hasIdentifier(const QString &id); + + void connectToId(const QString &id); + void disconnectFromId(const QString &id); + + Q_INVOKABLE void initialize(); + Q_INVOKABLE void requestUpdate(); + + QNetworkSession::State sessionStateForId(const QString &id); + + quint64 bytesWritten(const QString &id); + quint64 bytesReceived(const QString &id); + quint64 startTime(const QString &id); + + QNetworkConfigurationManager::Capabilities capabilities() const; + + QNetworkSessionPrivate *createSessionBackend(); + + QNetworkConfigurationPrivatePointer defaultConfiguration(); + + bool requiresPolling() const; + +private Q_SLOTS: + void doRequestUpdate(); + void networksChanged(); + +private: + bool isWifiReady(const QString &dev); + QList<QNetworkConfigurationPrivate *> foundConfigurations; + + SCDynamicStoreRef storeSession; + CFRunLoopSourceRef runloopSource; + bool hasWifi; + bool scanning; + QScanThread *scanThread; + + quint64 getBytes(const QString &interfaceName,bool b); + +protected: + void startNetworkChangeLoop(); + +}; + +class QScanThread : public QThread +{ + Q_OBJECT + +public: + QScanThread(QObject *parent = 0); + ~QScanThread(); + + void quit(); + QList<QNetworkConfigurationPrivate *> getConfigurations(); + QString interfaceName; + QMap<QString, QString> configurationInterface; + void getUserConfigurations(); + QString getNetworkNameFromSsid(const QString &ssid); + QString getSsidFromNetworkName(const QString &name); + bool isKnownSsid(const QString &ssid); + QMap<QString, QMap<QString,QString> > userProfiles; + +signals: + void networksChanged(); + +protected: + void run(); + +private: + QList<QNetworkConfigurationPrivate *> fetchedConfigurations; + QMutex mutex; + QStringList foundNetwork(const QString &id, const QString &ssid, const QNetworkConfiguration::StateFlags state, const QString &interfaceName, const QNetworkConfiguration::Purpose purpose); + +}; + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT + +#endif diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.mm b/src/plugins/bearer/corewlan/qcorewlanengine.mm new file mode 100644 index 0000000..9946b17 --- /dev/null +++ b/src/plugins/bearer/corewlan/qcorewlanengine.mm @@ -0,0 +1,946 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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 diff --git a/src/plugins/bearer/generic/generic.pro b/src/plugins/bearer/generic/generic.pro new file mode 100644 index 0000000..c967f8c --- /dev/null +++ b/src/plugins/bearer/generic/generic.pro @@ -0,0 +1,16 @@ +TARGET = qgenericbearer +include(../../qpluginbase.pri) + +QT = core network + +HEADERS += qgenericengine.h \ + ../qnetworksession_impl.h \ + ../qbearerengine_impl.h \ + ../platformdefs_win.h +SOURCES += qgenericengine.cpp \ + ../qnetworksession_impl.cpp \ + main.cpp + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/bearer +target.path += $$[QT_INSTALL_PLUGINS]/bearer +INSTALLS += target diff --git a/src/plugins/bearer/generic/main.cpp b/src/plugins/bearer/generic/main.cpp new file mode 100644 index 0000000..ec1b689 --- /dev/null +++ b/src/plugins/bearer/generic/main.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgenericengine.h" + +#include <QtNetwork/private/qbearerplugin_p.h> + +#include <QtCore/qdebug.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +class QGenericEnginePlugin : public QBearerEnginePlugin +{ +public: + QGenericEnginePlugin(); + ~QGenericEnginePlugin(); + + QStringList keys() const; + QBearerEngine *create(const QString &key) const; +}; + +QGenericEnginePlugin::QGenericEnginePlugin() +{ +} + +QGenericEnginePlugin::~QGenericEnginePlugin() +{ +} + +QStringList QGenericEnginePlugin::keys() const +{ + return QStringList() << QLatin1String("generic"); +} + +QBearerEngine *QGenericEnginePlugin::create(const QString &key) const +{ + if (key == QLatin1String("generic")) + return new QGenericEngine; + else + return 0; +} + +Q_EXPORT_STATIC_PLUGIN(QGenericEnginePlugin) +Q_EXPORT_PLUGIN2(qgenericbearer, QGenericEnginePlugin) + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/generic/qgenericengine.cpp b/src/plugins/bearer/generic/qgenericengine.cpp new file mode 100644 index 0000000..fad3ae8 --- /dev/null +++ b/src/plugins/bearer/generic/qgenericengine.cpp @@ -0,0 +1,359 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgenericengine.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 <QtCore/private/qcoreapplication_p.h> + +#ifdef Q_OS_WIN +#include "../platformdefs_win.h" +#endif + +#ifdef Q_OS_LINUX +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <unistd.h> +#endif + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_NETWORKINTERFACE +static QNetworkConfiguration::BearerType qGetInterfaceType(const QString &interface) +{ +#ifdef Q_OS_WIN32 + unsigned long oid; + DWORD bytesWritten; + + NDIS_MEDIUM medium; + NDIS_PHYSICAL_MEDIUM physicalMedium; + + HANDLE handle = CreateFile((TCHAR *)QString::fromLatin1("\\\\.\\%1").arg(interface).utf16(), 0, + FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if (handle == INVALID_HANDLE_VALUE) + return QNetworkConfiguration::BearerUnknown; + + oid = OID_GEN_MEDIA_SUPPORTED; + bytesWritten = 0; + bool result = DeviceIoControl(handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof(oid), + &medium, sizeof(medium), &bytesWritten, 0); + if (!result) { + CloseHandle(handle); + return QNetworkConfiguration::BearerUnknown; + } + + oid = OID_GEN_PHYSICAL_MEDIUM; + bytesWritten = 0; + result = DeviceIoControl(handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof(oid), + &physicalMedium, sizeof(physicalMedium), &bytesWritten, 0); + if (!result) { + CloseHandle(handle); + + if (medium == NdisMedium802_3) + return QNetworkConfiguration::BearerEthernet; + else + return QNetworkConfiguration::BearerUnknown; + } + + CloseHandle(handle); + + if (medium == NdisMedium802_3) { + switch (physicalMedium) { + case NdisPhysicalMediumWirelessLan: + return QNetworkConfiguration::BearerWLAN; + case NdisPhysicalMediumBluetooth: + return QNetworkConfiguration::BearerBluetooth; + case NdisPhysicalMediumWiMax: + return QNetworkConfiguration::BearerWiMAX; + default: +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "Physical Medium" << physicalMedium; +#endif + return QNetworkConfiguration::BearerEthernet; + } + } + +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << medium << physicalMedium; +#endif +#elif defined(Q_OS_LINUX) + int sock = socket(AF_INET, SOCK_DGRAM, 0); + + ifreq request; + strncpy(request.ifr_name, interface.toLocal8Bit().data(), sizeof(request.ifr_name)); + int result = ioctl(sock, SIOCGIFHWADDR, &request); + close(sock); + + if (result >= 0 && request.ifr_hwaddr.sa_family == ARPHRD_ETHER) + return QNetworkConfiguration::BearerEthernet; +#else + Q_UNUSED(interface); +#endif + + return QNetworkConfiguration::BearerUnknown; +} +#endif + +QGenericEngine::QGenericEngine(QObject *parent) +: QBearerEngineImpl(parent) +{ +} + +QGenericEngine::~QGenericEngine() +{ +} + +QString QGenericEngine::getInterfaceFromId(const QString &id) +{ + QMutexLocker locker(&mutex); + + return configurationInterface.value(id); +} + +bool QGenericEngine::hasIdentifier(const QString &id) +{ + QMutexLocker locker(&mutex); + + return configurationInterface.contains(id); +} + +void QGenericEngine::connectToId(const QString &id) +{ + emit connectionError(id, OperationNotSupported); +} + +void QGenericEngine::disconnectFromId(const QString &id) +{ + emit connectionError(id, OperationNotSupported); +} + +void QGenericEngine::initialize() +{ + doRequestUpdate(); +} + +void QGenericEngine::requestUpdate() +{ + doRequestUpdate(); +} + +void QGenericEngine::doRequestUpdate() +{ +#ifndef QT_NO_NETWORKINTERFACE + QMutexLocker locker(&mutex); + + // Immediately after connecting with a wireless access point + // QNetworkInterface::allInterfaces() will sometimes return an empty list. Calling it again a + // second time results in a non-empty list. If we loose interfaces we will end up removing + // network configurations which will break current sessions. + QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces(); + if (interfaces.isEmpty()) + interfaces = QNetworkInterface::allInterfaces(); + + QStringList previous = accessPointConfigurations.keys(); + + // create configuration for each interface + while (!interfaces.isEmpty()) { + QNetworkInterface interface = interfaces.takeFirst(); + + if (!interface.isValid()) + continue; + + // ignore loopback interface + if (interface.flags() & QNetworkInterface::IsLoopBack) + continue; + + // ignore WLAN interface handled in separate engine + if (qGetInterfaceType(interface.name()) == QNetworkConfiguration::BearerWLAN) + continue; + + uint identifier; + if (interface.index()) + identifier = qHash(QLatin1String("generic:") + QString::number(interface.index())); + else + identifier = qHash(QLatin1String("generic:") + interface.hardwareAddress()); + + const QString id = QString::number(identifier); + + previous.removeAll(id); + + QString name = interface.humanReadableName(); + if (name.isEmpty()) + name = interface.name(); + + QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Defined; + if((interface.flags() & QNetworkInterface::IsUp) && !interface.addressEntries().isEmpty()) + state |= QNetworkConfiguration::Active; + + if (accessPointConfigurations.contains(id)) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + bool changed = false; + + ptr->mutex.lock(); + + if (!ptr->isValid) { + ptr->isValid = true; + changed = true; + } + + if (ptr->name != name) { + ptr->name = name; + changed = true; + } + + if (ptr->id != id) { + ptr->id = id; + changed = true; + } + + if (ptr->state != state) { + ptr->state = state; + changed = true; + } + + ptr->mutex.unlock(); + + if (changed) { + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } + } else { + QNetworkConfigurationPrivatePointer ptr(new QNetworkConfigurationPrivate); + + ptr->name = name; + ptr->isValid = true; + ptr->id = id; + ptr->state = state; + ptr->type = QNetworkConfiguration::InternetAccessPoint; + ptr->bearerType = qGetInterfaceType(interface.name()); + + accessPointConfigurations.insert(id, ptr); + configurationInterface.insert(id, interface.name()); + + locker.unlock(); + emit configurationAdded(ptr); + locker.relock(); + } + } + + while (!previous.isEmpty()) { + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.take(previous.takeFirst()); + + configurationInterface.remove(ptr->id); + + locker.unlock(); + emit configurationRemoved(ptr); + locker.relock(); + } + + locker.unlock(); +#endif + + emit updateCompleted(); +} + +QNetworkSession::State QGenericEngine::sessionStateForId(const QString &id) +{ + QMutexLocker locker(&mutex); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + if (!ptr) + return QNetworkSession::Invalid; + + QMutexLocker configLocker(&ptr->mutex); + + 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 QGenericEngine::capabilities() const +{ + return QNetworkConfigurationManager::ForcedRoaming; +} + +QNetworkSessionPrivate *QGenericEngine::createSessionBackend() +{ + return new QNetworkSessionPrivateImpl; +} + +QNetworkConfigurationPrivatePointer QGenericEngine::defaultConfiguration() +{ + return QNetworkConfigurationPrivatePointer(); +} + + +bool QGenericEngine::requiresPolling() const +{ + return true; +} + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/imageformats/gif/qgifhandler.h b/src/plugins/bearer/generic/qgenericengine.h index 8e07aff..021b35b 100644 --- a/src/plugins/imageformats/gif/qgifhandler.h +++ b/src/plugins/bearer/generic/qgenericengine.h @@ -37,60 +37,60 @@ ** ** $QT_END_LICENSE$ ** -** WARNING: -** A separate license from Unisys may be required to use the gif -** reader. See http://www.unisys.com/about__unisys/lzw/ -** for information from Unisys -** ****************************************************************************/ -#ifndef QGIFHANDLER_H -#define QGIFHANDLER_H +#ifndef QGENERICENGINE_H +#define QGENERICENGINE_H + +#include "../qbearerengine_impl.h" + +#include <QMap> +#include <QTimer> -#include <QtGui/qimageiohandler.h> -#include <QtGui/qimage.h> -#include <QtCore/qbytearray.h> +#ifndef QT_NO_BEARERMANAGEMENT QT_BEGIN_NAMESPACE -class QGIFFormat; -class QGifHandler : public QImageIOHandler +class QNetworkConfigurationPrivate; +class QNetworkSessionPrivate; + +class QGenericEngine : public QBearerEngineImpl { + Q_OBJECT + public: - QGifHandler(); - ~QGifHandler(); + QGenericEngine(QObject *parent = 0); + ~QGenericEngine(); + + QString getInterfaceFromId(const QString &id); + bool hasIdentifier(const QString &id); - bool canRead() const; - bool read(QImage *image); - bool write(const QImage &image); + void connectToId(const QString &id); + void disconnectFromId(const QString &id); - QByteArray name() const; + Q_INVOKABLE void initialize(); + Q_INVOKABLE void requestUpdate(); - static bool canRead(QIODevice *device); + QNetworkSession::State sessionStateForId(const QString &id); - QVariant option(ImageOption option) const; - void setOption(ImageOption option, const QVariant &value); - bool supportsOption(ImageOption option) const; + QNetworkConfigurationManager::Capabilities capabilities() const; - int imageCount() const; - int loopCount() const; - int nextImageDelay() const; - int currentImageNumber() const; + QNetworkSessionPrivate *createSessionBackend(); + + QNetworkConfigurationPrivatePointer defaultConfiguration(); + + bool requiresPolling() const; + +private Q_SLOTS: + void doRequestUpdate(); private: - bool imageIsComing() const; - QGIFFormat *gifFormat; - QString fileName; - mutable QByteArray buffer; - mutable QImage lastImage; - - mutable int nextDelay; - mutable int loopCnt; - int frameNumber; - mutable QVector<QSize> imageSizes; - mutable bool scanIsCached; + QMap<QString, QString> configurationInterface; }; QT_END_NAMESPACE -#endif // QGIFHANDLER_H +#endif // QT_NO_BEARERMANAGEMENT + +#endif + diff --git a/src/plugins/bearer/icd/dbusdispatcher.cpp b/src/plugins/bearer/icd/dbusdispatcher.cpp new file mode 100644 index 0000000..3d588dc --- /dev/null +++ b/src/plugins/bearer/icd/dbusdispatcher.cpp @@ -0,0 +1,631 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QDebug> +#include <QtCore> +#include <poll.h> +#include <dbus/dbus.h> +#include <dbus/dbus-glib-lowlevel.h> +#include <glib.h> +#include "dbusdispatcher.h" + +namespace Maemo { + +/*! + \class DBusDispatcher + + \brief DBusDispatcher is a class, which is able to send DBUS method call + messages and receive unicast signals from DBUS object. +*/ + +class DBusDispatcherPrivate +{ +public: + DBusDispatcherPrivate(const QString& service, + const QString& path, + const QString& interface, + const QString& signalPath) + : service(service), path(path), interface(interface), + signalPath(signalPath), connection(0) + { + memset(&signal_vtable, 0, sizeof(signal_vtable)); + } + + ~DBusDispatcherPrivate() + { + foreach(DBusPendingCall *call, pending_calls) { + dbus_pending_call_cancel(call); + dbus_pending_call_unref(call); + } + } + + QString service; + QString path; + QString interface; + QString signalPath; + struct DBusConnection *connection; + QList<DBusPendingCall *> pending_calls; + struct DBusObjectPathVTable signal_vtable; +}; + +static bool constantVariantList(const QVariantList& variantList) { + // Special case, empty list == empty struct + if (variantList.isEmpty()) { + return false; + } else { + QVariant::Type type = variantList[0].type(); + // Iterate items in the list and check if they are same type + foreach(QVariant variant, variantList) { + if (variant.type() != type) { + return false; + } + } + } + return true; +} + +static QString variantToSignature(const QVariant& argument, + bool constantList = true) { + switch (argument.type()) { + case QVariant::Bool: + return "b"; + case QVariant::ByteArray: + return "ay"; + case QVariant::Char: + return "y"; + case QVariant::Int: + return "i"; + case QVariant::UInt: + return "u"; + case QVariant::StringList: + return "as"; + case QVariant::String: + return "s"; + case QVariant::LongLong: + return "x"; + case QVariant::ULongLong: + return "t"; + case QVariant::List: + { + QString signature; + QVariantList variantList = argument.toList(); + if (!constantList) { + signature += DBUS_STRUCT_BEGIN_CHAR_AS_STRING; + foreach(QVariant listItem, variantList) { + signature += variantToSignature(listItem); + } + signature += DBUS_STRUCT_END_CHAR_AS_STRING; + } else { + if (variantList.isEmpty()) + return ""; + signature = "a" + variantToSignature(variantList[0]); + } + + return signature; + } + default: + qDebug() << "Unsupported variant type: " << argument.type(); + break; + } + + return ""; +} + +static bool appendVariantToDBusMessage(const QVariant& argument, + DBusMessageIter *dbus_iter) { + int idx = 0; + DBusMessageIter array_iter; + QStringList str_list; + dbus_bool_t bool_data; + dbus_int32_t int32_data; + dbus_uint32_t uint32_data; + dbus_int64_t int64_data; + dbus_uint64_t uint64_data; + char *str_data; + char char_data; + + switch (argument.type()) { + + case QVariant::Bool: + bool_data = argument.toBool(); + dbus_message_iter_append_basic(dbus_iter, DBUS_TYPE_BOOLEAN, + &bool_data); + break; + + case QVariant::ByteArray: + str_data = argument.toByteArray().data(); + dbus_message_iter_open_container(dbus_iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array_iter); + dbus_message_iter_append_fixed_array(&array_iter, + DBUS_TYPE_BYTE, + &str_data, + argument.toByteArray().size()); + dbus_message_iter_close_container(dbus_iter, &array_iter); + break; + + case QVariant::Char: + char_data = argument.toChar().toAscii(); + dbus_message_iter_append_basic(dbus_iter, DBUS_TYPE_BYTE, + &char_data); + break; + + case QVariant::Int: + int32_data = argument.toInt(); + dbus_message_iter_append_basic(dbus_iter, DBUS_TYPE_INT32, + &int32_data); + break; + + case QVariant::String: + str_data = argument.toString().toLatin1().data(); + dbus_message_iter_append_basic(dbus_iter, DBUS_TYPE_STRING, + &str_data); + break; + + case QVariant::StringList: + str_list = argument.toStringList(); + dbus_message_iter_open_container(dbus_iter, DBUS_TYPE_ARRAY, + "s", &array_iter); + for (idx = 0; idx < str_list.size(); idx++) { + str_data = str_list.at(idx).toLatin1().data(); + dbus_message_iter_append_basic(&array_iter, + DBUS_TYPE_STRING, + &str_data); + } + dbus_message_iter_close_container(dbus_iter, &array_iter); + break; + + case QVariant::UInt: + uint32_data = argument.toUInt(); + dbus_message_iter_append_basic(dbus_iter, DBUS_TYPE_UINT32, + &uint32_data); + break; + + case QVariant::ULongLong: + uint64_data = argument.toULongLong(); + dbus_message_iter_append_basic(dbus_iter, DBUS_TYPE_UINT64, + &uint64_data); + break; + + case QVariant::LongLong: + int64_data = argument.toLongLong(); + dbus_message_iter_append_basic(dbus_iter, DBUS_TYPE_INT64, + &int64_data); + break; + + case QVariant::List: + { + QVariantList variantList = argument.toList(); + bool constantList = constantVariantList(variantList); + DBusMessageIter array_iter; + + // List is mapped either as an DBUS array (all items same type) + // DBUS struct (variable types) depending on constantList + if (constantList) { + // Resolve the signature for the first item + QString signature = ""; + if (!variantList.isEmpty()) { + signature = variantToSignature( + variantList[0], + constantVariantList(variantList[0].toList())); + } + + // Mapped as DBUS array + dbus_message_iter_open_container(dbus_iter, DBUS_TYPE_ARRAY, + signature.toAscii(), + &array_iter); + + foreach(QVariant listItem, variantList) { + appendVariantToDBusMessage(listItem, &array_iter); + } + + dbus_message_iter_close_container(dbus_iter, &array_iter); + } else { + // Mapped as DBUS struct + dbus_message_iter_open_container(dbus_iter, DBUS_TYPE_STRUCT, + NULL, + &array_iter); + + foreach(QVariant listItem, variantList) { + appendVariantToDBusMessage(listItem, &array_iter); + } + + dbus_message_iter_close_container(dbus_iter, &array_iter); + } + + break; + } + default: + qDebug() << "Unsupported variant type: " << argument.type(); + break; + } + + return true; +} + +static QVariant getVariantFromDBusMessage(DBusMessageIter *iter) { + dbus_bool_t bool_data; + dbus_int32_t int32_data; + dbus_uint32_t uint32_data; + dbus_int64_t int64_data; + dbus_uint64_t uint64_data; + char *str_data; + char char_data; + int argtype = dbus_message_iter_get_arg_type(iter); + + switch (argtype) { + + case DBUS_TYPE_BOOLEAN: + { + dbus_message_iter_get_basic(iter, &bool_data); + QVariant variant((bool)bool_data); + return variant; + } + + case DBUS_TYPE_ARRAY: + { + // Handle all arrays here + int elem_type = dbus_message_iter_get_element_type(iter); + DBusMessageIter array_iter; + + dbus_message_iter_recurse(iter, &array_iter); + + if (elem_type == DBUS_TYPE_BYTE) { + QByteArray byte_array; + do { + dbus_message_iter_get_basic(&array_iter, &char_data); + byte_array.append(char_data); + } while (dbus_message_iter_next(&array_iter)); + QVariant variant(byte_array); + return variant; + } else if (elem_type == DBUS_TYPE_STRING) { + QStringList str_list; + do { + dbus_message_iter_get_basic(&array_iter, &str_data); + str_list.append(str_data); + } while (dbus_message_iter_next(&array_iter)); + QVariant variant(str_list); + return variant; + } else { + QVariantList variantList; + do { + variantList << getVariantFromDBusMessage(&array_iter); + } while (dbus_message_iter_next(&array_iter)); + QVariant variant(variantList); + return variant; + } + break; + } + + case DBUS_TYPE_BYTE: + { + dbus_message_iter_get_basic(iter, &char_data); + QChar ch(char_data); + QVariant variant(ch); + return variant; + } + + case DBUS_TYPE_INT32: + { + dbus_message_iter_get_basic(iter, &int32_data); + QVariant variant((int)int32_data); + return variant; + } + + case DBUS_TYPE_UINT32: + { + dbus_message_iter_get_basic(iter, &uint32_data); + QVariant variant((uint)uint32_data); + return variant; + } + + case DBUS_TYPE_STRING: + { + dbus_message_iter_get_basic(iter, &str_data); + QString str(str_data); + QVariant variant(str); + return variant; + } + + case DBUS_TYPE_INT64: + { + dbus_message_iter_get_basic(iter, &int64_data); + QVariant variant((qlonglong)int64_data); + return variant; + } + + case DBUS_TYPE_UINT64: + { + dbus_message_iter_get_basic(iter, &uint64_data); + QVariant variant((qulonglong)uint64_data); + return variant; + } + + case DBUS_TYPE_STRUCT: + { + // Handle all structs here + DBusMessageIter struct_iter; + dbus_message_iter_recurse(iter, &struct_iter); + + QVariantList variantList; + do { + variantList << getVariantFromDBusMessage(&struct_iter); + } while (dbus_message_iter_next(&struct_iter)); + QVariant variant(variantList); + return variant; + } + + default: + qDebug() << "Unsupported DBUS type: " << argtype; + } + + return QVariant(); +} + +static DBusHandlerResult signalHandler (DBusConnection *connection, + DBusMessage *message, + void *object_ref) { + (void)connection; + QString interface; + QString signal; + DBusDispatcher *dispatcher = (DBusDispatcher *)object_ref; + + if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) { + interface = dbus_message_get_interface(message); + signal = dbus_message_get_member(message); + + QList<QVariant> arglist; + DBusMessageIter dbus_iter; + + if (dbus_message_iter_init(message, &dbus_iter)) { + // Read return arguments + while (dbus_message_iter_get_arg_type (&dbus_iter) != DBUS_TYPE_INVALID) { + arglist << getVariantFromDBusMessage(&dbus_iter); + dbus_message_iter_next(&dbus_iter); + } + } + + dispatcher->emitSignalReceived(interface, signal, arglist); + return DBUS_HANDLER_RESULT_HANDLED; + } + (void)message; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +DBusDispatcher::DBusDispatcher(const QString& service, + const QString& path, + const QString& interface, + QObject *parent) + : QObject(parent), + d_ptr(new DBusDispatcherPrivate(service, path, interface, path)) { + setupDBus(); +} + +DBusDispatcher::DBusDispatcher(const QString& service, + const QString& path, + const QString& interface, + const QString& signalPath, + QObject *parent) + : QObject(parent), + d_ptr(new DBusDispatcherPrivate(service, path, interface, signalPath)) { + setupDBus(); +} + +DBusDispatcher::~DBusDispatcher() +{ + if (d_ptr->connection) { + dbus_connection_close(d_ptr->connection); + dbus_connection_unref(d_ptr->connection); + } + delete d_ptr; +} + +void DBusDispatcher::setupDBus() +{ + d_ptr->connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, NULL); + + if (d_ptr->connection == NULL) + qDebug() << "Unable to get DBUS connection!"; + else { + d_ptr->signal_vtable.message_function = signalHandler; + + dbus_connection_set_exit_on_disconnect(d_ptr->connection, FALSE); + dbus_connection_setup_with_g_main(d_ptr->connection, NULL); + dbus_connection_register_object_path(d_ptr->connection, + d_ptr->signalPath.toLatin1(), + &d_ptr->signal_vtable, + this); + } +} + +static DBusMessage *prepareDBusCall(const QString& service, + const QString& path, + const QString& interface, + const QString& method, + const QVariant& arg1 = QVariant(), + const QVariant& arg2 = QVariant(), + const QVariant& arg3 = QVariant(), + const QVariant& arg4 = QVariant(), + const QVariant& arg5 = QVariant(), + const QVariant& arg6 = QVariant(), + const QVariant& arg7 = QVariant(), + const QVariant& arg8 = QVariant()) +{ + DBusMessage *message = dbus_message_new_method_call(service.toLatin1(), + path.toLatin1(), + interface.toLatin1(), + method.toLatin1()); + DBusMessageIter dbus_iter; + + // Append variants to DBUS message + QList<QVariant> arglist; + if (arg1.isValid()) arglist << arg1; + if (arg2.isValid()) arglist << arg2; + if (arg3.isValid()) arglist << arg3; + if (arg4.isValid()) arglist << arg4; + if (arg5.isValid()) arglist << arg5; + if (arg6.isValid()) arglist << arg6; + if (arg7.isValid()) arglist << arg7; + if (arg8.isValid()) arglist << arg8; + + dbus_message_iter_init_append (message, &dbus_iter); + + while (!arglist.isEmpty()) { + QVariant argument = arglist.takeFirst(); + appendVariantToDBusMessage(argument, &dbus_iter); + } + + return message; +} + +QList<QVariant> DBusDispatcher::call(const QString& method, + const QVariant& arg1, + const QVariant& arg2, + const QVariant& arg3, + const QVariant& arg4, + const QVariant& arg5, + const QVariant& arg6, + const QVariant& arg7, + const QVariant& arg8) { + DBusMessageIter dbus_iter; + DBusMessage *message = prepareDBusCall(d_ptr->service, d_ptr->path, + d_ptr->interface, method, + arg1, arg2, arg3, arg4, arg5, + arg6, arg7, arg8); + DBusMessage *reply = dbus_connection_send_with_reply_and_block( + d_ptr->connection, + message, -1, NULL); + dbus_message_unref(message); + + QList<QVariant> replylist; + if (reply != NULL && dbus_message_iter_init(reply, &dbus_iter)) { + // Read return arguments + while (dbus_message_iter_get_arg_type (&dbus_iter) != DBUS_TYPE_INVALID) { + replylist << getVariantFromDBusMessage(&dbus_iter); + dbus_message_iter_next(&dbus_iter); + } + } + if (reply != NULL) dbus_message_unref(reply); + return replylist; +} + +class PendingCallInfo { +public: + QString method; + DBusDispatcher *dispatcher; + DBusDispatcherPrivate *priv; +}; + +static void freePendingCallInfo(void *memory) { + PendingCallInfo *info = (PendingCallInfo *)memory; + delete info; +} + +static void pendingCallFunction (DBusPendingCall *pending, + void *memory) { + PendingCallInfo *info = (PendingCallInfo *)memory; + QString errorStr; + QList<QVariant> replyList; + DBusMessage *reply = dbus_pending_call_steal_reply (pending); + + Q_ASSERT(reply != NULL); + + if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) { + errorStr = dbus_message_get_error_name (reply); + } else { + DBusMessageIter dbus_iter; + dbus_message_iter_init(reply, &dbus_iter); + // Read return arguments + while (dbus_message_iter_get_arg_type (&dbus_iter) != DBUS_TYPE_INVALID) { + replyList << getVariantFromDBusMessage(&dbus_iter); + dbus_message_iter_next(&dbus_iter); + } + } + + info->priv->pending_calls.removeOne(pending); + info->dispatcher->emitCallReply(info->method, replyList, errorStr); + dbus_message_unref(reply); + dbus_pending_call_unref(pending); +} + +bool DBusDispatcher::callAsynchronous(const QString& method, + const QVariant& arg1, + const QVariant& arg2, + const QVariant& arg3, + const QVariant& arg4, + const QVariant& arg5, + const QVariant& arg6, + const QVariant& arg7, + const QVariant& arg8) { + DBusMessage *message = prepareDBusCall(d_ptr->service, d_ptr->path, + d_ptr->interface, method, + arg1, arg2, arg3, arg4, arg5, + arg6, arg7, arg8); + DBusPendingCall *call = NULL; + dbus_bool_t ret = dbus_connection_send_with_reply(d_ptr->connection, + message, &call, -1); + PendingCallInfo *info = new PendingCallInfo; + info->method = method; + info->dispatcher = this; + info->priv = d_ptr; + + dbus_pending_call_set_notify(call, pendingCallFunction, info, freePendingCallInfo); + d_ptr->pending_calls.append(call); + return (bool)ret; +} + +void DBusDispatcher::emitSignalReceived(const QString& interface, + const QString& signal, + const QList<QVariant>& args) { + emit signalReceived(interface, signal, args); } + +void DBusDispatcher::emitCallReply(const QString& method, + const QList<QVariant>& args, + const QString& error) { + emit callReply(method, args, error); } + +void DBusDispatcher::synchronousDispatch(int timeout_ms) +{ + dbus_connection_read_write_dispatch(d_ptr->connection, timeout_ms); +} + +} // Maemo namespace + diff --git a/src/plugins/bearer/icd/dbusdispatcher.h b/src/plugins/bearer/icd/dbusdispatcher.h new file mode 100644 index 0000000..6f2f347 --- /dev/null +++ b/src/plugins/bearer/icd/dbusdispatcher.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef DBUSDISPATCHER_H +#define DBUSDISPATCHER_H + +#include <QObject> +#include <QVariant> + +namespace Maemo { + +class DBusDispatcherPrivate; +class DBusDispatcher : public QObject +{ + Q_OBJECT + +public: + DBusDispatcher(const QString& service, + const QString& path, + const QString& interface, + QObject *parent = 0); + DBusDispatcher(const QString& service, + const QString& path, + const QString& interface, + const QString& signalPath, + QObject *parent = 0); + ~DBusDispatcher(); + + QList<QVariant> call(const QString& method, + const QVariant& arg1 = QVariant(), + const QVariant& arg2 = QVariant(), + const QVariant& arg3 = QVariant(), + const QVariant& arg4 = QVariant(), + const QVariant& arg5 = QVariant(), + const QVariant& arg6 = QVariant(), + const QVariant& arg7 = QVariant(), + const QVariant& arg8 = QVariant()); + bool callAsynchronous(const QString& method, + const QVariant& arg1 = QVariant(), + const QVariant& arg2 = QVariant(), + const QVariant& arg3 = QVariant(), + const QVariant& arg4 = QVariant(), + const QVariant& arg5 = QVariant(), + const QVariant& arg6 = QVariant(), + const QVariant& arg7 = QVariant(), + const QVariant& arg8 = QVariant()); + void emitSignalReceived(const QString& interface, + const QString& signal, + const QList<QVariant>& args); + void emitCallReply(const QString& method, + const QList<QVariant>& args, + const QString& error = ""); + void synchronousDispatch(int timeout_ms); + +Q_SIGNALS: + void signalReceived(const QString& interface, + const QString& signal, + const QList<QVariant>& args); + void callReply(const QString& method, + const QList<QVariant>& args, + const QString& error); + +protected: + void setupDBus(); + +private: + DBusDispatcherPrivate *d_ptr; +}; + +} // Maemo namespace + +#endif diff --git a/src/plugins/bearer/icd/iapconf.cpp b/src/plugins/bearer/icd/iapconf.cpp new file mode 100644 index 0000000..ddd9fc2 --- /dev/null +++ b/src/plugins/bearer/icd/iapconf.cpp @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <stdlib.h> +#include <string.h> +#include <conn_settings.h> + +#include "iapconf.h" + +#define QSTRING_TO_CONST_CSTR(str) \ + str.toUtf8().constData() + +namespace Maemo { + +class IAPConfPrivate { +public: + ConnSettings *settings; + + ConnSettingsValue *variantToValue(const QVariant &variant); + QVariant valueToVariant(ConnSettingsValue *value); +}; + +ConnSettingsValue *IAPConfPrivate::variantToValue(const QVariant &variant) +{ + // Convert variant to ConnSettingsValue + ConnSettingsValue *value = conn_settings_value_new(); + if (value == 0) { + qWarning("IAPConf: Unable to create new ConnSettingsValue"); + return 0; + } + + switch(variant.type()) { + + case QVariant::Invalid: + value->type = CONN_SETTINGS_VALUE_INVALID; + break; + + case QVariant::String: { + char *valueStr = strdup(QSTRING_TO_CONST_CSTR(variant.toString())); + value->type = CONN_SETTINGS_VALUE_STRING; + value->value.string_val = valueStr; + break; + } + + case QVariant::Int: + value->type = CONN_SETTINGS_VALUE_INT; + value->value.int_val = variant.toInt(); + break; + + case QMetaType::Float: + case QVariant::Double: + value->type = CONN_SETTINGS_VALUE_DOUBLE; + value->value.double_val = variant.toDouble(); + break; + + case QVariant::Bool: + value->type = CONN_SETTINGS_VALUE_BOOL; + value->value.bool_val = variant.toBool() ? 1 : 0; + break; + + case QVariant::ByteArray: { + QByteArray array = variant.toByteArray(); + value->type = CONN_SETTINGS_VALUE_BYTE_ARRAY; + value->value.byte_array.len = array.size(); + value->value.byte_array.val = (unsigned char *)malloc(array.size()); + memcpy(value->value.byte_array.val, array.constData(), array.size()); + break; + } + + case QVariant::List: { + QVariantList list = variant.toList(); + ConnSettingsValue **list_val = (ConnSettingsValue **)malloc( + (list.size() + 1) * sizeof(ConnSettingsValue *)); + + for (int idx = 0; idx < list.size(); idx++) { + list_val[idx] = variantToValue(list.at(idx)); + } + list_val[list.size()] = 0; + + value->type = CONN_SETTINGS_VALUE_LIST; + value->value.list_val = list_val; + break; + } + + default: + qWarning("IAPConf: Can not handle QVariant of type %d", + variant.type()); + conn_settings_value_destroy(value); + return 0; + } + + return value; +} + +QVariant IAPConfPrivate::valueToVariant(ConnSettingsValue *value) +{ + if (value == 0 || value->type == CONN_SETTINGS_VALUE_INVALID) { + return QVariant(); + } + + switch(value->type) { + + case CONN_SETTINGS_VALUE_BOOL: + return QVariant(value->value.bool_val ? true : false); + + case CONN_SETTINGS_VALUE_STRING: + return QVariant(QString(value->value.string_val)); + + case CONN_SETTINGS_VALUE_DOUBLE: + return QVariant(value->value.double_val); + + case CONN_SETTINGS_VALUE_INT: + return QVariant(value->value.int_val); + + case CONN_SETTINGS_VALUE_LIST: { + // At least with GConf backend connsettings returns byte array as list + // of ints, first check for that case + if (value->value.list_val && value->value.list_val[0]) { + bool canBeConvertedToByteArray = true; + for (int idx = 0; value->value.list_val[idx]; idx++) { + ConnSettingsValue *val = value->value.list_val[idx]; + if (val->type != CONN_SETTINGS_VALUE_INT + || val->value.int_val > 255 + || val->value.int_val < 0) { + canBeConvertedToByteArray = false; + break; + } + } + + if (canBeConvertedToByteArray) { + QByteArray array; + for (int idx = 0; value->value.list_val[idx]; idx++) { + array.append(value->value.list_val[idx]->value.int_val); + } + return array; + } + + // Create normal list + QVariantList list; + for (int idx = 0; value->value.list_val[idx]; idx++) { + list.append(valueToVariant(value->value.list_val[idx])); + } + return list; + } + } + + case CONN_SETTINGS_VALUE_BYTE_ARRAY: + return QByteArray::fromRawData((char *)value->value.byte_array.val, + value->value.byte_array.len); + + default: + return QVariant(); + } +} + +// Public class implementation + +IAPConf::IAPConf(const QString &iap_id) + : d_ptr(new IAPConfPrivate) +{ + d_ptr->settings = conn_settings_open(CONN_SETTINGS_CONNECTION, + QSTRING_TO_CONST_CSTR(iap_id)); + if (d_ptr->settings == 0) { + qWarning("IAPConf: Unable to open ConnSettings for %s", + QSTRING_TO_CONST_CSTR(iap_id)); + } +} + +IAPConf::~IAPConf() +{ + conn_settings_close(d_ptr->settings); + delete d_ptr; +} + + +QVariant IAPConf::value(const QString& key) const +{ + ConnSettingsValue *val = conn_settings_get(d_ptr->settings, + QSTRING_TO_CONST_CSTR(key)); + + QVariant variant = d_ptr->valueToVariant(val); + conn_settings_value_destroy(val); + return variant; +} + + +void IAPConf::getAll(QList<QString> &all_iaps, bool return_path) +{ + Q_UNUSED(return_path); // We don't use return path currently + + // Go through all available connections and add them to the list + char **ids = conn_settings_list_ids(CONN_SETTINGS_CONNECTION); + if (ids == 0) { + // No ids found - nothing to do + return; + } + + for (int idx = 0; ids[idx]; idx++) { + all_iaps.append(QString(ids[idx])); + free(ids[idx]); + } + free(ids); +} + + +} // namespace Maemo diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.h b/src/plugins/bearer/icd/iapconf.h index dfb6b47..9c4ddcb 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.h +++ b/src/plugins/bearer/icd/iapconf.h @@ -39,39 +39,36 @@ ** ****************************************************************************/ -#ifndef QJPEGHANDLER_H -#define QJPEGHANDLER_H -#include <QtGui/qimageiohandler.h> -#include <QtCore/QSize> -#include <QtCore/QRect> +#ifndef IAPCONF_H +#define IAPCONF_H -QT_BEGIN_NAMESPACE +#include <QString> +#include <QVariant> -class QJpegHandler : public QImageIOHandler -{ -public: - QJpegHandler(); - - bool canRead() const; - bool read(QImage *image); - bool write(const QImage &image); +namespace Maemo { - QByteArray name() const; +class IAPConfPrivate; +class IAPConf { +public: + IAPConf(const QString &iap_id); + virtual ~IAPConf(); - static bool canRead(QIODevice *device); + /** + Get one IAP value. + */ + QVariant value(const QString& key) const; - QVariant option(ImageOption option) const; - void setOption(ImageOption option, const QVariant &value); - bool supportsOption(ImageOption option) const; + /** + Return all the IAPs found in the system. If return_path is true, + then do not strip the IAP path away. + */ + static void getAll(QList<QString> &all_iaps, bool return_path=false); private: - int quality; - QSize scaledSize; - QRect scaledClipRect; - QRect clipRect; + IAPConfPrivate *d_ptr; }; -QT_END_NAMESPACE +} // namespace Maemo -#endif // QJPEGHANDLER_H +#endif diff --git a/src/plugins/bearer/icd/iapmonitor.cpp b/src/plugins/bearer/icd/iapmonitor.cpp new file mode 100644 index 0000000..322bac0 --- /dev/null +++ b/src/plugins/bearer/icd/iapmonitor.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QStringList> + +#include <conn_settings.h> +#include "iapmonitor.h" + +namespace Maemo { + + +void conn_settings_notify_func (ConnSettingsType type, + const char *id, + const char *key, + ConnSettingsValue *value, + void *user_data); + +class IAPMonitorPrivate { +private: + IAPMonitor *monitor; + ConnSettings *settings; + +public: + + IAPMonitorPrivate(IAPMonitor *monitor) + : monitor(monitor) + { + settings = conn_settings_open(CONN_SETTINGS_CONNECTION, NULL); + conn_settings_add_notify( + settings, + (ConnSettingsNotifyFunc *)conn_settings_notify_func, + this); + } + + ~IAPMonitorPrivate() + { + conn_settings_del_notify(settings); + conn_settings_close(settings); + } + + void iapAdded(const QString &iap) + { + monitor->iapAdded(iap); + } + + void iapRemoved(const QString &iap) + { + monitor->iapRemoved(iap); + } +}; + +void conn_settings_notify_func (ConnSettingsType type, + const char *id, + const char *key, + ConnSettingsValue *value, + void *user_data) +{ + Q_UNUSED(id); + + if (type != CONN_SETTINGS_CONNECTION) return; + IAPMonitorPrivate *priv = (IAPMonitorPrivate *)user_data; + + QString iapId(key); + iapId = iapId.split("/")[0]; + if (value != 0) { + priv->iapAdded(iapId); + } else if (iapId == QString(key)) { + // IAP is removed only when the directory gets removed + priv->iapRemoved(iapId); + } +} + +IAPMonitor::IAPMonitor() + : d_ptr(new IAPMonitorPrivate(this)) +{ +} + +IAPMonitor::~IAPMonitor() +{ + delete d_ptr; +} + +void IAPMonitor::iapAdded(const QString &id) +{ + Q_UNUSED(id); + // By default do nothing +} + +void IAPMonitor::iapRemoved(const QString &id) +{ + Q_UNUSED(id); + // By default do nothing +} + +} // namespace Maemo diff --git a/src/plugins/bearer/icd/iapmonitor.h b/src/plugins/bearer/icd/iapmonitor.h new file mode 100644 index 0000000..21ad3bc --- /dev/null +++ b/src/plugins/bearer/icd/iapmonitor.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef IAPMONITOR_H +#define IAPMONITOR_H + +#include <QString> + +namespace Maemo { + +class IAPMonitorPrivate; +class IAPMonitor { +public: + IAPMonitor(); + ~IAPMonitor(); + +protected: + virtual void iapAdded(const QString &id); + virtual void iapRemoved(const QString &id); + +private: + IAPMonitorPrivate *d_ptr; + Q_DECLARE_PRIVATE(IAPMonitor); +}; + +} // namespace Maemo + +#endif // IAPMONITOR_H + diff --git a/src/plugins/bearer/icd/icd.pro b/src/plugins/bearer/icd/icd.pro new file mode 100644 index 0000000..6700cda --- /dev/null +++ b/src/plugins/bearer/icd/icd.pro @@ -0,0 +1,33 @@ +TARGET = qicdbearer +include(../../qpluginbase.pri) + +QT = core network dbus + +QMAKE_CXXFLAGS *= $$QT_CFLAGS_DBUS $$QT_CFLAGS_CONNSETTINGS +LIBS += $$QT_LIBS_CONNSETTINGS + +HEADERS += qicdengine.h \ + qnetworksession_impl.h \ + dbusdispatcher.h \ + iapconf.h \ + iapmonitor.h \ + maemo_icd.h \ + proxyconf.h \ + wlan-utils.h + +SOURCES += main.cpp \ + qicdengine.cpp \ + qnetworksession_impl.cpp \ + dbusdispatcher.cpp \ + iapmonitor.cpp \ + iapconf.cpp \ + maemo_icd.cpp \ + proxyconf.cpp + +#DEFINES += BEARER_MANAGEMENT_DEBUG + +include(../../../3rdparty/libgq.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/bearer +target.path += $$[QT_INSTALL_PLUGINS]/bearer +INSTALLS += target diff --git a/src/plugins/bearer/icd/maemo_icd.cpp b/src/plugins/bearer/icd/maemo_icd.cpp new file mode 100644 index 0000000..57ab0a8 --- /dev/null +++ b/src/plugins/bearer/icd/maemo_icd.cpp @@ -0,0 +1,855 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "maemo_icd.h" +#include "dbusdispatcher.h" + +#include <QObject> +#include <QTimer> +#include <QCoreApplication> +#include <QEventLoop> +#include <QDebug> +#include <dbus/dbus.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include <stdio.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> + +namespace Maemo { + +#undef PRINT_DEBUGINFO +#ifdef PRINT_DEBUGINFO + static FILE *fdebug = NULL; +#define PDEBUG(fmt, args...) \ + do { \ + struct timeval tv; \ + gettimeofday(&tv, 0); \ + fprintf(fdebug, "DEBUG[%d]:%ld.%ld:%s:%s():%d: " fmt, \ + getpid(), \ + tv.tv_sec, tv.tv_usec, \ + __FILE__, __FUNCTION__, __LINE__, args); \ + fflush(fdebug); \ + } while(0) +#else +#define PDEBUG(fmt...) +#endif + + +class IcdPrivate +{ +public: + IcdPrivate(Icd *myfriend) + { + init(10000, IcdNewDbusInterface, myfriend); + } + + IcdPrivate(unsigned int timeout, Icd *myfriend) + { + init(timeout, IcdNewDbusInterface, myfriend); + } + + IcdPrivate(unsigned int timeout, IcdDbusInterfaceVer ver, Icd *myfriend) + { + Q_UNUSED(ver); + + /* Note that the old Icd interface is currently disabled and + * the new one is always used. + */ + init(timeout, IcdNewDbusInterface, myfriend); + } + + ~IcdPrivate() + { + QObject::disconnect(mDBus, + SIGNAL(signalReceived(const QString&, + const QString&, + const QList<QVariant>&)), + icd, + SLOT(icdSignalReceived(const QString&, + const QString&, + const QList<QVariant>&))); + + QObject::disconnect(mDBus, + SIGNAL(callReply(const QString&, + const QList<QVariant>&, + const QString&)), + icd, + SLOT(icdCallReply(const QString&, + const QList<QVariant>&, + const QString&))); + + delete mDBus; + mDBus = 0; + } + + /* Icd2 dbus API functions */ + QStringList scan(icd_scan_request_flags flags, + QStringList &network_types, + QList<IcdScanResult>& scan_results, + QString& error); + + uint state(QString& service_type, uint service_attrs, + QString& service_id, QString& network_type, + uint network_attrs, QByteArray& network_id, + IcdStateResult &state_result); + + uint addrinfo(QString& service_type, uint service_attrs, + QString& service_id, QString& network_type, + uint network_attrs, QByteArray& network_id, + IcdAddressInfoResult& addr_result); + + uint state(QList<IcdStateResult>& state_results); + uint statistics(QList<IcdStatisticsResult>& stats_results); + uint addrinfo(QList<IcdAddressInfoResult>& addr_results); + + void signalReceived(const QString& interface, + const QString& signal, + const QList<QVariant>& args); + void callReply(const QString& method, + const QList<QVariant>& args, + const QString& error); + +public: + DBusDispatcher *mDBus; + QString mMethod; + QString mInterface; + QString mSignal; + QString mError; + QList<QVariant> mArgs; + QList<QVariant> receivedSignals; + unsigned int timeout; + IcdDbusInterfaceVer icd_dbus_version; + Icd *icd; + + void init(unsigned int dbus_timeout, IcdDbusInterfaceVer ver, + Icd *myfriend) + { + if (ver == IcdNewDbusInterface) { + mDBus = new DBusDispatcher(ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_PATH, + ICD_DBUS_API_INTERFACE); + } else { + mDBus = new DBusDispatcher(ICD_DBUS_SERVICE, + ICD_DBUS_PATH, + ICD_DBUS_INTERFACE); + } + icd_dbus_version = ver; + + /* This connect has a side effect as it means that only one + * Icd object can exists in one time. This should be fixed! + */ + QObject::connect(mDBus, + SIGNAL(signalReceived(const QString&, + const QString&, + const QList<QVariant>&)), + myfriend, + SLOT(icdSignalReceived(const QString&, + const QString&, + const QList<QVariant>&))); + + QObject::connect(mDBus, + SIGNAL(callReply(const QString&, + const QList<QVariant>&, + const QString&)), + myfriend, + SLOT(icdCallReply(const QString&, + const QList<QVariant>&, + const QString&))); + + icd = myfriend; + timeout = dbus_timeout; + +#ifdef PRINT_DEBUGINFO + if (!fdebug) { + fdebug = fopen("/tmp/maemoicd.log", "a+"); + } + PDEBUG("created %s\n", "IcdPrivate"); +#endif + } + + void clearState() + { + mMethod.clear(); + mInterface.clear(); + mSignal.clear(); + mError.clear(); + mArgs.clear(); + receivedSignals.clear(); + } + + bool doState(); +}; + + +void IcdPrivate::signalReceived(const QString& interface, + const QString& signal, + const QList<QVariant>& args) +{ + // Signal handler, which simply records what has been signalled + mInterface = interface; + mSignal = signal; + mArgs = args; + + //qDebug() << "signal" << signal << "received:" << args; + receivedSignals << QVariant(interface) << QVariant(signal) << QVariant(args); +} + + +void IcdPrivate::callReply(const QString& method, + const QList<QVariant>& /*args*/, + const QString& error) +{ + mMethod = method; + mError = error; +} + + +static void get_scan_result(QList<QVariant>& args, + IcdScanResult& ret) +{ + int i=0; + + if (args.isEmpty()) + return; + + ret.status = args[i++].toUInt(); + ret.timestamp = args[i++].toUInt(); + ret.scan.service_type = args[i++].toString(); + ret.service_name = args[i++].toString(); + ret.scan.service_attrs = args[i++].toUInt(); + ret.scan.service_id = args[i++].toString(); + ret.service_priority = args[i++].toInt(); + ret.scan.network_type = args[i++].toString(); + ret.network_name = args[i++].toString(); + ret.scan.network_attrs = args[i++].toUInt(); + ret.scan.network_id = args[i++].toByteArray(); + ret.network_priority = args[i++].toInt(); + ret.signal_strength = args[i++].toInt(); + ret.station_id = args[i++].toString(); + ret.signal_dB = args[i++].toInt(); +} + + +QStringList IcdPrivate::scan(icd_scan_request_flags flags, + QStringList &network_types, + QList<IcdScanResult>& scan_results, + QString& error) +{ + Q_UNUSED(network_types); + + QStringList scanned_types; + QTimer timer; + QVariant reply; + QVariantList vl; + bool last_result = false; + IcdScanResult result; + int all_waited; + + clearState(); + reply = mDBus->call(ICD_DBUS_API_SCAN_REQ, (uint)flags); + if (reply.type() != QVariant::List) + return scanned_types; + vl = reply.toList(); + if (vl.isEmpty()) { + error = "Scan did not return anything."; + return scanned_types; + } + reply = vl.first(); + scanned_types = reply.toStringList(); + //qDebug() << "Scanning:" << scanned_types; + all_waited = scanned_types.size(); + + timer.setSingleShot(true); + timer.start(timeout); + + scan_results.clear(); + while (!last_result) { + while (timer.isActive() && mInterface.isEmpty() && mError.isEmpty()) { + QCoreApplication::processEvents(QEventLoop::AllEvents, 1000); + } + + if (!timer.isActive()) { + //qDebug() << "Timeout happened"; + break; + } + + if (mSignal != ICD_DBUS_API_SCAN_SIG) { + //qDebug() << "Received" << mSignal << "while waiting" << ICD_DBUS_API_SCAN_SIG << ", ignoring"; + mInterface.clear(); + continue; + } + + if (mError.isEmpty()) { + QString msgInterface = receivedSignals.takeFirst().toString(); + QString msgSignal = receivedSignals.takeFirst().toString(); + QList<QVariant> msgArgs = receivedSignals.takeFirst().toList(); + //qDebug() << "Signal" << msgSignal << "received."; + //qDebug() << "Params:" << msgArgs; + + while (!msgSignal.isEmpty()) { + get_scan_result(msgArgs, result); + +#if 0 + qDebug() << "Received: " << + "status =" << result.status << + ", timestamp =" << result.timestamp << + ", service_type =" << result.scan.service_type << + ", service_name =" << result.service_name << + ", service_attrs =" << result.scan.service_attrs << + ", service_id =" << result.scan.service_id << + ", service_priority =" << result.service_priority << + ", network_type =" << result.scan.network_type << + ", network_name =" << result.network_name << + ", network_attrs =" << result.scan.network_attrs << + ", network_id =" << "-" << + ", network_priority =" << result.network_priority << + ", signal_strength =" << result.signal_strength << + ", station_id =" << result.station_id << + ", signal_dB =" << result.signal_dB; +#endif + + if (result.status == ICD_SCAN_COMPLETE) { + //qDebug() << "waited =" << all_waited; + if (--all_waited == 0) { + last_result = true; + break; + } + } else + scan_results << result; + + if (receivedSignals.isEmpty()) + break; + + msgInterface = receivedSignals.takeFirst().toString(); + msgSignal = receivedSignals.takeFirst().toString(); + msgArgs = receivedSignals.takeFirst().toList(); + } + mInterface.clear(); + + } else { + qWarning() << "Error while scanning:" << mError; + break; + } + } + timer.stop(); + + error = mError; + return scanned_types; +} + + +static void get_state_all_result(QList<QVariant>& args, + IcdStateResult& ret) +{ + int i=0; + + ret.params.service_type = args[i++].toString(); + ret.params.service_attrs = args[i++].toUInt(); + ret.params.service_id = args[i++].toString(); + ret.params.network_type = args[i++].toString(); + ret.params.network_attrs = args[i++].toUInt(); + ret.params.network_id = args[i++].toByteArray(); + ret.error = args[i++].toString(); + ret.state = args[i++].toInt(); +} + + +static void get_state_all_result2(QList<QVariant>& args, + IcdStateResult& ret) +{ + int i=0; + + ret.params.network_type = args[i++].toString(); + ret.state = args[i++].toInt(); + + // Initialize the other values so that the caller can + // notice we only returned partial status + ret.params.service_type = QString(); + ret.params.service_attrs = 0; + ret.params.service_id = QString(); + ret.params.network_attrs = 0; + ret.params.network_id = QByteArray(); + ret.error = QString(); +} + + +uint IcdPrivate::state(QString& service_type, uint service_attrs, + QString& service_id, QString& network_type, + uint network_attrs, QByteArray& network_id, + IcdStateResult& state_result) +{ + QTimer timer; + QVariant reply; + uint total_signals; + QVariantList vl; + + clearState(); + + reply = mDBus->call(ICD_DBUS_API_STATE_REQ, + service_type, service_attrs, service_id, + network_type, network_attrs, network_id); + if (reply.type() != QVariant::List) + return 0; + vl = reply.toList(); + if (vl.isEmpty()) + return 0; + reply = vl.first(); + total_signals = reply.toUInt(); + if (!total_signals) + return 0; + + timer.setSingleShot(true); + timer.start(timeout); + + mInterface.clear(); + while (timer.isActive() && mInterface.isEmpty()) { + QCoreApplication::processEvents(QEventLoop::AllEvents, 1000); + + if (mSignal != ICD_DBUS_API_STATE_SIG) { + mInterface.clear(); + continue; + } + } + + timer.stop(); + + if (mError.isEmpty()) { + if (!mArgs.isEmpty()) { + if (mArgs.size()>2) + get_state_all_result(mArgs, state_result); + else { + // We are not connected as we did not get the status we asked + return 0; + } + } + } else { + qWarning() << "Error:" << mError; + } + + // The returned value should be one because we asked for one state + return total_signals; +} + + +/* Special version of the state() call which does not call event loop. + * Needed in order to fix NB#175098 where Qt4.7 webkit crashes because event + * loop is run when webkit does not expect it. This function is called from + * bearer management API syncStateWithInterface() in QNetworkSession + * constructor. + */ +uint IcdPrivate::state(QList<IcdStateResult>& state_results) +{ + QVariant reply; + QVariantList vl; + uint signals_left, total_signals; + IcdStateResult result; + time_t started; + int timeout_secs = timeout / 1000; + + PDEBUG("%s\n", "state_results"); + + clearState(); + reply = mDBus->call(ICD_DBUS_API_STATE_REQ); + if (reply.type() != QVariant::List) + return 0; + vl = reply.toList(); + if (vl.isEmpty()) + return 0; + reply = vl.first(); + signals_left = total_signals = reply.toUInt(); + if (!signals_left) + return 0; + + started = time(0); + state_results.clear(); + mError.clear(); + while (signals_left) { + mInterface.clear(); + while ((time(0)<=(started+timeout_secs)) && mInterface.isEmpty()) { + mDBus->synchronousDispatch(1000); + QCoreApplication::sendPostedEvents(icd, QEvent::MetaCall); + } + + if (time(0)>(started+timeout_secs)) { + total_signals = 0; + break; + } + + if (mSignal != ICD_DBUS_API_STATE_SIG) { + continue; + } + + if (mError.isEmpty()) { + if (!mArgs.isEmpty()) { + if (mArgs.size()==2) + get_state_all_result2(mArgs, result); + else + get_state_all_result(mArgs, result); + state_results << result; + } + signals_left--; + } else { + qWarning() << "Error:" << mError; + break; + } + } + + PDEBUG("total_signals=%d\n", total_signals); + return total_signals; +} + + +static void get_statistics_all_result(QList<QVariant>& args, + IcdStatisticsResult& ret) +{ + int i=0; + + if (args.isEmpty()) + return; + + ret.params.service_type = args[i++].toString(); + ret.params.service_attrs = args[i++].toUInt(); + ret.params.service_id = args[i++].toString(); + ret.params.network_type = args[i++].toString(); + ret.params.network_attrs = args[i++].toUInt(); + ret.params.network_id = args[i++].toByteArray(); + ret.time_active = args[i++].toUInt(); + ret.signal_strength = (enum icd_nw_levels)args[i++].toUInt(); + ret.bytes_sent = args[i++].toUInt(); + ret.bytes_received = args[i++].toUInt(); +} + + +uint IcdPrivate::statistics(QList<IcdStatisticsResult>& stats_results) +{ + QTimer timer; + QVariant reply; + QVariantList vl; + uint signals_left, total_signals; + IcdStatisticsResult result; + + clearState(); + reply = mDBus->call(ICD_DBUS_API_STATISTICS_REQ); + if (reply.type() != QVariant::List) + return 0; + vl = reply.toList(); + if (vl.isEmpty()) + return 0; + reply = vl.first(); + if (reply.type() != QVariant::UInt) + return 0; + signals_left = total_signals = reply.toUInt(); + + if (!signals_left) + return 0; + + timer.setSingleShot(true); + timer.start(timeout); + stats_results.clear(); + while (signals_left) { + mInterface.clear(); + while (timer.isActive() && mInterface.isEmpty()) { + QCoreApplication::processEvents(QEventLoop::AllEvents, 1000); + } + + if (!timer.isActive()) { + total_signals = 0; + break; + } + + if (mSignal != ICD_DBUS_API_STATISTICS_SIG) { + continue; + } + + if (mError.isEmpty()) { + get_statistics_all_result(mArgs, result); + stats_results << result; + signals_left--; + } else { + qWarning() << "Error:" << mError; + break; + } + } + timer.stop(); + + return total_signals; +} + + +static void get_addrinfo_all_result(QList<QVariant>& args, + IcdAddressInfoResult& ret) +{ + int i=0; + + if (args.isEmpty()) + return; + + ret.params.service_type = args[i++].toString(); + ret.params.service_attrs = args[i++].toUInt(); + ret.params.service_id = args[i++].toString(); + ret.params.network_type = args[i++].toString(); + ret.params.network_attrs = args[i++].toUInt(); + ret.params.network_id = args[i++].toByteArray(); + + QVariantList vl = args[i].toList(); + QVariant reply = vl.first(); + QList<QVariant> lst = reply.toList(); + for (int k=0; k<lst.size()/6; k=k+6) { + IcdIPInformation ip_info; + ip_info.address = lst[k].toString(); + ip_info.netmask = lst[k++].toString(); + ip_info.default_gateway = lst[k++].toString(); + ip_info.dns1 = lst[k++].toString(); + ip_info.dns2 = lst[k++].toString(); + ip_info.dns3 = lst[k++].toString(); + + ret.ip_info << ip_info; + } +} + + +/* Special version of the addrinfo() call which does not call event loop. + * Needed in order to fix NB#175098 where Qt4.7 webkit crashes because event + * loop is run when webkit does not expect it. This function is called from + * bearer management API syncStateWithInterface() in QNetworkSession + * constructor. + */ +uint IcdPrivate::addrinfo(QList<IcdAddressInfoResult>& addr_results) +{ + QVariant reply; + QVariantList vl; + uint signals_left, total_signals; + IcdAddressInfoResult result; + time_t started; + int timeout_secs = timeout / 1000; + + PDEBUG("%s\n", "addr_results"); + + clearState(); + reply = mDBus->call(ICD_DBUS_API_ADDRINFO_REQ); + if (reply.type() != QVariant::List) + return 0; + vl = reply.toList(); + if (vl.isEmpty()) + return 0; + reply = vl.first(); + if (reply.type() != QVariant::UInt) + return 0; + signals_left = total_signals = reply.toUInt(); + if (!signals_left) + return 0; + + started = time(0); + addr_results.clear(); + while (signals_left) { + mInterface.clear(); + while ((time(0)<=(started+timeout_secs)) && mInterface.isEmpty()) { + mDBus->synchronousDispatch(1000); + QCoreApplication::sendPostedEvents(icd, QEvent::MetaCall); + } + + if (time(0)>(started+timeout_secs)) { + total_signals = 0; + break; + } + + if (mSignal != ICD_DBUS_API_ADDRINFO_SIG) { + continue; + } + + if (mError.isEmpty()) { + get_addrinfo_all_result(mArgs, result); + addr_results << result; + signals_left--; + } else { + qWarning() << "Error:" << mError; + break; + } + } + + PDEBUG("total_signals=%d\n", total_signals); + return total_signals; +} + + +uint IcdPrivate::addrinfo(QString& service_type, uint service_attrs, + QString& service_id, QString& network_type, + uint network_attrs, QByteArray& network_id, + IcdAddressInfoResult& addr_result) +{ + QTimer timer; + QVariant reply; + uint total_signals; + QVariantList vl; + + clearState(); + + reply = mDBus->call(ICD_DBUS_API_ADDRINFO_REQ, + service_type, service_attrs, service_id, + network_type, network_attrs, network_id); + if (reply.type() != QVariant::List) + return 0; + vl = reply.toList(); + if (vl.isEmpty()) + return 0; + reply = vl.first(); + total_signals = reply.toUInt(); + + if (!total_signals) + return 0; + + timer.setSingleShot(true); + timer.start(timeout); + + mInterface.clear(); + while (timer.isActive() && mInterface.isEmpty()) { + QCoreApplication::processEvents(QEventLoop::AllEvents, 1000); + + if (mSignal != ICD_DBUS_API_ADDRINFO_SIG) { + mInterface.clear(); + continue; + } + } + + timer.stop(); + + if (mError.isEmpty()) { + get_addrinfo_all_result(mArgs, addr_result); + } else { + qWarning() << "Error:" << mError; + } + + // The returned value should be one because we asked for one addrinfo + return total_signals; +} + + +Icd::Icd(QObject *parent) + : QObject(parent), d(new IcdPrivate(this)) +{ +} + +Icd::Icd(unsigned int timeout, QObject *parent) + : QObject(parent), d(new IcdPrivate(timeout, this)) +{ +} + +Icd::Icd(unsigned int timeout, IcdDbusInterfaceVer ver, QObject *parent) + : QObject(parent), d(new IcdPrivate(timeout, ver, this)) +{ +} + +Icd::~Icd() +{ + delete d; +} + + +QStringList Icd::scan(icd_scan_request_flags flags, + QStringList &network_types, + QList<IcdScanResult>& scan_results, + QString& error) +{ + return d->scan(flags, network_types, scan_results, error); +} + + +uint Icd::state(QString& service_type, uint service_attrs, + QString& service_id, QString& network_type, + uint network_attrs, QByteArray& network_id, + IcdStateResult &state_result) +{ + return d->state(service_type, service_attrs, service_id, + network_type, network_attrs, network_id, + state_result); +} + + +uint Icd::addrinfo(QString& service_type, uint service_attrs, + QString& service_id, QString& network_type, + uint network_attrs, QByteArray& network_id, + IcdAddressInfoResult& addr_result) +{ + return d->addrinfo(service_type, service_attrs, service_id, + network_type, network_attrs, network_id, + addr_result); +} + + +uint Icd::state(QList<IcdStateResult>& state_results) +{ + return d->state(state_results); +} + + +uint Icd::statistics(QList<IcdStatisticsResult>& stats_results) +{ + return d->statistics(stats_results); +} + + +uint Icd::addrinfo(QList<IcdAddressInfoResult>& addr_results) +{ + return d->addrinfo(addr_results); +} + + +void Icd::icdSignalReceived(const QString& interface, + const QString& signal, + const QList<QVariant>& args) +{ + d->signalReceived(interface, signal, args); +} + + +void Icd::icdCallReply(const QString& method, + const QList<QVariant>& args, + const QString& error) +{ + d->callReply(method, args, error); +} + +} // Maemo namespace + + diff --git a/src/plugins/bearer/icd/maemo_icd.h b/src/plugins/bearer/icd/maemo_icd.h new file mode 100644 index 0000000..156316a --- /dev/null +++ b/src/plugins/bearer/icd/maemo_icd.h @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef MAEMO_ICD_H +#define MAEMO_ICD_H + +#include <QObject> +#include <QStringList> +#include <QByteArray> +#include <QMetaType> +#include <QtDBus> +#include <QDBusArgument> + +#include <glib.h> +#include <icd/dbus_api.h> +#include <icd/osso-ic.h> +#include <icd/osso-ic-dbus.h> +#include <icd/network_api_defines.h> + +#define ICD_LONG_SCAN_TIMEOUT (30*1000) /* 30sec */ +#define ICD_SHORT_SCAN_TIMEOUT (10*1000) /* 10sec */ +#define ICD_SHORT_CONNECT_TIMEOUT (10*1000) /* 10sec */ +#define ICD_LONG_CONNECT_TIMEOUT (150*1000) /* 2.5min */ + +namespace Maemo { + +struct CommonParams { + QString service_type; + uint service_attrs; + QString service_id; + QString network_type; + uint network_attrs; + QByteArray network_id; +}; + +struct IcdScanResult { + uint status; // see #icd_scan_status + uint timestamp; // when last seen + QString service_name; + uint service_priority; // within a service type + QString network_name; + uint network_priority; + struct CommonParams scan; + uint signal_strength; // quality, 0 (none) - 10 (good) + QString station_id; // e.g. MAC address or similar id + uint signal_dB; // use signal strength above unless you know what you are doing + + IcdScanResult() { + status = timestamp = scan.service_attrs = service_priority = + scan.network_attrs = network_priority = signal_strength = + signal_dB = 0; + } +}; + +struct IcdStateResult { + struct CommonParams params; + QString error; + uint state; +}; + +struct IcdStatisticsResult { + struct CommonParams params; + uint time_active; // in seconds + enum icd_nw_levels signal_strength; // see network_api_defines.h in icd2-dev package + uint bytes_sent; + uint bytes_received; +}; + +struct IcdIPInformation { + QString address; + QString netmask; + QString default_gateway; + QString dns1; + QString dns2; + QString dns3; +}; + +struct IcdAddressInfoResult { + struct CommonParams params; + QList<IcdIPInformation> ip_info; +}; + +enum IcdDbusInterfaceVer { + IcdOldDbusInterface = 0, // use the old OSSO-IC interface + IcdNewDbusInterface // use the new Icd2 interface (default) +}; + + +class IcdPrivate; +class Icd : public QObject +{ + Q_OBJECT + +public: + Icd(QObject *parent = 0); + Icd(unsigned int timeout, QObject *parent = 0); + Icd(unsigned int timeout, IcdDbusInterfaceVer ver, QObject *parent = 0); + ~Icd(); + + /* Icd2 dbus API functions */ + QStringList scan(icd_scan_request_flags flags, + QStringList &network_types, + QList<IcdScanResult>& scan_results, + QString& error); + + uint state(QString& service_type, uint service_attrs, + QString& service_id, QString& network_type, + uint network_attrs, QByteArray& network_id, + IcdStateResult &state_result); + + uint addrinfo(QString& service_type, uint service_attrs, + QString& service_id, QString& network_type, + uint network_attrs, QByteArray& network_id, + IcdAddressInfoResult& addr_result); + + uint state(QList<IcdStateResult>& state_results); + uint statistics(QList<IcdStatisticsResult>& stats_results); + uint addrinfo(QList<IcdAddressInfoResult>& addr_results); + +private Q_SLOTS: + void icdSignalReceived(const QString& interface, + const QString& signal, + const QList<QVariant>& args); + void icdCallReply(const QString& method, + const QList<QVariant>& args, + const QString& error); + +private: + IcdPrivate *d; + friend class IcdPrivate; +}; + +} // Maemo namespace + +#endif diff --git a/src/plugins/bearer/icd/main.cpp b/src/plugins/bearer/icd/main.cpp new file mode 100644 index 0000000..491112b --- /dev/null +++ b/src/plugins/bearer/icd/main.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qicdengine.h" + +#include <QtNetwork/private/qbearerplugin_p.h> + +#include <QtCore/qdebug.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +class QIcdEnginePlugin : public QBearerEnginePlugin +{ +public: + QIcdEnginePlugin(); + ~QIcdEnginePlugin(); + + QStringList keys() const; + QBearerEngine *create(const QString &key) const; +}; + +QIcdEnginePlugin::QIcdEnginePlugin() +{ +} + +QIcdEnginePlugin::~QIcdEnginePlugin() +{ +} + +QStringList QIcdEnginePlugin::keys() const +{ + return QStringList() << QLatin1String("icd"); +} + +QBearerEngine *QIcdEnginePlugin::create(const QString &key) const +{ + if (key == QLatin1String("icd")) + return new QIcdEngine; + else + return 0; +} + +Q_EXPORT_STATIC_PLUGIN(QIcdEnginePlugin) +Q_EXPORT_PLUGIN2(qicdbearer, QIcdEnginePlugin) + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/bearer/icd/proxyconf.cpp b/src/plugins/bearer/icd/proxyconf.cpp new file mode 100644 index 0000000..e5c8f4e --- /dev/null +++ b/src/plugins/bearer/icd/proxyconf.cpp @@ -0,0 +1,412 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QVariant> +#include <QStringList> +#include <QDebug> +#include <QWriteLocker> +#include <QNetworkProxyFactory> +#include <QNetworkProxy> +#include <gconf/gconf-value.h> +#include <gconf/gconf-client.h> +#include "proxyconf.h" + +#define CONF_PROXY "/system/proxy" +#define HTTP_PROXY "/system/http_proxy" + + +namespace Maemo { + +static QString convertKey(const char *key) +{ + return QString::fromUtf8(key); +} + +static QVariant convertValue(GConfValue *src) +{ + if (!src) { + return QVariant(); + } else { + switch (src->type) { + case GCONF_VALUE_INVALID: + return QVariant(QVariant::Invalid); + case GCONF_VALUE_BOOL: + return QVariant((bool)gconf_value_get_bool(src)); + case GCONF_VALUE_INT: + return QVariant(gconf_value_get_int(src)); + case GCONF_VALUE_FLOAT: + return QVariant(gconf_value_get_float(src)); + case GCONF_VALUE_STRING: + return QVariant(QString::fromUtf8(gconf_value_get_string(src))); + case GCONF_VALUE_LIST: + switch (gconf_value_get_list_type(src)) { + case GCONF_VALUE_STRING: + { + QStringList result; + for (GSList *elts = gconf_value_get_list(src); elts; elts = elts->next) + result.append(QString::fromUtf8(gconf_value_get_string((GConfValue *)elts->data))); + return QVariant(result); + } + default: + { + QList<QVariant> result; + for (GSList *elts = gconf_value_get_list(src); elts; elts = elts->next) + result.append(convertValue((GConfValue *)elts->data)); + return QVariant(result); + } + } + case GCONF_VALUE_SCHEMA: + default: + return QVariant(); + } + } +} + + +/* Fast version of GConfItem, allows reading subtree at a time */ +class GConfItemFast { +public: + GConfItemFast(const QString &k) : key(k) {} + QHash<QString,QVariant> getEntries() const; + +private: + QString key; +}; + +#define withClient(c) for (GConfClient *c = gconf_client_get_default(); c; c=0) + + +QHash<QString,QVariant> GConfItemFast::getEntries() const +{ + QHash<QString,QVariant> children; + + withClient(client) { + QByteArray k = key.toUtf8(); + GSList *entries = gconf_client_all_entries(client, k.data(), NULL); + for (GSList *e = entries; e; e = e->next) { + char *key_name = strrchr(((GConfEntry *)e->data)->key, '/'); + if (!key_name) + key_name = ((GConfEntry *)e->data)->key; + else + key_name++; + QString key(convertKey(key_name)); + QVariant value = convertValue(((GConfEntry *)e->data)->value); + gconf_entry_unref((GConfEntry *)e->data); + //qDebug()<<"key="<<key<<"value="<<value; + children.insert(key, value); + } + g_slist_free (entries); + } + + return children; +} + + + +class NetworkProxyFactory : QNetworkProxyFactory { +public: + NetworkProxyFactory() { } + QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query = QNetworkProxyQuery()); +}; + + +QList<QNetworkProxy> NetworkProxyFactory::queryProxy(const QNetworkProxyQuery &query) +{ + ProxyConf proxy_conf; + + QList<QNetworkProxy> result = proxy_conf.flush(query); + if (result.isEmpty()) + result << QNetworkProxy::NoProxy; + + return result; +} + + +class ProxyConfPrivate { +private: + // proxy values from gconf + QString mode; + bool use_http_host; + QString autoconfig_url; + QString http_proxy; + quint16 http_port; + QList<QVariant> ignore_hosts; + QString secure_host; + quint16 secure_port; + QString ftp_host; + quint16 ftp_port; + QString socks_host; + quint16 socks_port; + QString rtsp_host; + quint16 rtsp_port; + + bool isHostExcluded(const QString &host); + +public: + QString prefix; + QString http_prefix; + + void readProxyData(); + QList<QNetworkProxy> flush(const QNetworkProxyQuery &query); +}; + + +static QHash<QString,QVariant> getValues(const QString& prefix) +{ + GConfItemFast item(prefix); + return item.getEntries(); +} + +static QHash<QString,QVariant> getHttpValues(const QString& prefix) +{ + GConfItemFast item(prefix); + return item.getEntries(); +} + +#define GET(var, type) \ + do { \ + QVariant v = values.value(#var); \ + if (v.isValid()) \ + var = v.to##type (); \ + } while(0) + +#define GET_HTTP(var, name, type) \ + do { \ + QVariant v = httpValues.value(#name); \ + if (v.isValid()) \ + var = v.to##type (); \ + } while(0) + + +void ProxyConfPrivate::readProxyData() +{ + QHash<QString,QVariant> values = getValues(prefix); + QHash<QString,QVariant> httpValues = getHttpValues(http_prefix); + + //qDebug()<<"values="<<values; + + /* Read the proxy settings from /system/proxy* */ + GET_HTTP(http_proxy, host, String); + GET_HTTP(http_port, port, Int); + GET_HTTP(ignore_hosts, ignore_hosts, List); + + GET(mode, String); + GET(autoconfig_url, String); + GET(secure_host, String); + GET(secure_port, Int); + GET(ftp_host, String); + GET(ftp_port, Int); + GET(socks_host, String); + GET(socks_port, Int); + GET(rtsp_host, String); + GET(rtsp_port, Int); + + if (http_proxy.isEmpty()) + use_http_host = false; + else + use_http_host = true; +} + + +bool ProxyConfPrivate::isHostExcluded(const QString &host) +{ + if (host.isEmpty()) + return true; + + if (ignore_hosts.isEmpty()) + return false; + + QHostAddress ipAddress; + bool isIpAddress = ipAddress.setAddress(host); + + foreach (QVariant h, ignore_hosts) { + QString entry = h.toString(); + if (isIpAddress && ipAddress.isInSubnet(QHostAddress::parseSubnet(entry))) { + return true; // excluded + } else { + // do wildcard matching + QRegExp rx(entry, Qt::CaseInsensitive, QRegExp::Wildcard); + if (rx.exactMatch(host)) + return true; + } + } + + // host was not excluded + return false; +} + + +QList<QNetworkProxy> ProxyConfPrivate::flush(const QNetworkProxyQuery &query) +{ + QList<QNetworkProxy> result; + +#if 0 + qDebug()<<"http_proxy" << http_proxy; + qDebug()<<"http_port" << http_port; + qDebug()<<"ignore_hosts" << ignore_hosts; + qDebug()<<"use_http_host" << use_http_host; + qDebug()<<"mode" << mode; + qDebug()<<"autoconfig_url" << autoconfig_url; + qDebug()<<"secure_host" << secure_host; + qDebug()<<"secure_port" << secure_port; + qDebug()<<"ftp_host" << ftp_host; + qDebug()<<"ftp_port" << ftp_port; + qDebug()<<"socks_host" << socks_host; + qDebug()<<"socks_port" << socks_port; + qDebug()<<"rtsp_host" << rtsp_host; + qDebug()<<"rtsp_port" << rtsp_port; +#endif + + if (isHostExcluded(query.peerHostName())) + return result; // no proxy for this host + + if (mode == "auto") { + // TODO: pac currently not supported, fix me + return result; + } + + if (mode == "manual") { + bool isHttps = false; + QString protocol = query.protocolTag().toLower(); + + // try the protocol-specific proxy + QNetworkProxy protocolSpecificProxy; + + if (protocol == QLatin1String("ftp")) { + if (!ftp_host.isEmpty()) { + protocolSpecificProxy.setType(QNetworkProxy::FtpCachingProxy); + protocolSpecificProxy.setHostName(ftp_host); + protocolSpecificProxy.setPort(ftp_port); + } + } else if (protocol == QLatin1String("http")) { + if (!http_proxy.isEmpty()) { + protocolSpecificProxy.setType(QNetworkProxy::HttpProxy); + protocolSpecificProxy.setHostName(http_proxy); + protocolSpecificProxy.setPort(http_port); + } + } else if (protocol == QLatin1String("https")) { + isHttps = true; + if (!secure_host.isEmpty()) { + protocolSpecificProxy.setType(QNetworkProxy::HttpProxy); + protocolSpecificProxy.setHostName(secure_host); + protocolSpecificProxy.setPort(secure_port); + } + } + + if (protocolSpecificProxy.type() != QNetworkProxy::DefaultProxy) + result << protocolSpecificProxy; + + + if (!socks_host.isEmpty()) { + QNetworkProxy proxy; + proxy.setType(QNetworkProxy::Socks5Proxy); + proxy.setHostName(socks_host); + proxy.setPort(socks_port); + result << proxy; + } + + + // Add the HTTPS proxy if present (and if we haven't added yet) + if (!isHttps) { + QNetworkProxy https; + if (!secure_host.isEmpty()) { + https.setType(QNetworkProxy::HttpProxy); + https.setHostName(secure_host); + https.setPort(secure_port); + } + + if (https.type() != QNetworkProxy::DefaultProxy && + https != protocolSpecificProxy) + result << https; + } + } + + return result; +} + + +ProxyConf::ProxyConf() + : d_ptr(new ProxyConfPrivate) +{ + g_type_init(); + d_ptr->prefix = CONF_PROXY; + d_ptr->http_prefix = HTTP_PROXY; +} + +ProxyConf::~ProxyConf() +{ + delete d_ptr; +} + + +QList<QNetworkProxy> ProxyConf::flush(const QNetworkProxyQuery &query) +{ + d_ptr->readProxyData(); + return d_ptr->flush(query); +} + + +static int refcount = 0; +static QReadWriteLock lock; + +void ProxyConf::update() +{ + QWriteLocker locker(&lock); + NetworkProxyFactory *factory = new NetworkProxyFactory(); + QNetworkProxyFactory::setApplicationProxyFactory((QNetworkProxyFactory*)factory); + refcount++; +} + + +void ProxyConf::clear(void) +{ + QWriteLocker locker(&lock); + refcount--; + if (refcount == 0) + QNetworkProxyFactory::setApplicationProxyFactory(NULL); + + if (refcount<0) + refcount = 0; +} + + +} // namespace Maemo diff --git a/src/plugins/bearer/icd/proxyconf.h b/src/plugins/bearer/icd/proxyconf.h new file mode 100644 index 0000000..884cc5c --- /dev/null +++ b/src/plugins/bearer/icd/proxyconf.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef PROXYCONF_H +#define PROXYCONF_H + +#include <QString> +#include <QNetworkProxy> + +namespace Maemo { + +class ProxyConfPrivate; +class ProxyConf { +private: + ProxyConfPrivate *d_ptr; + +public: + ProxyConf(); + virtual ~ProxyConf(); + + QList<QNetworkProxy> flush(const QNetworkProxyQuery &query = QNetworkProxyQuery()); // read the proxies from db + + /* Note that for each update() call there should be corresponding + * clear() call because the ProxyConf class implements a reference + * counting mechanism. The factory is removed only when there is + * no one using the factory any more. + */ + static void update(void); // this builds QNetworkProxy factory + static void clear(void); // this removes QNetworkProxy factory +}; + +} // namespace Maemo + +#endif diff --git a/src/plugins/bearer/icd/qicdengine.cpp b/src/plugins/bearer/icd/qicdengine.cpp new file mode 100644 index 0000000..bdf4e2e --- /dev/null +++ b/src/plugins/bearer/icd/qicdengine.cpp @@ -0,0 +1,1052 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qicdengine.h" +#include "qnetworksession_impl.h" + +#include <wlancond.h> +#include <wlan-utils.h> +#include <iapconf.h> +#include <iapmonitor.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +IcdNetworkConfigurationPrivate::IcdNetworkConfigurationPrivate() +: service_attrs(0), network_attrs(0) +{ +} + +IcdNetworkConfigurationPrivate::~IcdNetworkConfigurationPrivate() +{ +} + +QString IcdNetworkConfigurationPrivate::bearerTypeName() const +{ + QMutexLocker locker(&mutex); + + return iap_type; +} + +/******************************************************************************/ +/** IapAddTimer specific */ +/******************************************************************************/ + +/* The IapAddTimer is a helper class that makes sure we update + * the configuration only after all db additions to certain + * iap are finished (after a certain timeout) + */ +class _IapAddTimer : public QObject +{ + Q_OBJECT + +public: + _IapAddTimer() {} + ~_IapAddTimer() + { + if (timer.isActive()) { + QObject::disconnect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); + timer.stop(); + } + } + + void add(QString& iap_id, QIcdEngine *d); + + QString iap_id; + QTimer timer; + QIcdEngine *d; + +public Q_SLOTS: + void timeout(); +}; + + +void _IapAddTimer::add(QString& id, QIcdEngine *d_ptr) +{ + iap_id = id; + d = d_ptr; + + if (timer.isActive()) { + QObject::disconnect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); + timer.stop(); + } + timer.setSingleShot(true); + QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); + timer.start(1500); +} + + +void _IapAddTimer::timeout() +{ + d->addConfiguration(iap_id); +} + + +class IapAddTimer { + QHash<QString, _IapAddTimer* > timers; + +public: + IapAddTimer() {} + ~IapAddTimer() {} + + void add(QString& iap_id, QIcdEngine *d); + void del(QString& iap_id); + void removeAll(); +}; + + +void IapAddTimer::removeAll() +{ + QHashIterator<QString, _IapAddTimer* > i(timers); + while (i.hasNext()) { + i.next(); + _IapAddTimer *t = i.value(); + delete t; + } + timers.clear(); +} + + +void IapAddTimer::add(QString& iap_id, QIcdEngine *d) +{ + if (timers.contains(iap_id)) { + _IapAddTimer *iap = timers.value(iap_id); + iap->add(iap_id, d); + } else { + _IapAddTimer *iap = new _IapAddTimer; + iap->add(iap_id, d); + timers.insert(iap_id, iap); + } +} + +void IapAddTimer::del(QString& iap_id) +{ + if (timers.contains(iap_id)) { + _IapAddTimer *iap = timers.take(iap_id); + delete iap; + } +} + +/******************************************************************************/ +/** IAPMonitor specific */ +/******************************************************************************/ + +class IapMonitor : public Maemo::IAPMonitor +{ +public: + IapMonitor() : first_call(true) { } + + void setup(QIcdEngine *d); + void cleanup(); + +protected: + void iapAdded(const QString &iapId); + void iapRemoved(const QString &iapId); + +private: + bool first_call; + + QIcdEngine *d; + IapAddTimer timers; +}; + +void IapMonitor::setup(QIcdEngine *d_ptr) +{ + if (first_call) { + d = d_ptr; + first_call = false; + } +} + + +void IapMonitor::cleanup() +{ + if (!first_call) { + timers.removeAll(); + first_call = true; + } +} + + +void IapMonitor::iapAdded(const QString &iap_id) +{ + /* We cannot know when the IAP is fully added to db, so a timer is + * installed instead. When the timer expires we hope that IAP is added ok. + */ + QString id = iap_id; + timers.add(id, d); +} + + +void IapMonitor::iapRemoved(const QString &iap_id) +{ + QString id = iap_id; + d->deleteConfiguration(id); +} + + +/******************************************************************************/ +/** QIcdEngine implementation */ +/******************************************************************************/ + +QIcdEngine::QIcdEngine(QObject *parent) +: QBearerEngine(parent), iapMonitor(0), m_dbusInterface(0), + firstUpdate(true), m_scanGoingOn(false) +{ +} + +QIcdEngine::~QIcdEngine() +{ + cleanup(); + delete iapMonitor; +} + +QNetworkConfigurationManager::Capabilities QIcdEngine::capabilities() const +{ + return QNetworkConfigurationManager::CanStartAndStopInterfaces | + QNetworkConfigurationManager::DataStatistics | + QNetworkConfigurationManager::ForcedRoaming | + QNetworkConfigurationManager::NetworkSessionRequired; +} + +void QIcdEngine::initialize() +{ + QMutexLocker locker(&mutex); + + // Setup DBus Interface for ICD + m_dbusInterface = new QDBusInterface(ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_PATH, + ICD_DBUS_API_INTERFACE, + QDBusConnection::systemBus(), + this); + + // abort if cannot connect to DBus. + if (!m_dbusInterface->isValid()) + return; + + connect(&m_scanTimer, SIGNAL(timeout()), this, SLOT(finishAsyncConfigurationUpdate())); + m_scanTimer.setSingleShot(true); + + /* Turn on IAP state monitoring */ + startListeningStateSignalsForAllConnections(); + + /* Turn on IAP add/remove monitoring */ + iapMonitor = new IapMonitor; + iapMonitor->setup(this); + + /* We create a default configuration which is a pseudo config */ + QNetworkConfigurationPrivate *cpPriv = new IcdNetworkConfigurationPrivate; + cpPriv->name = "UserChoice"; + cpPriv->state = QNetworkConfiguration::Discovered; + cpPriv->isValid = true; + cpPriv->id = OSSO_IAP_ANY; + cpPriv->type = QNetworkConfiguration::UserChoice; + cpPriv->purpose = QNetworkConfiguration::UnknownPurpose; + cpPriv->roamingSupported = false; + + QNetworkConfigurationPrivatePointer ptr(cpPriv); + userChoiceConfigurations.insert(cpPriv->id, ptr); + + doRequestUpdate(); + + getIcdInitialState(); +} + +static inline QString network_attrs_to_security(uint network_attrs) +{ + uint cap = 0; + nwattr2cap(network_attrs, &cap); /* from libicd-network-wlan-dev.h */ + if (cap & WLANCOND_OPEN) + return "NONE"; + else if (cap & WLANCOND_WEP) + return "WEP"; + else if (cap & WLANCOND_WPA_PSK) + return "WPA_PSK"; + else if (cap & WLANCOND_WPA_EAP) + return "WPA_EAP"; + return ""; +} + + +struct SSIDInfo { + QString iap_id; + QString wlan_security; +}; + + +void QIcdEngine::deleteConfiguration(const QString &iap_id) +{ + QMutexLocker locker(&mutex); + + /* Called when IAPs are deleted in db, in this case we do not scan + * or read all the IAPs from db because it might take too much power + * (multiple applications would need to scan and read all IAPs from db) + */ + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(iap_id); + if (ptr) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "IAP" << iap_id << "was removed from storage."; +#endif + + locker.unlock(); + emit configurationRemoved(ptr); + } else { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("IAP: %s, already missing from the known list", iap_id.toAscii().data()); +#endif + } +} + + +static quint32 getNetworkAttrs(bool is_iap_id, + const QString &iap_id, + const QString &iap_type, + QString security_method) +{ + guint network_attr = 0; + dbus_uint32_t cap = 0; + + if (iap_type == "WLAN_INFRA") + cap |= WLANCOND_INFRA; + else if (iap_type == "WLAN_ADHOC") + cap |= WLANCOND_ADHOC; + + if (security_method.isEmpty() && (cap & (WLANCOND_INFRA | WLANCOND_ADHOC))) { + Maemo::IAPConf saved_ap(iap_id); + security_method = saved_ap.value("wlan_security").toString(); + } + + if (!security_method.isEmpty()) { + if (security_method == "WEP") + cap |= WLANCOND_WEP; + else if (security_method == "WPA_PSK") + cap |= WLANCOND_WPA_PSK; + else if (security_method == "WPA_EAP") + cap |= WLANCOND_WPA_EAP; + else if (security_method == "NONE") + cap |= WLANCOND_OPEN; + + if (cap & (WLANCOND_WPA_PSK | WLANCOND_WPA_EAP)) { + Maemo::IAPConf saved_iap(iap_id); + bool wpa2_only = saved_iap.value("EAP_wpa2_only_mode").toBool(); + if (wpa2_only) { + cap |= WLANCOND_WPA2; + } + } + } + + cap2nwattr(cap, &network_attr); + if (is_iap_id) + network_attr |= ICD_NW_ATTR_IAPNAME; + + return quint32(network_attr); +} + + +void QIcdEngine::addConfiguration(QString& iap_id) +{ + // Note: When new IAP is created, this function gets called multiple times + // in a row. + // For example: Empty type & name for WLAN was stored into newly + // created IAP data in gconf when this function gets + // called for the first time. + // WLAN type & name are updated into IAP data in gconf + // as soon as WLAN connection is up and running. + // => And this function gets called again. + + QMutexLocker locker(&mutex); + + if (!accessPointConfigurations.contains(iap_id)) { + Maemo::IAPConf saved_iap(iap_id); + QString iap_type = saved_iap.value("type").toString(); + QString iap_name = saved_iap.value("name").toString(); + QByteArray ssid = saved_iap.value("wlan_ssid").toByteArray(); + if (!iap_type.isEmpty() && !iap_name.isEmpty()) { + // Check if new IAP is actually Undefined WLAN configuration + // Note: SSID is used as an iap id for Undefined WLAN configurations + // => configuration must be searched using SSID + if (!ssid.isEmpty() && accessPointConfigurations.contains(ssid)) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(ssid); + if (ptr) { + ptr->mutex.lock(); + ptr->id = iap_id; + toIcdConfig(ptr)->iap_type = iap_type; + ptr->bearerType = bearerTypeFromIapType(iap_type); + toIcdConfig(ptr)->network_attrs = getNetworkAttrs(true, iap_id, iap_type, QString()); + toIcdConfig(ptr)->network_id = ssid; + toIcdConfig(ptr)->service_id = saved_iap.value("service_id").toString(); + toIcdConfig(ptr)->service_type = saved_iap.value("service_type").toString(); + if (m_onlineIapId == iap_id) { + ptr->state = QNetworkConfiguration::Active; + } else { + ptr->state = QNetworkConfiguration::Defined; + } + ptr->mutex.unlock(); + accessPointConfigurations.insert(iap_id, ptr); + + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } + } else { + IcdNetworkConfigurationPrivate *cpPriv = new IcdNetworkConfigurationPrivate; + cpPriv->name = saved_iap.value("name").toString(); + if (cpPriv->name.isEmpty()) + cpPriv->name = iap_id; + cpPriv->isValid = true; + cpPriv->id = iap_id; + cpPriv->iap_type = iap_type; + cpPriv->bearerType = bearerTypeFromIapType(iap_type); + cpPriv->network_attrs = getNetworkAttrs(true, iap_id, iap_type, QString()); + cpPriv->service_id = saved_iap.value("service_id").toString(); + cpPriv->service_type = saved_iap.value("service_type").toString(); + if (iap_type.startsWith(QLatin1String("WLAN"))) { + QByteArray ssid = saved_iap.value("wlan_ssid").toByteArray(); + if (ssid.isEmpty()) { + qWarning() << "Cannot get ssid for" << iap_id; + } + cpPriv->network_id = ssid; + } + cpPriv->type = QNetworkConfiguration::InternetAccessPoint; + if (m_onlineIapId == iap_id) { + cpPriv->state = QNetworkConfiguration::Active; + } else { + cpPriv->state = QNetworkConfiguration::Defined; + } + + QNetworkConfigurationPrivatePointer ptr(cpPriv); + accessPointConfigurations.insert(iap_id, ptr); + +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("IAP: %s, name: %s, added to known list", iap_id.toAscii().data(), cpPriv->name.toAscii().data()); +#endif + locker.unlock(); + emit configurationAdded(ptr); + locker.relock(); + } + } else { + qWarning("IAP %s does not have \"type\" or \"name\" fields defined, skipping this IAP.", iap_id.toAscii().data()); + } + } else { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "IAP" << iap_id << "already in db."; +#endif + + /* Check if the data in db changed and update configuration accordingly + */ + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iap_id); + if (ptr) { + Maemo::IAPConf changed_iap(iap_id); + QString iap_type = changed_iap.value("type").toString(); + bool update_needed = false; /* if IAP type or ssid changed, we need to change the state */ + + QMutexLocker configLocker(&ptr->mutex); + + toIcdConfig(ptr)->network_attrs = getNetworkAttrs(true, iap_id, iap_type, QString()); + toIcdConfig(ptr)->service_id = changed_iap.value("service_id").toString(); + toIcdConfig(ptr)->service_type = changed_iap.value("service_type").toString(); + + if (!iap_type.isEmpty()) { + ptr->name = changed_iap.value("name").toString(); + if (ptr->name.isEmpty()) + ptr->name = iap_id; + ptr->isValid = true; + if (toIcdConfig(ptr)->iap_type != iap_type) { + toIcdConfig(ptr)->iap_type = iap_type; + ptr->bearerType = bearerTypeFromIapType(iap_type); + update_needed = true; + } + if (iap_type.startsWith(QLatin1String("WLAN"))) { + QByteArray ssid = changed_iap.value("wlan_ssid").toByteArray(); + if (ssid.isEmpty()) { + qWarning() << "Cannot get ssid for" << iap_id; + } + if (toIcdConfig(ptr)->network_id != ssid) { + toIcdConfig(ptr)->network_id = ssid; + update_needed = true; + } + } + } + + if (update_needed) { + ptr->type = QNetworkConfiguration::InternetAccessPoint; + if (m_onlineIapId == iap_id) { + if (ptr->state < QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Active; + + configLocker.unlock(); + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } + } else if (ptr->state < QNetworkConfiguration::Defined) { + ptr->state = QNetworkConfiguration::Defined; + + configLocker.unlock(); + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } + } + } else { + qWarning("Cannot find IAP %s from current configuration although it should be there.", iap_id.toAscii().data()); + } + } +} + +void QIcdEngine::doRequestUpdate(QList<Maemo::IcdScanResult> scanned) +{ + /* Contains all known iap_ids from storage */ + QList<QString> knownConfigs = accessPointConfigurations.keys(); + + /* Contains all known WLAN network ids (like ssid) from storage */ + QMultiHash<QByteArray, SSIDInfo* > notDiscoveredWLANConfigs; + + QList<QString> all_iaps; + Maemo::IAPConf::getAll(all_iaps); + + foreach (const QString &iap_id, all_iaps) { + QByteArray ssid; + + Maemo::IAPConf saved_ap(iap_id); + bool is_temporary = saved_ap.value("temporary").toBool(); + if (is_temporary) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "IAP" << iap_id << "is temporary, skipping it."; +#endif + continue; + } + + QString iap_type = saved_ap.value("type").toString(); + if (iap_type.startsWith(QLatin1String("WLAN"))) { + ssid = saved_ap.value("wlan_ssid").toByteArray(); + if (ssid.isEmpty()) + continue; + + QString security_method = saved_ap.value("wlan_security").toString(); + SSIDInfo *info = new SSIDInfo; + info->iap_id = iap_id; + info->wlan_security = security_method; + notDiscoveredWLANConfigs.insert(ssid, info); + } else if (iap_type.isEmpty()) { + continue; + } else { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "IAP" << iap_id << "network type is" << iap_type; +#endif + ssid.clear(); + } + + if (!accessPointConfigurations.contains(iap_id)) { + IcdNetworkConfigurationPrivate *cpPriv = new IcdNetworkConfigurationPrivate; + + cpPriv->name = saved_ap.value("name").toString(); + if (cpPriv->name.isEmpty()) { + if (!ssid.isEmpty() && ssid.size() > 0) + cpPriv->name = ssid.data(); + else + cpPriv->name = iap_id; + } + cpPriv->isValid = true; + cpPriv->id = iap_id; + cpPriv->network_id = ssid; + cpPriv->network_attrs = getNetworkAttrs(true, iap_id, iap_type, QString()); + cpPriv->iap_type = iap_type; + cpPriv->bearerType = bearerTypeFromIapType(iap_type); + cpPriv->service_id = saved_ap.value("service_id").toString(); + cpPriv->service_type = saved_ap.value("service_type").toString(); + cpPriv->type = QNetworkConfiguration::InternetAccessPoint; + cpPriv->state = QNetworkConfiguration::Defined; + + QNetworkConfigurationPrivatePointer ptr(cpPriv); + accessPointConfigurations.insert(iap_id, ptr); + + mutex.unlock(); + emit configurationAdded(ptr); + mutex.lock(); + +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("IAP: %s, name: %s, ssid: %s, added to known list", + iap_id.toAscii().data(), ptr->name.toAscii().data(), + !ssid.isEmpty() ? ssid.data() : "-"); +#endif + } else { + knownConfigs.removeOne(iap_id); +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("IAP: %s, ssid: %s, already exists in the known list", + iap_id.toAscii().data(), !ssid.isEmpty() ? ssid.data() : "-"); +#endif + } + } + + /* This is skipped in the first update as scanned size is zero */ + if (!scanned.isEmpty()) { + for (int i=0; i<scanned.size(); ++i) { + const Maemo::IcdScanResult ap = scanned.at(i); + + if (ap.scan.network_attrs & ICD_NW_ATTR_IAPNAME) { + /* The network_id is IAP id, so the IAP is a known one */ + QString iapid = ap.scan.network_id.data(); + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iapid); + if (ptr) { + bool changed = false; + + ptr->mutex.lock(); + + if (!ptr->isValid) { + ptr->isValid = true; + changed = true; + } + + /* If this config is the current active one, we do not set it + * to discovered. + */ + if ((ptr->state != QNetworkConfiguration::Discovered) && + (ptr->state != QNetworkConfiguration::Active)) { + ptr->state = QNetworkConfiguration::Discovered; + changed = true; + } + + toIcdConfig(ptr)->network_attrs = ap.scan.network_attrs; + toIcdConfig(ptr)->service_id = ap.scan.service_id; + toIcdConfig(ptr)->service_type = ap.scan.service_type; + toIcdConfig(ptr)->service_attrs = ap.scan.service_attrs; + +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("IAP: %s, ssid: %s, discovered", + iapid.toAscii().data(), toIcdConfig(ptr)->network_id.data()); +#endif + + ptr->mutex.unlock(); + + if (changed) { + mutex.unlock(); + emit configurationChanged(ptr); + mutex.lock(); + } + + if (!ap.scan.network_type.startsWith(QLatin1String("WLAN"))) + continue; // not a wlan AP + + /* Remove scanned AP from discovered WLAN configurations so that we can + * emit configurationRemoved signal later + */ + ptr->mutex.lock(); + QList<SSIDInfo* > known_iaps = notDiscoveredWLANConfigs.values(toIcdConfig(ptr)->network_id); +rescan_list: + if (!known_iaps.isEmpty()) { + for (int k=0; k<known_iaps.size(); ++k) { + SSIDInfo *iap = known_iaps.at(k); + + if (iap->wlan_security == + network_attrs_to_security(ap.scan.network_attrs)) { + /* Remove IAP from the list */ + notDiscoveredWLANConfigs.remove(toIcdConfig(ptr)->network_id, iap); +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "Removed IAP" << iap->iap_id << "from unknown config"; +#endif + known_iaps.removeAt(k); + delete iap; + goto rescan_list; + } + } + } + ptr->mutex.unlock(); + } + } else { + /* Non saved access point data */ + QByteArray scanned_ssid = ap.scan.network_id; + if (!accessPointConfigurations.contains(scanned_ssid)) { + IcdNetworkConfigurationPrivate *cpPriv = new IcdNetworkConfigurationPrivate; + QString hrs = scanned_ssid.data(); + + cpPriv->name = ap.network_name.isEmpty() ? hrs : ap.network_name; + cpPriv->isValid = true; + cpPriv->id = scanned_ssid.data(); // Note: id is now ssid, it should be set to IAP id if the IAP is saved + cpPriv->network_id = scanned_ssid; + cpPriv->iap_type = ap.scan.network_type; + cpPriv->bearerType = bearerTypeFromIapType(cpPriv->iap_type); + cpPriv->network_attrs = ap.scan.network_attrs; + cpPriv->service_id = ap.scan.service_id; + cpPriv->service_type = ap.scan.service_type; + cpPriv->service_attrs = ap.scan.service_attrs; + + cpPriv->type = QNetworkConfiguration::InternetAccessPoint; + cpPriv->state = QNetworkConfiguration::Undefined; + +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "IAP with network id" << cpPriv->id << "was found in the scan."; +#endif + + QNetworkConfigurationPrivatePointer ptr(cpPriv); + accessPointConfigurations.insert(ptr->id, ptr); + + mutex.unlock(); + emit configurationAdded(ptr); + mutex.lock(); + } else { + knownConfigs.removeOne(scanned_ssid); + } + } + } + } + + if (!firstUpdate) { + // Update Defined status to all defined WLAN IAPs which + // could not be found when access points were scanned + QHashIterator<QByteArray, SSIDInfo* > i(notDiscoveredWLANConfigs); + while (i.hasNext()) { + i.next(); + SSIDInfo *iap = i.value(); + QString iap_id = iap->iap_id; + //qDebug() << i.key() << ": " << iap_id; + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iap_id); + if (ptr) { + QMutexLocker configLocker(&ptr->mutex); + + // WLAN AccessPoint configuration could not be Discovered + // => Make sure that configuration state is Defined + if (ptr->state > QNetworkConfiguration::Defined) { + ptr->state = QNetworkConfiguration::Defined; + + configLocker.unlock(); + mutex.unlock(); + emit configurationChanged(ptr); + mutex.lock(); + } + } + } + + /* Remove non existing iaps since last update */ + foreach (const QString &oldIface, knownConfigs) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(oldIface); + if (ptr) { + mutex.unlock(); + emit configurationRemoved(ptr); + mutex.lock(); + //if we would have SNAP support we would have to remove the references + //from existing ServiceNetworks to the removed access point configuration + } + } + } + + QMutableHashIterator<QByteArray, SSIDInfo* > i(notDiscoveredWLANConfigs); + while (i.hasNext()) { + i.next(); + SSIDInfo *iap = i.value(); + delete iap; + i.remove(); + } + + if (!firstUpdate) { + mutex.unlock(); + emit updateCompleted(); + mutex.lock(); + } + + if (firstUpdate) + firstUpdate = false; +} + +QNetworkConfigurationPrivatePointer QIcdEngine::defaultConfiguration() +{ + QMutexLocker locker(&mutex); + + // Here we just return [ANY] request to icd and let the icd decide which IAP to connect. + return userChoiceConfigurations.value(OSSO_IAP_ANY); +} + +void QIcdEngine::startListeningStateSignalsForAllConnections() +{ + // Start listening ICD_DBUS_API_STATE_SIG signals + m_dbusInterface->connection().connect(ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_PATH, + ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_STATE_SIG, + this, SLOT(connectionStateSignalsSlot(QDBusMessage))); +} + +void QIcdEngine::getIcdInitialState() +{ + /* Instead of requesting ICD status asynchronously, we ask it synchronously. + * It ensures that we always get right icd status BEFORE initialize() ends. + * If not, initialize() might end before we got icd status and + * QNetworkConfigurationManager::updateConfigurations() + * call from user might also end before receiving icd status. + * In such case, we come up to a bug: + * QNetworkConfigurationManagerPrivate::isOnline() will be false even + * if we are connected. + */ + Maemo::Icd icd; + QList<Maemo::IcdStateResult> state_results; + QNetworkConfigurationPrivatePointer ptr; + + if (icd.state(state_results) && !state_results.isEmpty()) { + + if (!(state_results.first().params.network_attrs == 0 && + state_results.first().params.network_id.isEmpty())) { + + switch (state_results.first().state) { + case ICD_STATE_CONNECTED: + m_onlineIapId = state_results.first().params.network_id; + + ptr = accessPointConfigurations.value(m_onlineIapId); + if (ptr) { + QMutexLocker configLocker(&ptr->mutex); + ptr->state = QNetworkConfiguration::Active; + configLocker.unlock(); + + mutex.unlock(); + emit configurationChanged(ptr); + mutex.lock(); + } + break; + default: + break; + } + } + } +} + +void QIcdEngine::connectionStateSignalsSlot(QDBusMessage msg) +{ + QMutexLocker locker(&mutex); + + QList<QVariant> arguments = msg.arguments(); + if (arguments[1].toUInt() != 0 || arguments.count() < 8) { + return; + } + + QString iapid = arguments[5].toByteArray().data(); + uint icd_connection_state = arguments[7].toUInt(); + + switch (icd_connection_state) { + case ICD_STATE_CONNECTED: + { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iapid); + if (ptr) { + QMutexLocker configLocker(&ptr->mutex); + + ptr->type = QNetworkConfiguration::InternetAccessPoint; + if (ptr->state != QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Active; + + configLocker.unlock(); + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + + m_onlineIapId = iapid; + } + } else { + // This gets called when new WLAN IAP is created using Connection dialog + // At this point Undefined WLAN configuration has SSID as iap id + // => Because of that configuration can not be found from + // accessPointConfigurations using correct iap id + m_onlineIapId = iapid; + } + break; + } + case ICD_STATE_DISCONNECTED: + { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iapid); + if (ptr) { + QMutexLocker configLocker(&ptr->mutex); + + ptr->type = QNetworkConfiguration::InternetAccessPoint; + if (ptr->state == QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Discovered; + + configLocker.unlock(); + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + + // Note: If ICD switches used IAP from one to another: + // 1) new IAP is reported to be online first + // 2) old IAP is reported to be offline then + // => Device can be reported to be offline only + // if last known online IAP is reported to be disconnected + if (iapid == m_onlineIapId) { + // It's known that there is only one global ICD connection + // => Because ICD state was reported to be DISCONNECTED, Device is offline + m_onlineIapId.clear(); + } + } + } else { + // Disconnected IAP was not found from accessPointConfigurations + // => Reason: Online IAP was removed which resulted ICD to disconnect + if (iapid == m_onlineIapId) { + // It's known that there is only one global ICD connection + // => Because ICD state was reported to be DISCONNECTED, Device is offline + m_onlineIapId.clear(); + } + } + break; + } + default: + break; + } + + locker.unlock(); + emit iapStateChanged(iapid, icd_connection_state); + locker.relock(); +} + +void QIcdEngine::requestUpdate() +{ + QMutexLocker locker(&mutex); + + if (m_scanGoingOn) { + return; + } + m_scanGoingOn = true; + + m_dbusInterface->connection().connect(ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_PATH, + ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_SCAN_SIG, + this, SLOT(asyncUpdateConfigurationsSlot(QDBusMessage))); + + QDBusMessage msg = m_dbusInterface->call(ICD_DBUS_API_SCAN_REQ, + (uint)ICD_SCAN_REQUEST_ACTIVE); + m_typesToBeScanned = msg.arguments()[0].value<QStringList>(); + m_scanTimer.start(ICD_SHORT_SCAN_TIMEOUT); +} + +void QIcdEngine::cancelAsyncConfigurationUpdate() +{ + if (!m_scanGoingOn) { + return; + } + m_scanGoingOn = false; + + if (m_scanTimer.isActive()) { + m_scanTimer.stop(); + } + + m_dbusInterface->connection().disconnect(ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_PATH, + ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_SCAN_SIG, + this, SLOT(asyncUpdateConfigurationsSlot(QDBusMessage))); + + // Stop scanning rounds by calling ICD_DBUS_API_SCAN_CANCEL + // <=> If ICD_DBUS_API_SCAN_CANCEL is not called, new scanning round will + // be started after the module scan timeout. + m_dbusInterface->call(ICD_DBUS_API_SCAN_CANCEL); +} + +void QIcdEngine::finishAsyncConfigurationUpdate() +{ + QMutexLocker locker(&mutex); + + cancelAsyncConfigurationUpdate(); + doRequestUpdate(m_scanResult); + m_scanResult.clear(); +} + +void QIcdEngine::asyncUpdateConfigurationsSlot(QDBusMessage msg) +{ + QMutexLocker locker(&mutex); + + QList<QVariant> arguments = msg.arguments(); + uint icd_scan_status = arguments.takeFirst().toUInt(); + if (icd_scan_status == ICD_SCAN_COMPLETE) { + m_typesToBeScanned.removeOne(arguments[6].toString()); + if (!m_typesToBeScanned.count()) { + locker.unlock(); + finishAsyncConfigurationUpdate(); + locker.relock(); + } + } else { + Maemo::IcdScanResult scanResult; + scanResult.status = icd_scan_status; + scanResult.timestamp = arguments.takeFirst().toUInt(); + scanResult.scan.service_type = arguments.takeFirst().toString(); + scanResult.service_name = arguments.takeFirst().toString(); + scanResult.scan.service_attrs = arguments.takeFirst().toUInt(); + scanResult.scan.service_id = arguments.takeFirst().toString(); + scanResult.service_priority = arguments.takeFirst().toInt(); + scanResult.scan.network_type = arguments.takeFirst().toString(); + scanResult.network_name = arguments.takeFirst().toString(); + scanResult.scan.network_attrs = arguments.takeFirst().toUInt(); + scanResult.scan.network_id = arguments.takeFirst().toByteArray(); + scanResult.network_priority = arguments.takeFirst().toInt(); + scanResult.signal_strength = arguments.takeFirst().toInt(); + scanResult.station_id = arguments.takeFirst().toString(); + scanResult.signal_dB = arguments.takeFirst().toInt(); + + m_scanResult.append(scanResult); + } +} + +void QIcdEngine::cleanup() +{ + if (m_scanGoingOn) { + m_scanTimer.stop(); + m_dbusInterface->call(ICD_DBUS_API_SCAN_CANCEL); + } + if (iapMonitor) + iapMonitor->cleanup(); +} + +bool QIcdEngine::hasIdentifier(const QString &id) +{ + QMutexLocker locker(&mutex); + + return accessPointConfigurations.contains(id) || + snapConfigurations.contains(id) || + userChoiceConfigurations.contains(id); +} + +QNetworkSessionPrivate *QIcdEngine::createSessionBackend() +{ + return new QNetworkSessionPrivateImpl(this); +} + +#include "qicdengine.moc" + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/icd/qicdengine.h b/src/plugins/bearer/icd/qicdengine.h new file mode 100644 index 0000000..d528f15 --- /dev/null +++ b/src/plugins/bearer/icd/qicdengine.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QICDENGINE_H +#define QICDENGINE_H + +#include <QtNetwork/private/qbearerengine_p.h> + +#include <QtCore/qtimer.h> + +#include "maemo_icd.h" + +QT_BEGIN_NAMESPACE + +class QNetworkConfigurationPrivate; +class IapMonitor; +class QDBusInterface; + +inline QNetworkConfiguration::BearerType bearerTypeFromIapType(const QString &iapType) +{ + if (iapType == QLatin1String("WLAN_INFRA") || + iapType == QLatin1String("WLAN_ADHOC")) { + return QNetworkConfiguration::BearerWLAN; + } else if (iapType == QLatin1String("GPRS")) { + return QNetworkConfiguration::BearerHSPA; + } else { + return QNetworkConfiguration::BearerUnknown; + } +} + +class IcdNetworkConfigurationPrivate : public QNetworkConfigurationPrivate +{ +public: + IcdNetworkConfigurationPrivate(); + ~IcdNetworkConfigurationPrivate(); + + virtual QString bearerTypeName() const; + + // In Maemo the id field (defined in QNetworkConfigurationPrivate) + // is the IAP id (which typically is UUID) + QByteArray network_id; // typically WLAN ssid or similar + QString iap_type; // is this one WLAN or GPRS + + QString service_type; + QString service_id; + quint32 service_attrs; + + // Network attributes for this IAP, this is the value returned by icd and + // passed to it when connecting. + quint32 network_attrs; +}; + +inline IcdNetworkConfigurationPrivate *toIcdConfig(QNetworkConfigurationPrivatePointer ptr) +{ + return static_cast<IcdNetworkConfigurationPrivate *>(ptr.data()); +} + +class QIcdEngine : public QBearerEngine +{ + Q_OBJECT + +public: + QIcdEngine(QObject *parent = 0); + ~QIcdEngine(); + + bool hasIdentifier(const QString &id); + + Q_INVOKABLE void initialize(); + Q_INVOKABLE void requestUpdate(); + + QNetworkConfigurationManager::Capabilities capabilities() const; + + QNetworkSessionPrivate *createSessionBackend(); + + QNetworkConfigurationPrivatePointer defaultConfiguration(); + + void deleteConfiguration(const QString &iap_id); + + inline QNetworkConfigurationPrivatePointer configuration(const QString &id) + { + QMutexLocker locker(&mutex); + + return accessPointConfigurations.value(id); + } + + inline void addSessionConfiguration(QNetworkConfigurationPrivatePointer ptr) + { + QMutexLocker locker(&mutex); + + accessPointConfigurations.insert(ptr->id, ptr); + + locker.unlock(); + emit configurationAdded(ptr); + } + + inline void changedSessionConfiguration(QNetworkConfigurationPrivatePointer ptr) + { + emit configurationChanged(ptr); + } + + void cleanup(); + + void addConfiguration(QString &iap_id); + +Q_SIGNALS: + void iapStateChanged(const QString& iapid, uint icd_connection_state); + +private Q_SLOTS: + void finishAsyncConfigurationUpdate(); + void asyncUpdateConfigurationsSlot(QDBusMessage msg); + void connectionStateSignalsSlot(QDBusMessage msg); + +private: + void startListeningStateSignalsForAllConnections(); + void doRequestUpdate(QList<Maemo::IcdScanResult> scanned = QList<Maemo::IcdScanResult>()); + void cancelAsyncConfigurationUpdate(); + void getIcdInitialState(); + +private: + IapMonitor *iapMonitor; + QDBusInterface *m_dbusInterface; + QTimer m_scanTimer; + QString m_onlineIapId; + QStringList m_typesToBeScanned; + QList<Maemo::IcdScanResult> m_scanResult; + + bool firstUpdate; + bool m_scanGoingOn; +}; + +QT_END_NAMESPACE + +#endif // QICDENGINE_H diff --git a/src/plugins/bearer/icd/qnetworksession_impl.cpp b/src/plugins/bearer/icd/qnetworksession_impl.cpp new file mode 100644 index 0000000..8d0f587 --- /dev/null +++ b/src/plugins/bearer/icd/qnetworksession_impl.cpp @@ -0,0 +1,1072 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnetworksession_impl.h" +#include "qicdengine.h" + +#include <QHash> + +#include <maemo_icd.h> +#include <iapconf.h> +#include <proxyconf.h> + +#include <ifaddrs.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +QDBusArgument &operator<<(QDBusArgument &argument, + const ICd2DetailsDBusStruct &icd2) +{ + argument.beginStructure(); + + argument << icd2.serviceType; + argument << icd2.serviceAttributes; + argument << icd2.setviceId; + argument << icd2.networkType; + argument << icd2.networkAttributes; + argument << icd2.networkId; + + argument.endStructure(); + + return argument; +} + +const QDBusArgument &operator>>(const QDBusArgument &argument, + ICd2DetailsDBusStruct &icd2) +{ + argument.beginStructure(); + + argument >> icd2.serviceType; + argument >> icd2.serviceAttributes; + argument >> icd2.setviceId; + argument >> icd2.networkType; + argument >> icd2.networkAttributes; + argument >> icd2.networkId; + + argument.endStructure(); + + return argument; +} + +const QDBusArgument &operator>>(const QDBusArgument &argument, + ICd2DetailsList &detailsList) +{ + argument.beginArray(); + detailsList.clear(); + + while (!argument.atEnd()) { + ICd2DetailsDBusStruct element; + argument >> element; + detailsList.append(element); + } + + argument.endArray(); + return argument; +} + +QDBusArgument &operator<<(QDBusArgument &argument, + const ICd2DetailsList &detailsList) +{ + argument.beginArray(qMetaTypeId<ICd2DetailsDBusStruct>()); + + for (int i = 0; i < detailsList.count(); ++i) + argument << detailsList[i]; + + argument.endArray(); + + return argument; +} + +static QHash<QString, QVariant> properties; + +static QString get_network_interface(); + +void QNetworkSessionPrivateImpl::iapStateChanged(const QString& iapid, uint icd_connection_state) +{ + if ((publicConfig.type() == QNetworkConfiguration::UserChoice) && opened) { + updateIdentifier(iapid); + } + + if (((publicConfig.type() == QNetworkConfiguration::UserChoice) && + (activeConfig.identifier() == iapid)) || + (publicConfig.identifier() == iapid)) { + switch (icd_connection_state) { + case ICD_STATE_CONNECTING: + updateState(QNetworkSession::Connecting); + break; + case ICD_STATE_CONNECTED: + updateState(QNetworkSession::Connected); + break; + case ICD_STATE_DISCONNECTING: + updateState(QNetworkSession::Closing); + break; + case ICD_STATE_DISCONNECTED: + updateState(QNetworkSession::Disconnected); + break; + default: + break; + } + } +} + +void QNetworkSessionPrivateImpl::cleanupSession(void) +{ + QObject::disconnect(q, SIGNAL(stateChanged(QNetworkSession::State)), + this, SLOT(updateProxies(QNetworkSession::State))); +} + + +void QNetworkSessionPrivateImpl::updateState(QNetworkSession::State newState) +{ + if (newState != state) { + if (newState == QNetworkSession::Disconnected) { + if (isOpen) { + // The Session was aborted by the user or system + lastError = QNetworkSession::SessionAbortedError; + emit QNetworkSessionPrivate::error(lastError); + emit closed(); + } + if (m_stopTimer.isActive()) { + // Session was closed by calling stop() + m_stopTimer.stop(); + } + isOpen = false; + opened = false; + currentNetworkInterface.clear(); + if (publicConfig.type() == QNetworkConfiguration::UserChoice) { + copyConfig(publicConfig, activeConfig); + IcdNetworkConfigurationPrivate *icdConfig = + toIcdConfig(privateConfiguration(activeConfig)); + + icdConfig->mutex.lock(); + icdConfig->state = QNetworkConfiguration::Defined; + icdConfig->mutex.unlock(); + } else { + if (!activeConfig.isValid()) { + // Active configuration (IAP) was removed from system + // => Connection was disconnected and configuration became + // invalid + // => Also Session state must be changed to invalid + newState = QNetworkSession::Invalid; + } + } + } else if (newState == QNetworkSession::Connected) { + if (opened) { + isOpen = true; + } + if (publicConfig.type() == QNetworkConfiguration::UserChoice) { + IcdNetworkConfigurationPrivate *icdConfig = + toIcdConfig(privateConfiguration(activeConfig)); + + icdConfig->mutex.lock(); + icdConfig->state = QNetworkConfiguration::Active; + icdConfig->type = QNetworkConfiguration::InternetAccessPoint; + icdConfig->mutex.unlock(); + } + + IcdNetworkConfigurationPrivate *icdConfig = + toIcdConfig(privateConfiguration(publicConfig)); + + icdConfig->mutex.lock(); + icdConfig->state = QNetworkConfiguration::Active; + icdConfig->mutex.unlock(); + } + + if (newState != state) { + state = newState; + emit stateChanged(newState); + } + } +} + + +void QNetworkSessionPrivateImpl::updateIdentifier(const QString &newId) +{ + if (publicConfig.type() == QNetworkConfiguration::UserChoice) { + IcdNetworkConfigurationPrivate *icdConfig = + toIcdConfig(privateConfiguration(activeConfig)); + + icdConfig->mutex.lock(); + icdConfig->network_attrs |= ICD_NW_ATTR_IAPNAME; + icdConfig->id = newId; + icdConfig->mutex.unlock(); + } else { + IcdNetworkConfigurationPrivate *icdConfig = + toIcdConfig(privateConfiguration(publicConfig)); + + icdConfig->mutex.lock(); + icdConfig->network_attrs |= ICD_NW_ATTR_IAPNAME; + if (icdConfig->id != newId) + icdConfig->id = newId; + icdConfig->mutex.unlock(); + } +} + + +QNetworkSessionPrivateImpl::Statistics QNetworkSessionPrivateImpl::getStatistics() const +{ + /* This could be also implemented by using the Maemo::Icd::statistics() + * that gets the statistics data for a specific IAP. Change if + * necessary. + */ + Maemo::Icd icd; + QList<Maemo::IcdStatisticsResult> stats_results; + Statistics stats = { 0, 0, 0}; + + if (!icd.statistics(stats_results)) + return stats; + + foreach (const Maemo::IcdStatisticsResult &res, stats_results) { + if (res.params.network_attrs & ICD_NW_ATTR_IAPNAME) { + /* network_id is the IAP UUID */ + if (QString(res.params.network_id.data()) == activeConfig.identifier()) { + stats.txData = res.bytes_sent; + stats.rxData = res.bytes_received; + stats.activeTime = res.time_active; + } + } else { + /* We probably will never get to this branch */ + IcdNetworkConfigurationPrivate *icdConfig = + toIcdConfig(privateConfiguration(activeConfig)); + + icdConfig->mutex.lock(); + if (res.params.network_id == icdConfig->network_id) { + stats.txData = res.bytes_sent; + stats.rxData = res.bytes_received; + stats.activeTime = res.time_active; + } + icdConfig->mutex.unlock(); + } + } + + return stats; +} + + +quint64 QNetworkSessionPrivateImpl::bytesWritten() const +{ + return getStatistics().txData; +} + +quint64 QNetworkSessionPrivateImpl::bytesReceived() const +{ + return getStatistics().rxData; +} + +quint64 QNetworkSessionPrivateImpl::activeTime() const +{ + return getStatistics().activeTime; +} + + +QNetworkConfiguration& QNetworkSessionPrivateImpl::copyConfig(QNetworkConfiguration &fromConfig, + QNetworkConfiguration &toConfig, + bool deepCopy) +{ + IcdNetworkConfigurationPrivate *cpPriv; + if (deepCopy) { + cpPriv = new IcdNetworkConfigurationPrivate; + setPrivateConfiguration(toConfig, QNetworkConfigurationPrivatePointer(cpPriv)); + } else { + cpPriv = toIcdConfig(privateConfiguration(toConfig)); + } + + IcdNetworkConfigurationPrivate *fromPriv = toIcdConfig(privateConfiguration(fromConfig)); + + QMutexLocker toLocker(&cpPriv->mutex); + QMutexLocker fromLocker(&fromPriv->mutex); + + cpPriv->name = fromPriv->name; + cpPriv->isValid = fromPriv->isValid; + // Note that we do not copy id field here as the publicConfig does + // not contain a valid IAP id. + cpPriv->state = fromPriv->state; + cpPriv->type = fromPriv->type; + cpPriv->roamingSupported = fromPriv->roamingSupported; + cpPriv->purpose = fromPriv->purpose; + cpPriv->network_id = fromPriv->network_id; + cpPriv->iap_type = fromPriv->iap_type; + cpPriv->bearerType = fromPriv->bearerType; + cpPriv->network_attrs = fromPriv->network_attrs; + cpPriv->service_type = fromPriv->service_type; + cpPriv->service_id = fromPriv->service_id; + cpPriv->service_attrs = fromPriv->service_attrs; + + return toConfig; +} + + +/* This is called by QNetworkSession constructor and it updates the current + * state of the configuration. + */ +void QNetworkSessionPrivateImpl::syncStateWithInterface() +{ + /* Initially we are not active although the configuration might be in + * connected state. + */ + isOpen = false; + opened = false; + + connect(engine, SIGNAL(iapStateChanged(const QString&, uint)), + this, SLOT(iapStateChanged(const QString&, uint))); + + QObject::connect(q, SIGNAL(stateChanged(QNetworkSession::State)), this, SLOT(updateProxies(QNetworkSession::State))); + + state = QNetworkSession::Invalid; + lastError = QNetworkSession::UnknownSessionError; + + switch (publicConfig.type()) { + case QNetworkConfiguration::InternetAccessPoint: + activeConfig = publicConfig; + break; + case QNetworkConfiguration::ServiceNetwork: + serviceConfig = publicConfig; + break; + case QNetworkConfiguration::UserChoice: + // active config will contain correct data after open() has succeeded + copyConfig(publicConfig, activeConfig); + + /* We create new configuration that holds the actual configuration + * returned by icd. This way publicConfig still contains the + * original user specified configuration. + * + * Note that the new activeConfig configuration is not inserted + * to configurationManager as manager class will get the newly + * connected configuration from gconf when the IAP is saved. + * This configuration manager update is done by IapMonitor class. + * If the ANY connection fails in open(), then the configuration + * data is not saved to gconf and will not be added to + * configuration manager IAP list. + */ +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug()<<"New configuration created for" << publicConfig.identifier(); +#endif + break; + default: + /* Invalid configuration, no point continuing */ + return; + } + + if (!activeConfig.isValid()) + return; + + /* Get the initial state from icd */ + Maemo::Icd icd; + QList<Maemo::IcdStateResult> state_results; + + /* Update the active config from first connection, this is ok as icd + * supports only one connection anyway. + */ + if (icd.state(state_results) && !state_results.isEmpty()) { + /* If we did not get full state back, then we are not + * connected and can skip the next part. + */ + if (!(state_results.first().params.network_attrs == 0 && + state_results.first().params.network_id.isEmpty())) { + + /* If we try to connect to specific IAP and we get results back + * that tell the icd is actually connected to another IAP, + * then do not update current state etc. + */ + if (publicConfig.type() == QNetworkConfiguration::UserChoice || + publicConfig.identifier() == state_results.first().params.network_id) { + switch (state_results.first().state) { + case ICD_STATE_DISCONNECTED: + state = QNetworkSession::Disconnected; + if (QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig)) { + ptr->mutex.lock(); + ptr->isValid = true; + ptr->mutex.unlock(); + } + break; + case ICD_STATE_CONNECTING: + state = QNetworkSession::Connecting; + if (QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig)) { + ptr->mutex.lock(); + ptr->isValid = true; + ptr->mutex.unlock(); + } + break; + case ICD_STATE_CONNECTED: + { + if (!state_results.first().error.isEmpty()) + break; + + const QString id = state_results.first().params.network_id; + + QNetworkConfiguration config = manager.configurationFromIdentifier(id); + if (config.isValid()) { + //we don't want the copied data if the config is already known by the manager + //just reuse it so that existing references to the old data get the same update + setPrivateConfiguration(activeConfig, privateConfiguration(config)); + } + + QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig); + + QMutexLocker configLocker(&ptr->mutex); + + state = QNetworkSession::Connected; + toIcdConfig(ptr)->network_id = state_results.first().params.network_id; + ptr->id = toIcdConfig(ptr)->network_id; + toIcdConfig(ptr)->network_attrs = state_results.first().params.network_attrs; + toIcdConfig(ptr)->iap_type = state_results.first().params.network_type; + ptr->bearerType = bearerTypeFromIapType(toIcdConfig(ptr)->iap_type); + toIcdConfig(ptr)->service_type = state_results.first().params.service_type; + toIcdConfig(ptr)->service_id = state_results.first().params.service_id; + toIcdConfig(ptr)->service_attrs = state_results.first().params.service_attrs; + ptr->type = QNetworkConfiguration::InternetAccessPoint; + ptr->state = QNetworkConfiguration::Active; + ptr->isValid = true; + currentNetworkInterface = get_network_interface(); + + Maemo::IAPConf iap_name(ptr->id); + QString name_value = iap_name.value("name").toString(); + if (!name_value.isEmpty()) + ptr->name = name_value; + else + ptr->name = ptr->id; + + const QString identifier = ptr->id; + + configLocker.unlock(); + + // Add the new active configuration to manager or update the old config + if (!engine->hasIdentifier(identifier)) + engine->addSessionConfiguration(ptr); + else + engine->changedSessionConfiguration(ptr); + } + break; + + case ICD_STATE_DISCONNECTING: + state = QNetworkSession::Closing; + if (QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig)) { + ptr->mutex.lock(); + ptr->isValid = true; + ptr->mutex.unlock(); + } + break; + default: + break; + } + } + } else { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "status_req tells icd is not connected"; +#endif + } + } else { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "status_req did not return any results from icd"; +#endif + } + + networkConfigurationsChanged(); +} + + +void QNetworkSessionPrivateImpl::networkConfigurationsChanged() +{ + if (serviceConfig.isValid()) + updateStateFromServiceNetwork(); + else + updateStateFromActiveConfig(); +} + + +void QNetworkSessionPrivateImpl::updateStateFromServiceNetwork() +{ + QNetworkSession::State oldState = state; + + foreach (const QNetworkConfiguration &config, serviceConfig.children()) { + if ((config.state() & QNetworkConfiguration::Active) != QNetworkConfiguration::Active) + continue; + + if (activeConfig != config) { + activeConfig = config; + emit newConfigurationActivated(); + } + + state = QNetworkSession::Connected; + if (state != oldState) + emit stateChanged(state); + + return; + } + + if (serviceConfig.children().isEmpty()) + state = QNetworkSession::NotAvailable; + else + state = QNetworkSession::Disconnected; + + if (state != oldState) + emit stateChanged(state); +} + + +void QNetworkSessionPrivateImpl::clearConfiguration(QNetworkConfiguration &config) +{ + IcdNetworkConfigurationPrivate *icdConfig = toIcdConfig(privateConfiguration(config)); + + QMutexLocker locker(&icdConfig->mutex); + + icdConfig->network_id.clear(); + icdConfig->iap_type.clear(); + icdConfig->network_attrs = 0; + icdConfig->service_type.clear(); + icdConfig->service_id.clear(); + icdConfig->service_attrs = 0; +} + + +void QNetworkSessionPrivateImpl::updateStateFromActiveConfig() +{ + QNetworkSession::State oldState = state; + + bool newActive = false; + + if (!activeConfig.isValid()) + return; + + if (!activeConfig.isValid()) { + state = QNetworkSession::Invalid; + clearConfiguration(activeConfig); + } else if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + state = QNetworkSession::Connected; + newActive = opened; + } else if ((activeConfig.state() & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered) { + state = QNetworkSession::Disconnected; + } else if ((activeConfig.state() & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) { + state = QNetworkSession::NotAvailable; + } else if ((activeConfig.state() & QNetworkConfiguration::Undefined) == QNetworkConfiguration::Undefined) { + state = QNetworkSession::NotAvailable; + } + + bool oldActive = isOpen; + isOpen = newActive; + + if (!oldActive && isOpen) + emit quitPendingWaitsForOpened(); + + if (oldActive && !isOpen) + emit closed(); + + if (oldState != state) { + emit stateChanged(state); + + if (state == QNetworkSession::Disconnected && oldActive) { +#ifdef BEARER_MANAGEMENT_DEBUG + //qDebug()<<"session aborted error emitted for"<<activeConfig.identifier(); +#endif + lastError = QNetworkSession::SessionAbortedError; + emit QNetworkSessionPrivate::error(lastError); + } + } + +#ifdef BEARER_MANAGEMENT_DEBUG + //qDebug()<<"oldState ="<<oldState<<" state ="<<state<<" oldActive ="<<oldActive<<" newActive ="<<newActive<<" opened ="<<opened; +#endif +} + +static QString get_network_interface() +{ + Maemo::Icd icd; + QList<Maemo::IcdAddressInfoResult> addr_results; + uint ret; + QString iface; + + ret = icd.addrinfo(addr_results); + if (ret == 0) { + /* No results */ +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "Cannot get addrinfo from icd, are you connected or is icd running?"; +#endif + return iface; + } + + if (addr_results.first().ip_info.isEmpty()) + return QString(); + + const char *address = addr_results.first().ip_info.first().address.toAscii().constData(); + struct in_addr addr; + if (inet_aton(address, &addr) == 0) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "address" << address << "invalid"; +#endif + return iface; + } + + struct ifaddrs *ifaddr, *ifa; + int family; + + if (getifaddrs(&ifaddr) == -1) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "getifaddrs() failed"; +#endif + return iface; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr) { + family = ifa->ifa_addr->sa_family; + if (family != AF_INET) { + continue; /* Currently only IPv4 is supported by icd dbus interface */ + } + if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == addr.s_addr) { + iface = QString(ifa->ifa_name); + break; + } + } + } + + freeifaddrs(ifaddr); + return iface; +} + + +void QNetworkSessionPrivateImpl::open() +{ + if (m_stopTimer.isActive()) { + m_stopTimer.stop(); + } + if (!publicConfig.isValid()) { + lastError = QNetworkSession::InvalidConfigurationError; + emit QNetworkSessionPrivate::error(lastError); + return; + } + if (serviceConfig.isValid()) { + lastError = QNetworkSession::OperationNotSupportedError; + emit QNetworkSessionPrivate::error(lastError); + } else if (!opened) { + if (publicConfig.type() == QNetworkConfiguration::UserChoice) { + /* Caller is trying to connect to default IAP. + * At this time we will not know the IAP details so we just + * connect and update the active config when the IAP is + * connected. + */ + opened = true; + state = QNetworkSession::Connecting; + emit stateChanged(state); + QTimer::singleShot(0, this, SLOT(do_open())); + return; + } + + /* User is connecting to one specific IAP. If that IAP is not + * in discovered state we cannot continue. + */ + if ((activeConfig.state() & QNetworkConfiguration::Discovered) != + QNetworkConfiguration::Discovered) { + lastError =QNetworkSession::InvalidConfigurationError; + emit QNetworkSessionPrivate::error(lastError); + return; + } + opened = true; + + if ((activeConfig.state() & QNetworkConfiguration::Active) != QNetworkConfiguration::Active) { + state = QNetworkSession::Connecting; + emit stateChanged(state); + QTimer::singleShot(0, this, SLOT(do_open())); + return; + } + isOpen = (activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active; + if (isOpen) + emit quitPendingWaitsForOpened(); + } else { + /* We seem to be active so inform caller */ + emit quitPendingWaitsForOpened(); + } +} + +void QNetworkSessionPrivateImpl::do_open() +{ + icd_connection_flags flags = connectFlags; + QString iap = publicConfig.identifier(); + + if (state == QNetworkSession::Connected) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "Already connected to" << activeConfig.identifier(); +#endif + emit stateChanged(QNetworkSession::Connected); + emit quitPendingWaitsForOpened(); + return; + } + + if (publicConfig.type() == QNetworkConfiguration::UserChoice) + config = activeConfig; + else + config = publicConfig; + + if (iap == OSSO_IAP_ANY) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "connecting to default IAP" << iap; +#endif + m_connectRequestTimer.start(ICD_LONG_CONNECT_TIMEOUT); + m_dbusInterface->asyncCall(ICD_DBUS_API_CONNECT_REQ, (uint)flags); // Return value ignored + m_asynchCallActive = true; + } else { + IcdNetworkConfigurationPrivate *icdConfig = toIcdConfig(privateConfiguration(config)); + + icdConfig->mutex.lock(); + ICd2DetailsDBusStruct icd2; + icd2.serviceType = icdConfig->service_type; + icd2.serviceAttributes = icdConfig->service_attrs; + icd2.setviceId = icdConfig->service_id; + icd2.networkType = icdConfig->iap_type; + icd2.networkAttributes = icdConfig->network_attrs; + if (icdConfig->network_attrs & ICD_NW_ATTR_IAPNAME) { + icd2.networkId = QByteArray(iap.toLatin1()); + } else { + icd2.networkId = icdConfig->network_id; + } + icdConfig->mutex.unlock(); + +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("connecting to %s/%s/0x%x/%s/0x%x/%s", + icd2.networkId.data(), + icd2.networkType.toAscii().constData(), + icd2.networkAttributes, + icd2.serviceType.toAscii().constData(), + icd2.serviceAttributes, + icd2.setviceId.toAscii().constData()); +#endif + + ICd2DetailsList paramArray; + paramArray.append(icd2); + m_connectRequestTimer.start(ICD_LONG_CONNECT_TIMEOUT); + m_dbusInterface->asyncCall(ICD_DBUS_API_CONNECT_REQ, (uint)flags, QVariant::fromValue(paramArray)); // Return value ignored + m_asynchCallActive = true; + } +} + +void QNetworkSessionPrivateImpl::stateChange(const QDBusMessage& rep) +{ + if (m_asynchCallActive == true) { + if (m_connectRequestTimer.isActive()) + m_connectRequestTimer.stop(); + m_asynchCallActive = false; + + QString result = rep.arguments().at(5).toString(); // network id or empty string + QString connected_iap = result; + if (connected_iap.isEmpty()) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "connect to"<< publicConfig.identifier() << "failed, result is empty"; +#endif + updateState(QNetworkSession::Disconnected); + emit QNetworkSessionPrivate::error(QNetworkSession::SessionAbortedError); + if (publicConfig.type() == QNetworkConfiguration::UserChoice) + copyConfig(publicConfig, activeConfig); + return; + } + + /* If the user tried to connect to some specific connection (foo) + * and we were already connected to some other connection (bar), + * then we cannot activate this session although icd has a valid + * connection to somewhere. + */ + if ((publicConfig.type() != QNetworkConfiguration::UserChoice) && + (connected_iap != config.identifier())) { + updateState(QNetworkSession::Disconnected); + emit QNetworkSessionPrivate::error(QNetworkSession::UnknownSessionError); + return; + } + + IcdNetworkConfigurationPrivate *icdConfig = toIcdConfig(privateConfiguration(config)); + + /* Did we connect to non saved IAP? */ + icdConfig->mutex.lock(); + if (!(icdConfig->network_attrs & ICD_NW_ATTR_IAPNAME)) { + /* Because the connection succeeded, the IAP is now known. + */ + icdConfig->network_attrs |= ICD_NW_ATTR_IAPNAME; + icdConfig->id = connected_iap; + } + + /* User might have changed the IAP name when a new IAP was saved */ + Maemo::IAPConf iap_name(icdConfig->id); + QString name = iap_name.value("name").toString(); + if (!name.isEmpty()) + icdConfig->name = name; + + icdConfig->iap_type = rep.arguments().at(3).toString(); // connect_result.connect.network_type; + icdConfig->bearerType = bearerTypeFromIapType(icdConfig->iap_type); + icdConfig->isValid = true; + icdConfig->state = QNetworkConfiguration::Active; + icdConfig->type = QNetworkConfiguration::InternetAccessPoint; + + icdConfig->mutex.unlock(); + + startTime = QDateTime::currentDateTime(); + updateState(QNetworkSession::Connected); + //currentNetworkInterface = get_network_interface(); +#ifdef BEARER_MANAGEMENT_DEBUG + //qDebug() << "connected to" << result << config.name() << "at" << currentNetworkInterface; +#endif + + /* We first check if the configuration already exists in the manager + * and if it is not found there, we then insert it. Note that this + * is only done for user choice config only because it can be missing + * from config manager list. + */ + if (publicConfig.type() == QNetworkConfiguration::UserChoice) { + if (!engine->hasIdentifier(result)) { + engine->addSessionConfiguration(privateConfiguration(config)); + } else { + QNetworkConfigurationPrivatePointer priv = engine->configuration(result); + QNetworkConfiguration reference; + setPrivateConfiguration(reference, priv); + copyConfig(config, reference, false); + privateConfiguration(reference)->id = result; // Note: Id was not copied in copyConfig() function + config = reference; + activeConfig = reference; + engine->changedSessionConfiguration(privateConfiguration(config)); + +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug()<<"Existing configuration"<<result<<"updated in manager in open"; +#endif + } + } + + emit quitPendingWaitsForOpened(); + } +} + +void QNetworkSessionPrivateImpl::connectTimeout() +{ + updateState(QNetworkSession::Disconnected); + if (publicConfig.type() == QNetworkConfiguration::UserChoice) + copyConfig(publicConfig, activeConfig); + emit QNetworkSessionPrivate::error(QNetworkSession::UnknownSessionError); +} + +void QNetworkSessionPrivateImpl::close() +{ + if (m_connectRequestTimer.isActive()) + m_connectRequestTimer.stop(); + + if (serviceConfig.isValid()) { + lastError = QNetworkSession::OperationNotSupportedError; + emit QNetworkSessionPrivate::error(lastError); + } else if (isOpen) { + if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + // We will not wait any disconnect from icd as it might never come +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "closing session" << publicConfig.identifier(); +#endif + state = QNetworkSession::Closing; + emit stateChanged(state); + + // we fake a disconnection, session error is sent + updateState(QNetworkSession::Disconnected); + + opened = false; + isOpen = false; + + m_dbusInterface->call(ICD_DBUS_API_DISCONNECT_REQ, ICD_CONNECTION_FLAG_APPLICATION_EVENT); + startTime = QDateTime(); + } else { + opened = false; + isOpen = false; + emit closed(); + } + } +} + + +void QNetworkSessionPrivateImpl::stop() +{ + if (m_connectRequestTimer.isActive()) + m_connectRequestTimer.stop(); + + if (serviceConfig.isValid()) { + lastError = QNetworkSession::OperationNotSupportedError; + emit QNetworkSessionPrivate::error(lastError); + } else { + if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "stopping session" << publicConfig.identifier(); +#endif + state = QNetworkSession::Closing; + emit stateChanged(state); + + // we fake a disconnection, a session error is sent also + updateState(QNetworkSession::Disconnected); + + opened = false; + isOpen = false; + + m_dbusInterface->call(ICD_DBUS_API_DISCONNECT_REQ, ICD_CONNECTION_FLAG_APPLICATION_EVENT); + startTime = QDateTime(); + } else { + opened = false; + isOpen = false; + emit closed(); + } + } +} + +void QNetworkSessionPrivateImpl::finishStopBySendingClosedSignal() +{ + if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + state = QNetworkSession::Connected; + emit stateChanged(state); + } + + emit closed(); +} + +void QNetworkSessionPrivateImpl::migrate() +{ +} + + +void QNetworkSessionPrivateImpl::accept() +{ +} + + +void QNetworkSessionPrivateImpl::ignore() +{ +} + + +void QNetworkSessionPrivateImpl::reject() +{ +} + +#ifndef QT_NO_NETWORKINTERFACE +QNetworkInterface QNetworkSessionPrivateImpl::currentInterface() const +{ + if (!publicConfig.isValid() || state != QNetworkSession::Connected) + return QNetworkInterface(); + + if (currentNetworkInterface.isEmpty()) + return QNetworkInterface(); + + return QNetworkInterface::interfaceFromName(currentNetworkInterface); +} +#endif + +void QNetworkSessionPrivateImpl::setSessionProperty(const QString& key, const QVariant& value) +{ + if (value.isValid()) { + properties.insert(key, value); + + if (key == "ConnectInBackground") { + bool v = value.toBool(); + if (v) + connectFlags = ICD_CONNECTION_FLAG_APPLICATION_EVENT; + else + connectFlags = ICD_CONNECTION_FLAG_USER_EVENT; + } + } else { + properties.remove(key); + + /* Set default value when property is removed */ + if (key == "ConnectInBackground") + connectFlags = ICD_CONNECTION_FLAG_USER_EVENT; + } +} + + +QVariant QNetworkSessionPrivateImpl::sessionProperty(const QString& key) const +{ + return properties.value(key); +} + + +QString QNetworkSessionPrivateImpl::errorString() const +{ + QString errorStr; + switch(q->error()) { + case QNetworkSession::RoamingError: + errorStr = QNetworkSessionPrivateImpl::tr("Roaming error"); + break; + case QNetworkSession::SessionAbortedError: + errorStr = QNetworkSessionPrivateImpl::tr("Session aborted by user or system"); + break; + case QNetworkSession::InvalidConfigurationError: + errorStr = QNetworkSessionPrivateImpl::tr("The specified configuration cannot be used."); + break; + default: + case QNetworkSession::UnknownSessionError: + errorStr = QNetworkSessionPrivateImpl::tr("Unidentified Error"); + break; + } + return errorStr; +} + + +QNetworkSession::SessionError QNetworkSessionPrivateImpl::error() const +{ + return QNetworkSession::UnknownSessionError; +} + +void QNetworkSessionPrivateImpl::updateProxies(QNetworkSession::State newState) +{ + if ((newState == QNetworkSession::Connected) && + (newState != currentState)) + updateProxyInformation(); + else if ((newState == QNetworkSession::Disconnected) && + (currentState == QNetworkSession::Closing)) + clearProxyInformation(); + + currentState = newState; +} + + +void QNetworkSessionPrivateImpl::updateProxyInformation() +{ + Maemo::ProxyConf::update(); +} + + +void QNetworkSessionPrivateImpl::clearProxyInformation() +{ + Maemo::ProxyConf::clear(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/icd/qnetworksession_impl.h b/src/plugins/bearer/icd/qnetworksession_impl.h new file mode 100644 index 0000000..9ef9dc3 --- /dev/null +++ b/src/plugins/bearer/icd/qnetworksession_impl.h @@ -0,0 +1,229 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNETWORKSESSION_IMPL_H +#define QNETWORKSESSION_IMPL_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtNetwork/private/qnetworksession_p.h> +#include <QtNetwork/qnetworkconfigmanager.h> + +#include <QtCore/qdatetime.h> +#include <QtCore/qtimer.h> +#include <QtCore/quuid.h> + +#include <QtDBus/qdbusconnection.h> +#include <QtDBus/qdbusinterface.h> +#include <QtDBus/qdbusmessage.h> +#include <QtDBus/qdbusmetatype.h> + +#include <icd/dbus_api.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +class QIcdEngine; + +struct ICd2DetailsDBusStruct +{ + QString serviceType; + uint serviceAttributes; + QString setviceId; + QString networkType; + uint networkAttributes; + QByteArray networkId; +}; + +typedef QList<ICd2DetailsDBusStruct> ICd2DetailsList; + +class QNetworkSessionPrivateImpl : public QNetworkSessionPrivate +{ + Q_OBJECT + +public: + QNetworkSessionPrivateImpl(QIcdEngine *engine) + : engine(engine), + connectFlags(ICD_CONNECTION_FLAG_USER_EVENT), + currentState(QNetworkSession::Invalid), + m_asynchCallActive(false) + { + m_stopTimer.setSingleShot(true); + connect(&m_stopTimer, SIGNAL(timeout()), this, SLOT(finishStopBySendingClosedSignal())); + + QDBusConnection systemBus = QDBusConnection::connectToBus( + QDBusConnection::SystemBus, + QUuid::createUuid().toString()); + + m_dbusInterface = new QDBusInterface(ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_PATH, + ICD_DBUS_API_INTERFACE, + systemBus, + this); + + systemBus.connect(ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_PATH, + ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_CONNECT_SIG, + this, + SLOT(stateChange(const QDBusMessage&))); + + qDBusRegisterMetaType<ICd2DetailsDBusStruct>(); + qDBusRegisterMetaType<ICd2DetailsList>(); + + m_connectRequestTimer.setSingleShot(true); + connect(&m_connectRequestTimer, SIGNAL(timeout()), this, SLOT(connectTimeout())); + } + + ~QNetworkSessionPrivateImpl() + { + cleanupSession(); + + QDBusConnection::disconnectFromBus(m_dbusInterface->connection().name()); + } + + //called by QNetworkSession constructor and ensures + //that the state is immediately updated (w/o actually opening + //a session). Also this function should take care of + //notification hooks to discover future state changes. + void syncStateWithInterface(); + +#ifndef QT_NO_NETWORKINTERFACE + QNetworkInterface currentInterface() const; +#endif + QVariant sessionProperty(const QString& key) const; + void setSessionProperty(const QString& key, const QVariant& value); + + void open(); + void close(); + void stop(); + + void migrate(); + void accept(); + void ignore(); + void reject(); + + QString errorString() const; //must return translated string + QNetworkSession::SessionError error() const; + + quint64 bytesWritten() const; + quint64 bytesReceived() const; + quint64 activeTime() const; + +private: + void updateStateFromServiceNetwork(); + void updateStateFromActiveConfig(); + +private Q_SLOTS: + void do_open(); + void networkConfigurationsChanged(); + void iapStateChanged(const QString& iapid, uint icd_connection_state); + void updateProxies(QNetworkSession::State newState); + void finishStopBySendingClosedSignal(); + void stateChange(const QDBusMessage& rep); + void connectTimeout(); + +private: + QNetworkConfigurationManager manager; + QIcdEngine *engine; + + struct Statistics { + quint64 txData; + quint64 rxData; + quint64 activeTime; + }; + + // The config set on QNetworkSession. + QNetworkConfiguration config; + + QNetworkConfiguration& copyConfig(QNetworkConfiguration &fromConfig, QNetworkConfiguration &toConfig, bool deepCopy = true); + void clearConfiguration(QNetworkConfiguration &config); + + bool opened; + icd_connection_flags connectFlags; + + QNetworkSession::SessionError lastError; + + QDateTime startTime; + QString currentNetworkInterface; + friend class IcdListener; + void updateState(QNetworkSession::State); + void updateIdentifier(const QString &newId); + Statistics getStatistics() const; + void cleanupSession(void); + + void updateProxyInformation(); + void clearProxyInformation(); + QNetworkSession::State currentState; + + QDBusInterface *m_dbusInterface; + + QTimer m_stopTimer; + + bool m_asynchCallActive; + QTimer m_connectRequestTimer; +}; + +// Marshall the ICd2DetailsDBusStruct data into a D-Bus argument +QDBusArgument &operator<<(QDBusArgument &argument, const ICd2DetailsDBusStruct &icd2); + +// Retrieve the ICd2DetailsDBusStruct data from the D-Bus argument +const QDBusArgument &operator>>(const QDBusArgument &argument, ICd2DetailsDBusStruct &icd2); + +Q_DECLARE_METATYPE(ICd2DetailsDBusStruct); +Q_DECLARE_METATYPE(ICd2DetailsList); + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT + +#endif //QNETWORKSESSIONPRIVATE_H + diff --git a/src/plugins/bearer/icd/wlan-utils.h b/src/plugins/bearer/icd/wlan-utils.h new file mode 100644 index 0000000..1d9e89d --- /dev/null +++ b/src/plugins/bearer/icd/wlan-utils.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef WLAN_UTILS_H +#define WLAN_UTILS_H + +/** Originally taken from: libicd-network-wlan-dev.h*/ + +#include <glib.h> +#include <dbus/dbus.h> +#include <wlancond.h> +#include <icd/network_api_defines.h> + +/* capability bits inside network attributes var */ +#define NWATTR_WPS_MASK 0x0000F000 +#define NWATTR_ALGORITHM_MASK 0x00000F00 +#define NWATTR_WPA2_MASK 0x00000080 +#define NWATTR_METHOD_MASK 0x00000078 +#define NWATTR_MODE_MASK 0x00000007 + +#define CAP_LOCALMASK 0x0FFFE008 + +/* how much to shift between capability and network attributes var */ +#define CAP_SHIFT_WPS 3 +#define CAP_SHIFT_ALGORITHM 20 +#define CAP_SHIFT_WPA2 1 +#define CAP_SHIFT_METHOD 1 +#define CAP_SHIFT_MODE 0 +#define CAP_SHIFT_ALWAYS_ONLINE 26 + +/* ------------------------------------------------------------------------- */ +/* From combined to capability */ +static inline dbus_uint32_t nwattr2cap(guint nwattrs, dbus_uint32_t *cap) +{ + guint oldval = *cap; + + *cap &= CAP_LOCALMASK; /* clear old capabilities */ + *cap |= + ((nwattrs & ICD_NW_ATTR_ALWAYS_ONLINE) >> CAP_SHIFT_ALWAYS_ONLINE) | + ((nwattrs & NWATTR_WPS_MASK) >> CAP_SHIFT_WPS) | + ((nwattrs & NWATTR_ALGORITHM_MASK) << CAP_SHIFT_ALGORITHM) | + ((nwattrs & NWATTR_WPA2_MASK) << CAP_SHIFT_WPA2) | + ((nwattrs & NWATTR_METHOD_MASK) << CAP_SHIFT_METHOD) | + (nwattrs & NWATTR_MODE_MASK); + + return oldval; +} + + +/* ------------------------------------------------------------------------- */ +/* From capability to combined */ +static inline guint cap2nwattr(dbus_uint32_t cap, guint *nwattrs) +{ + guint oldval = *nwattrs; + + *nwattrs &= ~ICD_NW_ATTR_LOCALMASK; /* clear old capabilities */ + *nwattrs |= +#ifdef WLANCOND_WPS_MASK + ((cap & WLANCOND_WPS_MASK) << CAP_SHIFT_WPS) | +#endif + ((cap & (WLANCOND_ENCRYPT_ALG_MASK | + WLANCOND_ENCRYPT_GROUP_ALG_MASK)) >> CAP_SHIFT_ALGORITHM)| + ((cap & WLANCOND_ENCRYPT_WPA2_MASK) >> CAP_SHIFT_WPA2) | + ((cap & WLANCOND_ENCRYPT_METHOD_MASK) >> CAP_SHIFT_METHOD) | + (cap & WLANCOND_MODE_MASK); + + return oldval; +} + + +#endif diff --git a/src/plugins/bearer/nativewifi/main.cpp b/src/plugins/bearer/nativewifi/main.cpp new file mode 100644 index 0000000..98789aa --- /dev/null +++ b/src/plugins/bearer/nativewifi/main.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnativewifiengine.h" +#include "platformdefs.h" + +#include <QtCore/qmutex.h> +#include <QtCore/private/qmutexpool_p.h> +#include <QtCore/qlibrary.h> + +#include <QtNetwork/private/qbearerplugin_p.h> + +#include <QtCore/qdebug.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +static void resolveLibrary() +{ + static volatile bool triedResolve = false; + + if (!triedResolve) { +#ifndef QT_NO_THREAD + QMutexLocker locker(QMutexPool::globalInstanceGet(&local_WlanOpenHandle)); +#endif + + if (!triedResolve) { + local_WlanOpenHandle = (WlanOpenHandleProto) + QLibrary::resolve(QLatin1String("wlanapi.dll"), "WlanOpenHandle"); + local_WlanRegisterNotification = (WlanRegisterNotificationProto) + QLibrary::resolve(QLatin1String("wlanapi.dll"), "WlanRegisterNotification"); + local_WlanEnumInterfaces = (WlanEnumInterfacesProto) + QLibrary::resolve(QLatin1String("wlanapi.dll"), "WlanEnumInterfaces"); + local_WlanGetAvailableNetworkList = (WlanGetAvailableNetworkListProto) + QLibrary::resolve(QLatin1String("wlanapi.dll"), "WlanGetAvailableNetworkList"); + local_WlanQueryInterface = (WlanQueryInterfaceProto) + QLibrary::resolve(QLatin1String("wlanapi.dll"), "WlanQueryInterface"); + local_WlanConnect = (WlanConnectProto) + QLibrary::resolve(QLatin1String("wlanapi.dll"), "WlanConnect"); + local_WlanDisconnect = (WlanDisconnectProto) + QLibrary::resolve(QLatin1String("wlanapi.dll"), "WlanDisconnect"); + local_WlanScan = (WlanScanProto) + QLibrary::resolve(QLatin1String("wlanapi.dll"), "WlanScan"); + local_WlanFreeMemory = (WlanFreeMemoryProto) + QLibrary::resolve(QLatin1String("wlanapi.dll"), "WlanFreeMemory"); + local_WlanCloseHandle = (WlanCloseHandleProto) + QLibrary::resolve(QLatin1String("wlanapi.dll"), "WlanCloseHandle"); + + triedResolve = true; + } + } +} + +class QNativeWifiEnginePlugin : public QBearerEnginePlugin +{ +public: + QNativeWifiEnginePlugin(); + ~QNativeWifiEnginePlugin(); + + QStringList keys() const; + QBearerEngine *create(const QString &key) const; +}; + +QNativeWifiEnginePlugin::QNativeWifiEnginePlugin() +{ +} + +QNativeWifiEnginePlugin::~QNativeWifiEnginePlugin() +{ +} + +QStringList QNativeWifiEnginePlugin::keys() const +{ + return QStringList() << QLatin1String("nativewifi"); +} + +QBearerEngine *QNativeWifiEnginePlugin::create(const QString &key) const +{ + if (key != QLatin1String("nativewifi")) + return 0; + + resolveLibrary(); + + // native wifi dll not available + if (!local_WlanOpenHandle) + return 0; + + QNativeWifiEngine *engine = new QNativeWifiEngine; + + // could not initialise subsystem + if (engine && !engine->available()) { + delete engine; + return 0; + } + + return engine; +} + +Q_EXPORT_STATIC_PLUGIN(QNativeWifiEnginePlugin) +Q_EXPORT_PLUGIN2(qnativewifibearer, QNativeWifiEnginePlugin) + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/nativewifi/nativewifi.pro b/src/plugins/bearer/nativewifi/nativewifi.pro new file mode 100644 index 0000000..36dd36d --- /dev/null +++ b/src/plugins/bearer/nativewifi/nativewifi.pro @@ -0,0 +1,17 @@ +TARGET = qnativewifibearer +include(../../qpluginbase.pri) + +QT = core network + +HEADERS += qnativewifiengine.h \ + platformdefs.h \ + ../qnetworksession_impl.h \ + ../qbearerengine_impl.h + +SOURCES += main.cpp \ + qnativewifiengine.cpp \ + ../qnetworksession_impl.cpp + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/bearer +target.path += $$[QT_INSTALL_PLUGINS]/bearer +INSTALLS += target diff --git a/src/plugins/bearer/nativewifi/platformdefs.h b/src/plugins/bearer/nativewifi/platformdefs.h new file mode 100644 index 0000000..d67525a --- /dev/null +++ b/src/plugins/bearer/nativewifi/platformdefs.h @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PLATFORMDEFS_H +#define PLATFORMDEFS_H + +#include <wtypes.h> +#undef interface + +#define WLAN_MAX_NAME_LENGTH 256 +#define WLAN_MAX_PHY_TYPE_NUMBER 8 +#define WLAN_NOTIFICATION_SOURCE_ALL 0x0000ffff +#define WLAN_AVAILABLE_NETWORK_CONNECTED 1 +#define WLAN_AVAILABLE_NETWORK_HAS_PROFILE 2 +#define DOT11_SSID_MAX_LENGTH 32 + +QT_BEGIN_NAMESPACE + +struct WLAN_NOTIFICATION_DATA { + DWORD NotificationSource; + DWORD NotificationCode; + GUID InterfaceGuid; + DWORD dwDataSize; + PVOID pData; +}; + +enum WLAN_INTERFACE_STATE { + wlan_interface_state_not_ready = 0, + wlan_interface_state_connected, + wlan_interface_state_ad_hoc_network_formed, + wlan_interface_state_disconnecting, + wlan_interface_state_disconnected, + wlan_interface_state_associating, + wlan_interface_state_discovering, + wlan_interface_state_authenticating +}; + +struct WLAN_INTERFACE_INFO { + GUID InterfaceGuid; + WCHAR strInterfaceDescription[WLAN_MAX_NAME_LENGTH]; + WLAN_INTERFACE_STATE isState; +}; + +struct WLAN_INTERFACE_INFO_LIST { + DWORD dwNumberOfItems; + DWORD dwIndex; + WLAN_INTERFACE_INFO InterfaceInfo[1]; +}; + +struct DOT11_SSID { + ULONG uSSIDLength; + UCHAR ucSSID[DOT11_SSID_MAX_LENGTH]; +}; + +struct NDIS_OBJECT_HEADER { + UCHAR Type; + UCHAR Revision; + USHORT Size; +}; + +typedef UCHAR DOT11_MAC_ADDRESS[6]; +struct DOT11_BSSID_LIST { + NDIS_OBJECT_HEADER Header; + ULONG uNumberOfEntries; + ULONG uTotalNumOfEntries; + DOT11_MAC_ADDRESS BSSIDs[1]; +}; + +enum DOT11_BSS_TYPE { + dot11_BSS_type_infrastructure = 1, + dot11_BSS_type_independent = 2, + dot11_BSS_type_any = 3 +}; + +enum DOT11_PHY_TYPE { + dot11_phy_type_unknown = 0, + dot11_phy_type_any = dot11_phy_type_unknown, + dot11_phy_type_fhss = 1, + dot11_phy_type_dsss = 2, + dot11_phy_type_irbaseband = 3, + dot11_phy_type_ofdm = 4, + dot11_phy_type_hrdsss = 5, + dot11_phy_type_erp = 6, + dot11_phy_type_ht = 7, + dot11_phy_type_IHV_start = 0x80000000, + dot11_phy_type_IHV_end = 0xffffffff +}; + +enum DOT11_AUTH_ALGORITHM { + DOT11_AUTH_ALGO_80211_OPEN = 1, + DOT11_AUTH_ALGO_80211_SHARED_KEY = 2, + DOT11_AUTH_ALGO_WPA = 3, + DOT11_AUTH_ALGO_WPA_PSK = 4, + DOT11_AUTH_ALGO_WPA_NONE = 5, + DOT11_AUTH_ALGO_RSNA = 6, + DOT11_AUTH_ALGO_RSNA_PSK = 7, + DOT11_AUTH_ALGO_IHV_START = 0x80000000, + DOT11_AUTH_ALGO_IHV_END = 0xffffffff +}; + +enum DOT11_CIPHER_ALGORITHM { + DOT11_CIPHER_ALGO_NONE = 0x00, + DOT11_CIPHER_ALGO_WEP40 = 0x01, + DOT11_CIPHER_ALGO_TKIP = 0x02, + DOT11_CIPHER_ALGO_CCMP = 0x04, + DOT11_CIPHER_ALGO_WEP104 = 0x05, + DOT11_CIPHER_ALGO_WPA_USE_GROUP = 0x100, + DOT11_CIPHER_ALGO_RSN_USE_GROUP = 0x100, + DOT11_CIPHER_ALGO_WEP = 0x101, + DOT11_CIPHER_ALGO_IHV_START = 0x80000000, + DOT11_CIPHER_ALGO_IHV_END = 0xffffffff +}; + +struct WLAN_AVAILABLE_NETWORK { + WCHAR strProfileName[WLAN_MAX_NAME_LENGTH]; + DOT11_SSID dot11Ssid; + DOT11_BSS_TYPE dot11BssType; + ULONG uNumberOfBssids; + BOOL bNetworkConnectable; + DWORD wlanNotConnectableReason; + ULONG uNumberOfPhyTypes; + DOT11_PHY_TYPE dot11PhyTypes[WLAN_MAX_PHY_TYPE_NUMBER]; + BOOL bMorePhyTypes; + ULONG wlanSignalQuality; + BOOL bSecurityEnabled; + DOT11_AUTH_ALGORITHM dot11DefaultAuthAlgorithm; + DOT11_CIPHER_ALGORITHM dot11DefaultCipherAlgorithm; + DWORD dwFlags; + DWORD dwReserved; +}; + +struct WLAN_AVAILABLE_NETWORK_LIST { + DWORD dwNumberOfItems; + DWORD dwIndex; + WLAN_AVAILABLE_NETWORK Network[1]; +}; + +enum WLAN_INTF_OPCODE { + wlan_intf_opcode_autoconf_start = 0x000000000, + wlan_intf_opcode_autoconf_enabled, + wlan_intf_opcode_background_scan_enabled, + wlan_intf_opcode_media_streaming_mode, + wlan_intf_opcode_radio_state, + wlan_intf_opcode_bss_type, + wlan_intf_opcode_interface_state, + wlan_intf_opcode_current_connection, + wlan_intf_opcode_channel_number, + wlan_intf_opcode_supported_infrastructure_auth_cipher_pairs, + wlan_intf_opcode_supported_adhoc_auth_cipher_pairs, + wlan_intf_opcode_supported_country_or_region_string_list, + wlan_intf_opcode_current_operation_mode, + wlan_intf_opcode_supported_safe_mode, + wlan_intf_opcode_certified_safe_mode, + wlan_intf_opcode_autoconf_end = 0x0fffffff, + wlan_intf_opcode_msm_start = 0x10000100, + wlan_intf_opcode_statistics, + wlan_intf_opcode_rssi, + wlan_intf_opcode_msm_end = 0x1fffffff, + wlan_intf_opcode_security_start = 0x20010000, + wlan_intf_opcode_security_end = 0x2fffffff, + wlan_intf_opcode_ihv_start = 0x30000000, + wlan_intf_opcode_ihv_end = 0x3fffffff +}; + +enum WLAN_OPCODE_VALUE_TYPE { + wlan_opcode_value_type_query_only = 0, + wlan_opcode_value_type_set_by_group_policy, + wlan_opcode_value_type_set_by_user, + wlan_opcode_value_type_invalid +}; + +enum WLAN_CONNECTION_MODE { + wlan_connection_mode_profile = 0, + wlan_connection_mode_temporary_profile, + wlan_connection_mode_discovery_secure, + wlan_connection_mode_discovery_unsecure, + wlan_connection_mode_auto, + wlan_connection_mode_invalid +}; + +struct WLAN_CONNECTION_PARAMETERS { + WLAN_CONNECTION_MODE wlanConnectionMode; + LPCWSTR strProfile; + DOT11_SSID *pDot11Ssid; + DOT11_BSSID_LIST *pDesiredBssidList; + DOT11_BSS_TYPE dot11BssType; + DWORD dwFlags; +}; + +struct WLAN_RAW_DATA { + DWORD dwDataSize; + BYTE DataBlob[1]; +}; + +enum WLAN_NOTIFICATION_ACM { + wlan_notification_acm_start = 0, + wlan_notification_acm_autoconf_enabled, + wlan_notification_acm_autoconf_disabled, + wlan_notification_acm_background_scan_enabled, + wlan_notification_acm_background_scan_disabled, + wlan_notification_acm_bss_type_change, + wlan_notification_acm_power_setting_change, + wlan_notification_acm_scan_complete, + wlan_notification_acm_scan_fail, + wlan_notification_acm_connection_start, + wlan_notification_acm_connection_complete, + wlan_notification_acm_connection_attempt_fail, + wlan_notification_acm_filter_list_change, + wlan_notification_acm_interface_arrival, + wlan_notification_acm_interface_removal, + wlan_notification_acm_profile_change, + wlan_notification_acm_profile_name_change, + wlan_notification_acm_profiles_exhausted, + wlan_notification_acm_network_not_available, + wlan_notification_acm_network_available, + wlan_notification_acm_disconnecting, + wlan_notification_acm_disconnected, + wlan_notification_acm_adhoc_network_state_change, + wlan_notification_acm_end +}; + +struct WLAN_ASSOCIATION_ATTRIBUTES { + DOT11_SSID dot11Ssid; + DOT11_BSS_TYPE dot11BssType; + DOT11_MAC_ADDRESS dot11Bssid; + DOT11_PHY_TYPE dot11PhyType; + ULONG uDot11PhyIndex; + ULONG wlanSignalQuality; + ULONG ulRxRate; + ULONG ulTxRate; +}; + +struct WLAN_SECURITY_ATTRIBUTES { + BOOL bSecurityEnabled; + BOOL bOneXEnabled; + DOT11_AUTH_ALGORITHM dot11AuthAlgorithm; + DOT11_CIPHER_ALGORITHM dot11CipherAlgorithm; +}; + +struct WLAN_CONNECTION_ATTRIBUTES { + WLAN_INTERFACE_STATE isState; + WLAN_CONNECTION_MODE wlanConnectionMode; + WCHAR strProfileName[WLAN_MAX_NAME_LENGTH]; + WLAN_ASSOCIATION_ATTRIBUTES wlanAssociationAttributes; + WLAN_SECURITY_ATTRIBUTES wlanSecurityAttributes; +}; + +typedef void (WINAPI *WLAN_NOTIFICATION_CALLBACK)(WLAN_NOTIFICATION_DATA *, PVOID); + +typedef DWORD (WINAPI *WlanOpenHandleProto) + (DWORD dwClientVersion, PVOID pReserved, PDWORD pdwNegotiatedVersion, PHANDLE phClientHandle); +typedef DWORD (WINAPI *WlanRegisterNotificationProto) + (HANDLE hClientHandle, DWORD dwNotifSource, BOOL bIgnoreDuplicate, + WLAN_NOTIFICATION_CALLBACK funcCallback, PVOID pCallbackContext, + PVOID pReserved, PDWORD pdwPrevNotifSource); +typedef DWORD (WINAPI *WlanEnumInterfacesProto) + (HANDLE hClientHandle, PVOID pReserved, WLAN_INTERFACE_INFO_LIST **ppInterfaceList); +typedef DWORD (WINAPI *WlanGetAvailableNetworkListProto) + (HANDLE hClientHandle, const GUID* pInterfaceGuid, DWORD dwFlags, PVOID pReserved, + WLAN_AVAILABLE_NETWORK_LIST **ppAvailableNetworkList); +typedef DWORD (WINAPI *WlanQueryInterfaceProto) + (HANDLE hClientHandle, const GUID *pInterfaceGuid, WLAN_INTF_OPCODE OpCode, PVOID pReserved, + PDWORD pdwDataSize, PVOID *ppData, WLAN_OPCODE_VALUE_TYPE *pWlanOpcodeValueType); +typedef DWORD (WINAPI *WlanConnectProto) + (HANDLE hClientHandle, const GUID *pInterfaceGuid, + const WLAN_CONNECTION_PARAMETERS *pConnectionParameters, PVOID pReserved); +typedef DWORD (WINAPI *WlanDisconnectProto) + (HANDLE hClientHandle, const GUID *pInterfaceGuid, PVOID pReserved); +typedef DWORD (WINAPI *WlanScanProto) + (HANDLE hClientHandle, const GUID *pInterfaceGuid, const DOT11_SSID *pDot11Ssid, + const WLAN_RAW_DATA *pIeData, PVOID pReserved); +typedef VOID (WINAPI *WlanFreeMemoryProto)(PVOID pMemory); +typedef DWORD (WINAPI *WlanCloseHandleProto)(HANDLE hClientHandle, PVOID pReserved); + +extern WlanOpenHandleProto local_WlanOpenHandle; +extern WlanRegisterNotificationProto local_WlanRegisterNotification; +extern WlanEnumInterfacesProto local_WlanEnumInterfaces; +extern WlanGetAvailableNetworkListProto local_WlanGetAvailableNetworkList; +extern WlanQueryInterfaceProto local_WlanQueryInterface; +extern WlanConnectProto local_WlanConnect; +extern WlanDisconnectProto local_WlanDisconnect; +extern WlanScanProto local_WlanScan; +extern WlanFreeMemoryProto local_WlanFreeMemory; +extern WlanCloseHandleProto local_WlanCloseHandle; + +QT_END_NAMESPACE + +#endif // PLATFORMDEFS_H diff --git a/src/plugins/bearer/nativewifi/qnativewifiengine.cpp b/src/plugins/bearer/nativewifi/qnativewifiengine.cpp new file mode 100644 index 0000000..ba8297e --- /dev/null +++ b/src/plugins/bearer/nativewifi/qnativewifiengine.cpp @@ -0,0 +1,611 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnativewifiengine.h" +#include "platformdefs.h" +#include "../qnetworksession_impl.h" + +#include <QtNetwork/private/qnetworkconfiguration_p.h> + +#include <QtCore/qstringlist.h> +#include <QtCore/qcoreapplication.h> + +#include <QtCore/qdebug.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +WlanOpenHandleProto local_WlanOpenHandle = 0; +WlanRegisterNotificationProto local_WlanRegisterNotification = 0; +WlanEnumInterfacesProto local_WlanEnumInterfaces = 0; +WlanGetAvailableNetworkListProto local_WlanGetAvailableNetworkList = 0; +WlanQueryInterfaceProto local_WlanQueryInterface = 0; +WlanConnectProto local_WlanConnect = 0; +WlanDisconnectProto local_WlanDisconnect = 0; +WlanScanProto local_WlanScan = 0; +WlanFreeMemoryProto local_WlanFreeMemory = 0; +WlanCloseHandleProto local_WlanCloseHandle = 0; + +void qNotificationCallback(WLAN_NOTIFICATION_DATA *data, QNativeWifiEngine *d) +{ + Q_UNUSED(d); + + switch (data->NotificationCode) { + case wlan_notification_acm_connection_complete: + case wlan_notification_acm_disconnected: + QMetaObject::invokeMethod(d, "scanComplete", Qt::QueuedConnection); + break; + default: + ; + } +} + +QNativeWifiEngine::QNativeWifiEngine(QObject *parent) +: QBearerEngineImpl(parent), handle(INVALID_HANDLE_VALUE) +{ + connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(closeHandle())); +} + +QNativeWifiEngine::~QNativeWifiEngine() +{ + closeHandle(); +} + +void QNativeWifiEngine::scanComplete() +{ + QMutexLocker locker(&mutex); + + if (!available()) { + locker.unlock(); + emit updateCompleted(); + return; + } + + // enumerate interfaces + WLAN_INTERFACE_INFO_LIST *interfaceList; + DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList); + if (result != ERROR_SUCCESS) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result); +#endif + + locker.unlock(); + emit updateCompleted(); + + return; + } + + QStringList previous = accessPointConfigurations.keys(); + + for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) { + const WLAN_INTERFACE_INFO &interface = interfaceList->InterfaceInfo[i]; + + WLAN_AVAILABLE_NETWORK_LIST *networkList; + result = local_WlanGetAvailableNetworkList(handle, &interface.InterfaceGuid, + 3, 0, &networkList); + if (result != ERROR_SUCCESS) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: WlanGetAvailableNetworkList failed with error %ld\n", + __FUNCTION__, result); +#endif + continue; + } + + QStringList seenNetworks; + + for (unsigned int j = 0; j < networkList->dwNumberOfItems; ++j) { + WLAN_AVAILABLE_NETWORK &network = networkList->Network[j]; + + QString networkName; + + if (network.strProfileName[0] != 0) { + networkName = QString::fromWCharArray(network.strProfileName); + } else { + networkName = QByteArray(reinterpret_cast<char *>(network.dot11Ssid.ucSSID), + network.dot11Ssid.uSSIDLength); + } + + const QString id = QString::number(qHash(QLatin1String("WLAN:") + networkName)); + + previous.removeAll(id); + + QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; + + if (!(network.dwFlags & WLAN_AVAILABLE_NETWORK_HAS_PROFILE)) + state = QNetworkConfiguration::Undefined; + + if (network.strProfileName[0] != 0) { + if (network.bNetworkConnectable) { + if (network.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) + state = QNetworkConfiguration::Active; + else + state = QNetworkConfiguration::Discovered; + } else { + state = QNetworkConfiguration::Defined; + } + } + + if (seenNetworks.contains(networkName)) + continue; + else + seenNetworks.append(networkName); + + if (accessPointConfigurations.contains(id)) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + bool changed = false; + + ptr->mutex.lock(); + + if (!ptr->isValid) { + ptr->isValid = true; + changed = true; + } + + if (ptr->name != networkName) { + ptr->name = networkName; + changed = true; + } + + if (ptr->state != state) { + ptr->state = state; + changed = true; + } + + ptr->mutex.unlock(); + + if (changed) { + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } + } else { + QNetworkConfigurationPrivatePointer ptr(new QNetworkConfigurationPrivate); + + ptr->name = networkName; + ptr->isValid = true; + ptr->id = id; + ptr->state = state; + ptr->type = QNetworkConfiguration::InternetAccessPoint; + ptr->bearerType = QNetworkConfiguration::BearerWLAN; + + accessPointConfigurations.insert(id, ptr); + + locker.unlock(); + emit configurationAdded(ptr); + locker.relock(); + } + } + + local_WlanFreeMemory(networkList); + } + + local_WlanFreeMemory(interfaceList); + + while (!previous.isEmpty()) { + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.take(previous.takeFirst()); + + locker.unlock(); + emit configurationRemoved(ptr); + locker.relock(); + } + + locker.unlock(); + emit updateCompleted(); +} + +QString QNativeWifiEngine::getInterfaceFromId(const QString &id) +{ + QMutexLocker locker(&mutex); + + if (!available()) + return QString(); + + // enumerate interfaces + WLAN_INTERFACE_INFO_LIST *interfaceList; + DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList); + if (result != ERROR_SUCCESS) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result); +#endif + return QString(); + } + + for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) { + const WLAN_INTERFACE_INFO &interface = interfaceList->InterfaceInfo[i]; + + DWORD dataSize; + WLAN_CONNECTION_ATTRIBUTES *connectionAttributes; + result = local_WlanQueryInterface(handle, &interface.InterfaceGuid, + wlan_intf_opcode_current_connection, 0, &dataSize, + reinterpret_cast<PVOID *>(&connectionAttributes), 0); + if (result != ERROR_SUCCESS) { +#ifdef BEARER_MANAGEMENT_DEBUG + if (result != ERROR_INVALID_STATE) + qDebug("%s: WlanQueryInterface failed with error %ld\n", __FUNCTION__, result); +#endif + + continue; + } + + if (qHash(QLatin1String("WLAN:") + + QString::fromWCharArray(connectionAttributes->strProfileName)) == id.toUInt()) { + QString guid("{%1-%2-%3-%4%5-%6%7%8%9%10%11}"); + + guid = guid.arg(interface.InterfaceGuid.Data1, 8, 16, QChar('0')); + guid = guid.arg(interface.InterfaceGuid.Data2, 4, 16, QChar('0')); + guid = guid.arg(interface.InterfaceGuid.Data3, 4, 16, QChar('0')); + for (int i = 0; i < 8; ++i) + guid = guid.arg(interface.InterfaceGuid.Data4[i], 2, 16, QChar('0')); + + local_WlanFreeMemory(connectionAttributes); + local_WlanFreeMemory(interfaceList); + + return guid.toUpper(); + } + + local_WlanFreeMemory(connectionAttributes); + } + + local_WlanFreeMemory(interfaceList); + + return QString(); +} + +bool QNativeWifiEngine::hasIdentifier(const QString &id) +{ + QMutexLocker locker(&mutex); + + if (!available()) + return false; + + // enumerate interfaces + WLAN_INTERFACE_INFO_LIST *interfaceList; + DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList); + if (result != ERROR_SUCCESS) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result); +#endif + return false; + } + + for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) { + const WLAN_INTERFACE_INFO &interface = interfaceList->InterfaceInfo[i]; + + WLAN_AVAILABLE_NETWORK_LIST *networkList; + result = local_WlanGetAvailableNetworkList(handle, &interface.InterfaceGuid, + 3, 0, &networkList); + if (result != ERROR_SUCCESS) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: WlanGetAvailableNetworkList failed with error %ld\n", + __FUNCTION__, result); +#endif + continue; + } + + for (unsigned int j = 0; j < networkList->dwNumberOfItems; ++j) { + WLAN_AVAILABLE_NETWORK &network = networkList->Network[j]; + + QString networkName; + + if (network.strProfileName[0] != 0) { + networkName = QString::fromWCharArray(network.strProfileName); + } else { + networkName = QByteArray(reinterpret_cast<char *>(network.dot11Ssid.ucSSID), + network.dot11Ssid.uSSIDLength); + } + + if (qHash(QLatin1String("WLAN:") + networkName) == id.toUInt()) { + local_WlanFreeMemory(networkList); + local_WlanFreeMemory(interfaceList); + return true; + } + } + + local_WlanFreeMemory(networkList); + } + + local_WlanFreeMemory(interfaceList); + + return false; +} + +void QNativeWifiEngine::connectToId(const QString &id) +{ + QMutexLocker locker(&mutex); + + if (!available()) { + locker.unlock(); + emit connectionError(id, InterfaceLookupError); + return; + } + + WLAN_INTERFACE_INFO_LIST *interfaceList; + DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList); + if (result != ERROR_SUCCESS) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result); +#endif + locker.unlock(); + emit connectionError(id, InterfaceLookupError); + return; + } + + QString profile; + + for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) { + const WLAN_INTERFACE_INFO &interface = interfaceList->InterfaceInfo[i]; + + WLAN_AVAILABLE_NETWORK_LIST *networkList; + result = local_WlanGetAvailableNetworkList(handle, &interface.InterfaceGuid, + 3, 0, &networkList); + if (result != ERROR_SUCCESS) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: WlanGetAvailableNetworkList failed with error %ld\n", + __FUNCTION__, result); +#endif + continue; + } + + for (unsigned int j = 0; j < networkList->dwNumberOfItems; ++j) { + WLAN_AVAILABLE_NETWORK &network = networkList->Network[j]; + + profile = QString::fromWCharArray(network.strProfileName); + + if (qHash(QLatin1String("WLAN:") + profile) == id.toUInt()) + break; + else + profile.clear(); + } + + local_WlanFreeMemory(networkList); + + if (!profile.isEmpty()) { + WLAN_CONNECTION_PARAMETERS parameters; + parameters.wlanConnectionMode = wlan_connection_mode_profile; + parameters.strProfile = reinterpret_cast<LPCWSTR>(profile.utf16()); + parameters.pDot11Ssid = 0; + parameters.pDesiredBssidList = 0; + parameters.dot11BssType = dot11_BSS_type_any; + parameters.dwFlags = 0; + + DWORD result = local_WlanConnect(handle, &interface.InterfaceGuid, ¶meters, 0); + if (result != ERROR_SUCCESS) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: WlanConnect failed with error %ld\n", __FUNCTION__, result); +#endif + locker.unlock(); + emit connectionError(id, ConnectError); + locker.relock(); + break; + } + + break; + } + } + + local_WlanFreeMemory(interfaceList); + + if (profile.isEmpty()) { + locker.unlock(); + emit connectionError(id, InterfaceLookupError); + } +} + +void QNativeWifiEngine::disconnectFromId(const QString &id) +{ + QMutexLocker locker(&mutex); + + if (!available()) { + locker.unlock(); + emit connectionError(id, InterfaceLookupError); + return; + } + + QString interface = getInterfaceFromId(id); + + if (interface.isEmpty()) { + locker.unlock(); + emit connectionError(id, InterfaceLookupError); + return; + } + + QStringList split = interface.mid(1, interface.length() - 2).split('-'); + + GUID guid; + guid.Data1 = split.at(0).toUInt(0, 16); + guid.Data2 = split.at(1).toUShort(0, 16); + guid.Data3 = split.at(2).toUShort(0, 16); + guid.Data4[0] = split.at(3).left(2).toUShort(0, 16); + guid.Data4[1] = split.at(3).right(2).toUShort(0, 16); + for (int i = 0; i < 6; ++i) + guid.Data4[i + 2] = split.at(4).mid(i*2, 2).toUShort(0, 16); + + DWORD result = local_WlanDisconnect(handle, &guid, 0); + if (result != ERROR_SUCCESS) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: WlanDisconnect failed with error %ld\n", __FUNCTION__, result); +#endif + locker.unlock(); + emit connectionError(id, DisconnectionError); + return; + } +} + +void QNativeWifiEngine::initialize() +{ + scanComplete(); +} + +void QNativeWifiEngine::requestUpdate() +{ + QMutexLocker locker(&mutex); + + if (!available()) { + locker.unlock(); + emit updateCompleted(); + return; + } + + // enumerate interfaces + WLAN_INTERFACE_INFO_LIST *interfaceList; + DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList); + if (result != ERROR_SUCCESS) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result); +#endif + + locker.unlock(); + emit updateCompleted(); + + return; + } + + bool requested = false; + for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) { + result = local_WlanScan(handle, &interfaceList->InterfaceInfo[i].InterfaceGuid, 0, 0, 0); + if (result != ERROR_SUCCESS) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: WlanScan failed with error %ld\n", __FUNCTION__, result); +#endif + } else { + requested = true; + } + } + + local_WlanFreeMemory(interfaceList); + + if (!requested) { + locker.unlock(); + emit updateCompleted(); + } +} + +QNetworkSession::State QNativeWifiEngine::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 QNativeWifiEngine::capabilities() const +{ + return QNetworkConfigurationManager::ForcedRoaming | + QNetworkConfigurationManager::CanStartAndStopInterfaces; +} + +QNetworkSessionPrivate *QNativeWifiEngine::createSessionBackend() +{ + return new QNetworkSessionPrivateImpl; +} + +QNetworkConfigurationPrivatePointer QNativeWifiEngine::defaultConfiguration() +{ + return QNetworkConfigurationPrivatePointer(); +} + +bool QNativeWifiEngine::available() +{ + if (handle != INVALID_HANDLE_VALUE) + return true; + + DWORD clientVersion; + + DWORD result = local_WlanOpenHandle(1, 0, &clientVersion, &handle); + if (result != ERROR_SUCCESS) { +#ifdef BEARER_MANAGEMENT_DEBUG + if (result != ERROR_SERVICE_NOT_ACTIVE) + qDebug("%s: WlanOpenHandle failed with error %ld\n", __FUNCTION__, result); +#endif + + return false; + } + + result = local_WlanRegisterNotification(handle, WLAN_NOTIFICATION_SOURCE_ALL, true, + WLAN_NOTIFICATION_CALLBACK(qNotificationCallback), + this, 0, 0); +#ifdef BEARER_MANAGEMENT_DEBUG + if (result != ERROR_SUCCESS) + qDebug("%s: WlanRegisterNotification failed with error %ld\n", __FUNCTION__, result); +#endif + + return handle != INVALID_HANDLE_VALUE; +} + +void QNativeWifiEngine::closeHandle() +{ + if (handle != INVALID_HANDLE_VALUE) { + local_WlanCloseHandle(handle, 0); + handle = INVALID_HANDLE_VALUE; + } +} + +bool QNativeWifiEngine::requiresPolling() const +{ + // On Windows XP SP2 and SP3 only connection and disconnection notifications are available. + // We need to poll for changes in available wireless networks. + return true; +} + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/nativewifi/qnativewifiengine.h b/src/plugins/bearer/nativewifi/qnativewifiengine.h new file mode 100644 index 0000000..dccf2e2 --- /dev/null +++ b/src/plugins/bearer/nativewifi/qnativewifiengine.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNATIVEWIFIENGINE_P_H +#define QNATIVEWIFIENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "../qbearerengine_impl.h" + +#include <QtCore/qtimer.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +class QNetworkConfigurationPrivate; +struct WLAN_NOTIFICATION_DATA; + +class QNativeWifiEngine : public QBearerEngineImpl +{ + Q_OBJECT + +public: + QNativeWifiEngine(QObject *parent = 0); + ~QNativeWifiEngine(); + + QString getInterfaceFromId(const QString &id); + bool hasIdentifier(const QString &id); + + void connectToId(const QString &id); + void disconnectFromId(const QString &id); + + Q_INVOKABLE void initialize(); + Q_INVOKABLE void requestUpdate(); + + QNetworkSession::State sessionStateForId(const QString &id); + + QNetworkConfigurationManager::Capabilities capabilities() const; + + QNetworkSessionPrivate *createSessionBackend(); + + QNetworkConfigurationPrivatePointer defaultConfiguration(); + + bool available(); + + bool requiresPolling() const; + +private Q_SLOTS: + void scanComplete(); + void closeHandle(); + +private: + Qt::HANDLE handle; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT + +#endif diff --git a/src/plugins/bearer/networkmanager/main.cpp b/src/plugins/bearer/networkmanager/main.cpp new file mode 100644 index 0000000..9ab2c39 --- /dev/null +++ b/src/plugins/bearer/networkmanager/main.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnetworkmanagerengine.h" + +#include <QtNetwork/private/qbearerplugin_p.h> + +#include <QtCore/qdebug.h> + +#ifndef QT_NO_BEARERMANAGEMENT +#ifndef QT_NO_DBUS + +QT_BEGIN_NAMESPACE + +class QNetworkManagerEnginePlugin : public QBearerEnginePlugin +{ +public: + QNetworkManagerEnginePlugin(); + ~QNetworkManagerEnginePlugin(); + + QStringList keys() const; + QBearerEngine *create(const QString &key) const; +}; + +QNetworkManagerEnginePlugin::QNetworkManagerEnginePlugin() +{ +} + +QNetworkManagerEnginePlugin::~QNetworkManagerEnginePlugin() +{ +} + +QStringList QNetworkManagerEnginePlugin::keys() const +{ + return QStringList() << QLatin1String("networkmanager"); +} + +QBearerEngine *QNetworkManagerEnginePlugin::create(const QString &key) const +{ + if (key == QLatin1String("networkmanager")) { + QNetworkManagerEngine *engine = new QNetworkManagerEngine; + if (engine->networkManagerAvailable()) + return engine; + else + delete engine; + } + + return 0; +} + +Q_EXPORT_STATIC_PLUGIN(QNetworkManagerEnginePlugin) +Q_EXPORT_PLUGIN2(qnmbearer, QNetworkManagerEnginePlugin) + +QT_END_NAMESPACE + +#endif // QT_NO_DBUS +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/networkmanager/networkmanager.pro b/src/plugins/bearer/networkmanager/networkmanager.pro new file mode 100644 index 0000000..e396263 --- /dev/null +++ b/src/plugins/bearer/networkmanager/networkmanager.pro @@ -0,0 +1,20 @@ +TARGET = qnmbearer +include(../../qpluginbase.pri) + +QT = core network dbus + +HEADERS += qnmdbushelper.h \ + qnetworkmanagerservice.h \ + qnetworkmanagerengine.h \ + ../qnetworksession_impl.h \ + ../qbearerengine_impl.h + +SOURCES += main.cpp \ + qnmdbushelper.cpp \ + qnetworkmanagerservice.cpp \ + qnetworkmanagerengine.cpp \ + ../qnetworksession_impl.cpp + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/bearer +target.path += $$[QT_INSTALL_PLUGINS]/bearer +INSTALLS += target diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp new file mode 100644 index 0000000..554f9b7 --- /dev/null +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -0,0 +1,904 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnetworkmanagerengine.h" +#include "qnetworkmanagerservice.h" +#include "../qnetworksession_impl.h" + +#include <QtNetwork/private/qnetworkconfiguration_p.h> + +#include <QtNetwork/qnetworksession.h> + +#include <QtCore/qdebug.h> + +#include <QtDBus> +#include <QDBusConnection> +#include <QDBusError> +#include <QDBusInterface> +#include <QDBusMessage> +#include <QDBusReply> + +#ifndef QT_NO_BEARERMANAGEMENT +#ifndef QT_NO_DBUS + +QT_BEGIN_NAMESPACE + +QNetworkManagerEngine::QNetworkManagerEngine(QObject *parent) +: QBearerEngineImpl(parent), + interface(new QNetworkManagerInterface(this)), + systemSettings(new QNetworkManagerSettings(NM_DBUS_SERVICE_SYSTEM_SETTINGS, this)), + userSettings(new QNetworkManagerSettings(NM_DBUS_SERVICE_USER_SETTINGS, this)) +{ + if (!interface->isValid()) + return; + + interface->setConnections(); + connect(interface, SIGNAL(deviceAdded(QDBusObjectPath)), + this, SLOT(deviceAdded(QDBusObjectPath))); + connect(interface, SIGNAL(deviceRemoved(QDBusObjectPath)), + this, SLOT(deviceRemoved(QDBusObjectPath))); +#if 0 + connect(interface, SIGNAL(stateChanged(const QString,quint32)), + this, SIGNAL(configurationsChanged())); +#endif + connect(interface, SIGNAL(activationFinished(QDBusPendingCallWatcher*)), + this, SLOT(activationFinished(QDBusPendingCallWatcher*))); + connect(interface, SIGNAL(propertiesChanged(QString,QMap<QString,QVariant>)), + this, SLOT(interfacePropertiesChanged(QString,QMap<QString,QVariant>))); + + qDBusRegisterMetaType<QNmSettingsMap>(); + + systemSettings->setConnections(); + connect(systemSettings, SIGNAL(newConnection(QDBusObjectPath)), + this, SLOT(newConnection(QDBusObjectPath))); + + userSettings->setConnections(); + connect(userSettings, SIGNAL(newConnection(QDBusObjectPath)), + this, SLOT(newConnection(QDBusObjectPath))); +} + +QNetworkManagerEngine::~QNetworkManagerEngine() +{ + qDeleteAll(connections); + qDeleteAll(accessPoints); + qDeleteAll(wirelessDevices); + qDeleteAll(activeConnections); +} + +void QNetworkManagerEngine::initialize() +{ + QMutexLocker locker(&mutex); + + // Get current list of access points. + foreach (const QDBusObjectPath &devicePath, interface->getDevices()) { + locker.unlock(); + deviceAdded(devicePath); + locker.relock(); + } + + // Get connections. + foreach (const QDBusObjectPath &settingsPath, systemSettings->listConnections()) { + locker.unlock(); + newConnection(settingsPath, systemSettings); + locker.relock(); + } + foreach (const QDBusObjectPath &settingsPath, userSettings->listConnections()) { + locker.unlock(); + newConnection(settingsPath, userSettings); + locker.relock(); + } + + // Get active connections. + foreach (const QDBusObjectPath &acPath, interface->activeConnections()) { + QNetworkManagerConnectionActive *activeConnection = + new QNetworkManagerConnectionActive(acPath.path()); + activeConnections.insert(acPath.path(), activeConnection); + + activeConnection->setConnections(); + connect(activeConnection, SIGNAL(propertiesChanged(QString,QMap<QString,QVariant>)), + this, SLOT(activeConnectionPropertiesChanged(QString,QMap<QString,QVariant>))); + } +} + +bool QNetworkManagerEngine::networkManagerAvailable() const +{ + QMutexLocker locker(&mutex); + + return interface->isValid(); +} + +QString QNetworkManagerEngine::getInterfaceFromId(const QString &id) +{ + QMutexLocker locker(&mutex); + + foreach (const QDBusObjectPath &acPath, interface->activeConnections()) { + QNetworkManagerConnectionActive activeConnection(acPath.path()); + + const QString identifier = QString::number(qHash(activeConnection.serviceName() + ' ' + + activeConnection.connection().path())); + + if (id == identifier) { + QList<QDBusObjectPath> devices = activeConnection.devices(); + + if (devices.isEmpty()) + continue; + + QNetworkManagerInterfaceDevice device(devices.at(0).path()); + return device.networkInterface(); + } + } + + return QString(); +} + +bool QNetworkManagerEngine::hasIdentifier(const QString &id) +{ + QMutexLocker locker(&mutex); + + if (connectionFromId(id)) + return true; + + for (int i = 0; i < accessPoints.count(); ++i) { + QNetworkManagerInterfaceAccessPoint *accessPoint = accessPoints.at(i); + + const QString identifier = + QString::number(qHash(accessPoint->connectionInterface()->path())); + + if (id == identifier) + return true; + } + + return false; +} + +void QNetworkManagerEngine::connectToId(const QString &id) +{ + QMutexLocker locker(&mutex); + + QNetworkManagerSettingsConnection *connection = connectionFromId(id); + + if (!connection) + return; + + QNmSettingsMap map = connection->getSettings(); + const QString connectionType = map.value("connection").value("type").toString(); + + QString dbusDevicePath; + foreach (const QDBusObjectPath &devicePath, interface->getDevices()) { + QNetworkManagerInterfaceDevice device(devicePath.path()); + if (device.deviceType() == DEVICE_TYPE_802_3_ETHERNET && + connectionType == QLatin1String("802-3-ethernet")) { + dbusDevicePath = devicePath.path(); + break; + } else if (device.deviceType() == DEVICE_TYPE_802_11_WIRELESS && + connectionType == QLatin1String("802-11-wireless")) { + dbusDevicePath = devicePath.path(); + break; + } + } + + const QString service = connection->connectionInterface()->service(); + const QString settingsPath = connection->connectionInterface()->path(); + + interface->activateConnection(service, QDBusObjectPath(settingsPath), + QDBusObjectPath(dbusDevicePath), QDBusObjectPath("/")); +} + +void QNetworkManagerEngine::disconnectFromId(const QString &id) +{ + QMutexLocker locker(&mutex); + + foreach (const QDBusObjectPath &acPath, interface->activeConnections()) { + QNetworkManagerConnectionActive activeConnection(acPath.path()); + + const QString identifier = QString::number(qHash(activeConnection.serviceName() + ' ' + + activeConnection.connection().path())); + + if (id == identifier && accessPointConfigurations.contains(id)) { + interface->deactivateConnection(acPath); + break; + } + } +} + +void QNetworkManagerEngine::requestUpdate() +{ + QMetaObject::invokeMethod(this, "updateCompleted", Qt::QueuedConnection); +} + +void QNetworkManagerEngine::interfacePropertiesChanged(const QString &path, + const QMap<QString, QVariant> &properties) +{ + QMutexLocker locker(&mutex); + + Q_UNUSED(path) + + QMapIterator<QString, QVariant> i(properties); + while (i.hasNext()) { + i.next(); + + if (i.key() == QLatin1String("ActiveConnections")) { + // Active connections changed, update configurations. + + QList<QDBusObjectPath> activeConnections = + qdbus_cast<QList<QDBusObjectPath> >(i.value().value<QDBusArgument>()); + + QStringList identifiers = accessPointConfigurations.keys(); + foreach (const QString &id, identifiers) + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + QStringList priorActiveConnections = this->activeConnections.keys(); + + foreach (const QDBusObjectPath &acPath, activeConnections) { + priorActiveConnections.removeOne(acPath.path()); + QNetworkManagerConnectionActive *activeConnection = + this->activeConnections.value(acPath.path()); + if (!activeConnection) { + activeConnection = new QNetworkManagerConnectionActive(acPath.path()); + this->activeConnections.insert(acPath.path(), activeConnection); + + activeConnection->setConnections(); + connect(activeConnection, SIGNAL(propertiesChanged(QString,QMap<QString,QVariant>)), + this, SLOT(activeConnectionPropertiesChanged(QString,QMap<QString,QVariant>))); + } + + const QString id = QString::number(qHash(activeConnection->serviceName() + ' ' + + activeConnection->connection().path())); + + identifiers.removeOne(id); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + if (ptr) { + ptr->mutex.lock(); + if (activeConnection->state() == 2 && + ptr->state != QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Active; + ptr->mutex.unlock(); + + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } else { + ptr->mutex.unlock(); + } + } + } + + while (!priorActiveConnections.isEmpty()) + delete this->activeConnections.take(priorActiveConnections.takeFirst()); + + while (!identifiers.isEmpty()) { + // These configurations are not active + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.value(identifiers.takeFirst()); + + ptr->mutex.lock(); + if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Discovered; + ptr->mutex.unlock(); + + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } else { + ptr->mutex.unlock(); + } + } + } + } +} + +void QNetworkManagerEngine::activeConnectionPropertiesChanged(const QString &path, + const QMap<QString, QVariant> &properties) +{ + QMutexLocker locker(&mutex); + + Q_UNUSED(properties) + + QNetworkManagerConnectionActive *activeConnection = activeConnections.value(path); + + if (!activeConnection) + return; + + const QString id = QString::number(qHash(activeConnection->serviceName() + ' ' + + activeConnection->connection().path())); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + if (ptr) { + ptr->mutex.lock(); + if (activeConnection->state() == 2 && + ptr->state != QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Active; + ptr->mutex.unlock(); + + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } else { + ptr->mutex.unlock(); + } + } +} + +void QNetworkManagerEngine::devicePropertiesChanged(const QString &path, + const QMap<QString, QVariant> &properties) +{ + Q_UNUSED(path); + Q_UNUSED(properties); +} + +void QNetworkManagerEngine::deviceAdded(const QDBusObjectPath &path) +{ + QNetworkManagerInterfaceDevice device(path.path()); + if (device.deviceType() == DEVICE_TYPE_802_11_WIRELESS) { + QNetworkManagerInterfaceDeviceWireless *wirelessDevice = + new QNetworkManagerInterfaceDeviceWireless(device.connectionInterface()->path()); + + wirelessDevice->setConnections(); + connect(wirelessDevice, SIGNAL(accessPointAdded(QString,QDBusObjectPath)), + this, SLOT(newAccessPoint(QString,QDBusObjectPath))); + connect(wirelessDevice, SIGNAL(accessPointRemoved(QString,QDBusObjectPath)), + this, SLOT(removeAccessPoint(QString,QDBusObjectPath))); + connect(wirelessDevice, SIGNAL(propertiesChanged(QString,QMap<QString,QVariant>)), + this, SLOT(devicePropertiesChanged(QString,QMap<QString,QVariant>))); + + foreach (const QDBusObjectPath &apPath, wirelessDevice->getAccessPoints()) + newAccessPoint(QString(), apPath); + + mutex.lock(); + wirelessDevices.insert(path.path(), wirelessDevice); + mutex.unlock(); + } +} + +void QNetworkManagerEngine::deviceRemoved(const QDBusObjectPath &path) +{ + QMutexLocker locker(&mutex); + + delete wirelessDevices.take(path.path()); +} + +void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, + QNetworkManagerSettings *settings) +{ + QMutexLocker locker(&mutex); + + if (!settings) + settings = qobject_cast<QNetworkManagerSettings *>(sender()); + + if (!settings) + return; + + QNetworkManagerSettingsConnection *connection = + new QNetworkManagerSettingsConnection(settings->connectionInterface()->service(), + path.path()); + connections.append(connection); + + connect(connection, SIGNAL(removed(QString)), this, SLOT(removeConnection(QString))); + connect(connection, SIGNAL(updated(const QNmSettingsMap&)), + this, SLOT(updateConnection(const QNmSettingsMap&))); + + const QString service = connection->connectionInterface()->service(); + const QString settingsPath = connection->connectionInterface()->path(); + + QNetworkConfigurationPrivate *cpPriv = + parseConnection(service, settingsPath, connection->getSettings()); + + // Check if connection is active. + foreach (const QDBusObjectPath &acPath, interface->activeConnections()) { + QNetworkManagerConnectionActive activeConnection(acPath.path()); + + if (activeConnection.serviceName() == service && + activeConnection.connection().path() == settingsPath && + activeConnection.state() == 2) { + cpPriv->state |= QNetworkConfiguration::Active; + break; + } + } + + QNetworkConfigurationPrivatePointer ptr(cpPriv); + accessPointConfigurations.insert(ptr->id, ptr); + + locker.unlock(); + emit configurationAdded(ptr); +} + +void QNetworkManagerEngine::removeConnection(const QString &path) +{ + QMutexLocker locker(&mutex); + + Q_UNUSED(path) + + QNetworkManagerSettingsConnection *connection = + qobject_cast<QNetworkManagerSettingsConnection *>(sender()); + if (!connection) + return; + + connections.removeAll(connection); + + const QString id = QString::number(qHash(connection->connectionInterface()->service() + ' ' + + connection->connectionInterface()->path())); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(id); + + connection->deleteLater(); + + locker.unlock(); + emit configurationRemoved(ptr); +} + +void QNetworkManagerEngine::updateConnection(const QNmSettingsMap &settings) +{ + QMutexLocker locker(&mutex); + + QNetworkManagerSettingsConnection *connection = + qobject_cast<QNetworkManagerSettingsConnection *>(sender()); + if (!connection) + return; + + const QString service = connection->connectionInterface()->service(); + const QString settingsPath = connection->connectionInterface()->path(); + + QNetworkConfigurationPrivate *cpPriv = parseConnection(service, settingsPath, settings); + + // Check if connection is active. + foreach (const QDBusObjectPath &acPath, interface->activeConnections()) { + QNetworkManagerConnectionActive activeConnection(acPath.path()); + + if (activeConnection.serviceName() == service && + activeConnection.connection().path() == settingsPath && + activeConnection.state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + cpPriv->state |= QNetworkConfiguration::Active; + break; + } + } + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(cpPriv->id); + + ptr->mutex.lock(); + + ptr->isValid = cpPriv->isValid; + ptr->name = cpPriv->name; + ptr->id = cpPriv->id; + ptr->state = cpPriv->state; + + ptr->mutex.unlock(); + + locker.unlock(); + emit configurationChanged(ptr); + delete cpPriv; +} + +void QNetworkManagerEngine::activationFinished(QDBusPendingCallWatcher *watcher) +{ + QMutexLocker locker(&mutex); + + QDBusPendingReply<QDBusObjectPath> reply = *watcher; + if (!reply.isError()) { + QDBusObjectPath result = reply.value(); + + QNetworkManagerConnectionActive activeConnection(result.path()); + + const QString id = QString::number(qHash(activeConnection.serviceName() + ' ' + + activeConnection.connection().path())); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + if (ptr) { + ptr->mutex.lock(); + if (activeConnection.state() == 2 && + ptr->state != QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Active; + ptr->mutex.unlock(); + + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } else { + ptr->mutex.unlock(); + } + } + } +} + +void QNetworkManagerEngine::newAccessPoint(const QString &path, const QDBusObjectPath &objectPath) +{ + QMutexLocker locker(&mutex); + + Q_UNUSED(path) + + QNetworkManagerInterfaceAccessPoint *accessPoint = + new QNetworkManagerInterfaceAccessPoint(objectPath.path()); + accessPoints.append(accessPoint); + + accessPoint->setConnections(); + connect(accessPoint, SIGNAL(propertiesChanged(QMap<QString,QVariant>)), + this, SLOT(updateAccessPoint(QMap<QString,QVariant>))); + + // Check if configuration for this SSID already exists. + for (int i = 0; i < accessPoints.count(); ++i) { + if (accessPoint != accessPoints.at(i) && + accessPoint->ssid() == accessPoints.at(i)->ssid()) { + return; + } + } + + // Check if configuration exists for connection. + if (!accessPoint->ssid().isEmpty()) { + for (int i = 0; i < connections.count(); ++i) { + QNetworkManagerSettingsConnection *connection = connections.at(i); + + if (accessPoint->ssid() == connection->getSsid()) { + const QString service = connection->connectionInterface()->service(); + const QString settingsPath = connection->connectionInterface()->path(); + const QString connectionId = QString::number(qHash(service + ' ' + settingsPath)); + + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.value(connectionId); + ptr->mutex.lock(); + ptr->state = QNetworkConfiguration::Discovered; + ptr->mutex.unlock(); + + locker.unlock(); + emit configurationChanged(ptr); + return; + } + } + } + + // New access point. + QNetworkConfigurationPrivatePointer ptr(new QNetworkConfigurationPrivate); + + ptr->name = accessPoint->ssid(); + ptr->isValid = true; + ptr->id = QString::number(qHash(objectPath.path())); + ptr->type = QNetworkConfiguration::InternetAccessPoint; + if(accessPoint->flags() == NM_802_11_AP_FLAGS_PRIVACY) { + ptr->purpose = QNetworkConfiguration::PrivatePurpose; + } else { + ptr->purpose = QNetworkConfiguration::PublicPurpose; + } + ptr->state = QNetworkConfiguration::Undefined; + ptr->bearerType = QNetworkConfiguration::BearerWLAN; + + accessPointConfigurations.insert(ptr->id, ptr); + + locker.unlock(); + emit configurationAdded(ptr); +} + +void QNetworkManagerEngine::removeAccessPoint(const QString &path, + const QDBusObjectPath &objectPath) +{ + QMutexLocker locker(&mutex); + + Q_UNUSED(path) + + for (int i = 0; i < accessPoints.count(); ++i) { + QNetworkManagerInterfaceAccessPoint *accessPoint = accessPoints.at(i); + + if (accessPoint->connectionInterface()->path() == objectPath.path()) { + accessPoints.removeOne(accessPoint); + + if (configuredAccessPoints.contains(accessPoint)) { + // find connection and change state to Defined + configuredAccessPoints.removeOne(accessPoint); + for (int i = 0; i < connections.count(); ++i) { + QNetworkManagerSettingsConnection *connection = connections.at(i); + + if (accessPoint->ssid() == connection->getSsid()) { + const QString service = connection->connectionInterface()->service(); + const QString settingsPath = connection->connectionInterface()->path(); + const QString connectionId = + QString::number(qHash(service + ' ' + settingsPath)); + + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.value(connectionId); + ptr->mutex.lock(); + ptr->state = QNetworkConfiguration::Defined; + ptr->mutex.unlock(); + + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + break; + } + } + } else { + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.take(QString::number(qHash(objectPath.path()))); + + if (ptr) { + locker.unlock(); + emit configurationRemoved(ptr); + locker.relock(); + } + } + + delete accessPoint; + + break; + } + } +} + +void QNetworkManagerEngine::updateAccessPoint(const QMap<QString, QVariant> &map) +{ + QMutexLocker locker(&mutex); + + Q_UNUSED(map) + + QNetworkManagerInterfaceAccessPoint *accessPoint = + qobject_cast<QNetworkManagerInterfaceAccessPoint *>(sender()); + if (!accessPoint) + return; + + for (int i = 0; i < connections.count(); ++i) { + QNetworkManagerSettingsConnection *connection = connections.at(i); + + if (accessPoint->ssid() == connection->getSsid()) { + const QString service = connection->connectionInterface()->service(); + const QString settingsPath = connection->connectionInterface()->path(); + const QString connectionId = QString::number(qHash(service + ' ' + settingsPath)); + + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.value(connectionId); + ptr->mutex.lock(); + ptr->state = QNetworkConfiguration::Discovered; + ptr->mutex.unlock(); + + locker.unlock(); + emit configurationChanged(ptr); + return; + } + } +} + +QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QString &service, + const QString &settingsPath, + const QNmSettingsMap &map) +{ + QNetworkConfigurationPrivate *cpPriv = new QNetworkConfigurationPrivate; + cpPriv->name = map.value("connection").value("id").toString(); + cpPriv->isValid = true; + cpPriv->id = QString::number(qHash(service + ' ' + settingsPath)); + cpPriv->type = QNetworkConfiguration::InternetAccessPoint; + + cpPriv->purpose = QNetworkConfiguration::PublicPurpose; + + cpPriv->state = QNetworkConfiguration::Defined; + + const QString connectionType = map.value("connection").value("type").toString(); + + if (connectionType == QLatin1String("802-3-ethernet")) { + cpPriv->bearerType = QNetworkConfiguration::BearerEthernet; + cpPriv->purpose = QNetworkConfiguration::PublicPurpose; + + foreach (const QDBusObjectPath &devicePath, interface->getDevices()) { + QNetworkManagerInterfaceDevice device(devicePath.path()); + if (device.deviceType() == DEVICE_TYPE_802_3_ETHERNET) { + QNetworkManagerInterfaceDeviceWired wiredDevice(device.connectionInterface()->path()); + if (wiredDevice.carrier()) { + cpPriv->state |= QNetworkConfiguration::Discovered; + break; + } + + } + } + } else if (connectionType == QLatin1String("802-11-wireless")) { + cpPriv->bearerType = QNetworkConfiguration::BearerWLAN; + + const QString connectionSsid = map.value("802-11-wireless").value("ssid").toString(); + const QString connectionSecurity = map.value("802-11-wireless").value("security").toString(); + if(!connectionSecurity.isEmpty()) { + cpPriv->purpose = QNetworkConfiguration::PrivatePurpose; + } else { + cpPriv->purpose = QNetworkConfiguration::PublicPurpose; + } + for (int i = 0; i < accessPoints.count(); ++i) { + if (connectionSsid == accessPoints.at(i)->ssid()) { + cpPriv->state |= QNetworkConfiguration::Discovered; + if (!configuredAccessPoints.contains(accessPoints.at(i))) { + configuredAccessPoints.append(accessPoints.at(i)); + + const QString accessPointId = + QString::number(qHash(accessPoints.at(i)->connectionInterface()->path())); + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.take(accessPointId); + + mutex.unlock(); + emit configurationRemoved(ptr); + mutex.lock(); + } + break; + } + } + } else if (connectionType == "gsm") { + cpPriv->bearerType = QNetworkConfiguration::Bearer2G; + } else if (connectionType == "cdma") { + cpPriv->bearerType = QNetworkConfiguration::BearerCDMA2000; + } + + return cpPriv; +} + +QNetworkManagerSettingsConnection *QNetworkManagerEngine::connectionFromId(const QString &id) const +{ + for (int i = 0; i < connections.count(); ++i) { + QNetworkManagerSettingsConnection *connection = connections.at(i); + const QString service = connection->connectionInterface()->service(); + const QString settingsPath = connection->connectionInterface()->path(); + + const QString identifier = QString::number(qHash(service + ' ' + settingsPath)); + + if (id == identifier) + return connection; + } + + return 0; +} + +QNetworkSession::State QNetworkManagerEngine::sessionStateForId(const QString &id) +{ + QMutexLocker locker(&mutex); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + if (!ptr) + return QNetworkSession::Invalid; + + if (!ptr->isValid) + return QNetworkSession::Invalid; + + foreach (const QString &acPath, activeConnections.keys()) { + QNetworkManagerConnectionActive *activeConnection = activeConnections.value(acPath); + + const QString identifier = QString::number(qHash(activeConnection->serviceName() + ' ' + + activeConnection->connection().path())); + + if (id == identifier) { + switch (activeConnection->state()) { + case 0: + return QNetworkSession::Disconnected; + case 1: + return QNetworkSession::Connecting; + case 2: + return QNetworkSession::Connected; + } + } + } + + 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; +} + +quint64 QNetworkManagerEngine::bytesWritten(const QString &id) +{ + QMutexLocker locker(&mutex); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + if (ptr && (ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + const QString networkInterface = getInterfaceFromId(id); + if (!networkInterface.isEmpty()) { + const QString devFile = QLatin1String("/sys/class/net/") + + networkInterface + + QLatin1String("/statistics/tx_bytes"); + + quint64 result = Q_UINT64_C(0); + + QFile tx(devFile); + if (tx.exists() && tx.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&tx); + in >> result; + tx.close(); + } + + return result; + } + } + + return Q_UINT64_C(0); +} + +quint64 QNetworkManagerEngine::bytesReceived(const QString &id) +{ + QMutexLocker locker(&mutex); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + if (ptr && (ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + const QString networkInterface = getInterfaceFromId(id); + if (!networkInterface.isEmpty()) { + const QString devFile = QLatin1String("/sys/class/net/") + + networkInterface + + QLatin1String("/statistics/rx_bytes"); + + quint64 result = Q_UINT64_C(0); + + QFile tx(devFile); + if (tx.exists() && tx.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&tx); + in >> result; + tx.close(); + } + + return result; + } + } + + return Q_UINT64_C(0); +} + +quint64 QNetworkManagerEngine::startTime(const QString &id) +{ + QMutexLocker locker(&mutex); + + QNetworkManagerSettingsConnection *connection = connectionFromId(id); + if (connection) + return connection->getTimestamp(); + else + return Q_UINT64_C(0); +} + +QNetworkConfigurationManager::Capabilities QNetworkManagerEngine::capabilities() const +{ + return QNetworkConfigurationManager::ForcedRoaming | + QNetworkConfigurationManager::CanStartAndStopInterfaces; +} + +QNetworkSessionPrivate *QNetworkManagerEngine::createSessionBackend() +{ + return new QNetworkSessionPrivateImpl; +} + +QNetworkConfigurationPrivatePointer QNetworkManagerEngine::defaultConfiguration() +{ + return QNetworkConfigurationPrivatePointer(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_DBUS +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h new file mode 100644 index 0000000..78ebb0a --- /dev/null +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNETWORKMANAGERENGINE_P_H +#define QNETWORKMANAGERENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "../qbearerengine_impl.h" + +#include "qnetworkmanagerservice.h" + +#include <QMap> +#include <QVariant> + +#ifndef QT_NO_BEARERMANAGEMENT +#ifndef QT_NO_DBUS + +QT_BEGIN_NAMESPACE + +class QNetworkManagerEngine : public QBearerEngineImpl +{ + Q_OBJECT + +public: + QNetworkManagerEngine(QObject *parent = 0); + ~QNetworkManagerEngine(); + + bool networkManagerAvailable() const; + + QString getInterfaceFromId(const QString &id); + bool hasIdentifier(const QString &id); + + void connectToId(const QString &id); + void disconnectFromId(const QString &id); + + Q_INVOKABLE void initialize(); + Q_INVOKABLE void requestUpdate(); + + QNetworkSession::State sessionStateForId(const QString &id); + + quint64 bytesWritten(const QString &id); + quint64 bytesReceived(const QString &id); + quint64 startTime(const QString &id); + + QNetworkConfigurationManager::Capabilities capabilities() const; + + QNetworkSessionPrivate *createSessionBackend(); + + QNetworkConfigurationPrivatePointer defaultConfiguration(); + +private Q_SLOTS: + void interfacePropertiesChanged(const QString &path, + const QMap<QString, QVariant> &properties); + void activeConnectionPropertiesChanged(const QString &path, + const QMap<QString, QVariant> &properties); + void devicePropertiesChanged(const QString &path, + const QMap<QString, QVariant> &properties); + + void deviceAdded(const QDBusObjectPath &path); + void deviceRemoved(const QDBusObjectPath &path); + + void newConnection(const QDBusObjectPath &path, QNetworkManagerSettings *settings = 0); + void removeConnection(const QString &path); + void updateConnection(const QNmSettingsMap &settings); + void activationFinished(QDBusPendingCallWatcher *watcher); + + void newAccessPoint(const QString &path, const QDBusObjectPath &objectPath); + void removeAccessPoint(const QString &path, const QDBusObjectPath &objectPath); + void updateAccessPoint(const QMap<QString, QVariant> &map); + +private: + QNetworkConfigurationPrivate *parseConnection(const QString &service, + const QString &settingsPath, + const QNmSettingsMap &map); + QNetworkManagerSettingsConnection *connectionFromId(const QString &id) const; + +private: + QNetworkManagerInterface *interface; + QNetworkManagerSettings *systemSettings; + QNetworkManagerSettings *userSettings; + QHash<QString, QNetworkManagerInterfaceDeviceWireless *> wirelessDevices; + QHash<QString, QNetworkManagerConnectionActive *> activeConnections; + QList<QNetworkManagerSettingsConnection *> connections; + QList<QNetworkManagerInterfaceAccessPoint *> accessPoints; + QList<QNetworkManagerInterfaceAccessPoint *> configuredAccessPoints; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_DBUS +#endif // QT_NO_BEARERMANAGEMENT + +#endif + diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp new file mode 100644 index 0000000..499fe5a --- /dev/null +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp @@ -0,0 +1,931 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QObject> +#include <QList> +#include <QtDBus/QtDBus> +#include <QtDBus/QDBusConnection> +#include <QtDBus/QDBusError> +#include <QtDBus/QDBusInterface> +#include <QtDBus/QDBusMessage> +#include <QtDBus/QDBusReply> +#include <QtDBus/QDBusPendingCallWatcher> +#include <QtDBus/QDBusObjectPath> +#include <QtDBus/QDBusPendingCall> + +#include "qnetworkmanagerservice.h" +#include "qnmdbushelper.h" + +#ifndef QT_NO_DBUS + +QT_BEGIN_NAMESPACE + +static QDBusConnection dbusConnection = QDBusConnection::systemBus(); + +class QNetworkManagerInterfacePrivate +{ +public: + QDBusInterface *connectionInterface; + bool valid; +}; + +QNetworkManagerInterface::QNetworkManagerInterface(QObject *parent) + : QObject(parent) +{ + d = new QNetworkManagerInterfacePrivate(); + d->connectionInterface = new QDBusInterface(QLatin1String(NM_DBUS_SERVICE), + QLatin1String(NM_DBUS_PATH), + QLatin1String(NM_DBUS_INTERFACE), + dbusConnection); + if (!d->connectionInterface->isValid()) { + d->valid = false; + return; + } + d->valid = true; + nmDBusHelper = new QNmDBusHelper(this); + connect(nmDBusHelper, SIGNAL(pathForPropertiesChanged(const QString &,QMap<QString,QVariant>)), + this,SIGNAL(propertiesChanged( const QString &, QMap<QString,QVariant>))); + connect(nmDBusHelper,SIGNAL(pathForStateChanged(const QString &, quint32)), + this, SIGNAL(stateChanged(const QString&, quint32))); + +} + +QNetworkManagerInterface::~QNetworkManagerInterface() +{ + delete d->connectionInterface; + delete d; +} + +bool QNetworkManagerInterface::isValid() +{ + return d->valid; +} + +bool QNetworkManagerInterface::setConnections() +{ + if(!isValid() ) + return false; + bool allOk = false; + if (!dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), + QLatin1String(NM_DBUS_PATH), + QLatin1String(NM_DBUS_INTERFACE), + QLatin1String("PropertiesChanged"), + nmDBusHelper,SLOT(slotPropertiesChanged( QMap<QString,QVariant>)))) { + allOk = true; + } + if (!dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), + QLatin1String(NM_DBUS_PATH), + QLatin1String(NM_DBUS_INTERFACE), + QLatin1String("DeviceAdded"), + this,SIGNAL(deviceAdded(QDBusObjectPath)))) { + allOk = true; + } + if (!dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), + QLatin1String(NM_DBUS_PATH), + QLatin1String(NM_DBUS_INTERFACE), + QLatin1String("DeviceRemoved"), + this,SIGNAL(deviceRemoved(QDBusObjectPath)))) { + allOk = true; + } + + return allOk; +} + +QDBusInterface *QNetworkManagerInterface::connectionInterface() const +{ + return d->connectionInterface; +} + +QList <QDBusObjectPath> QNetworkManagerInterface::getDevices() const +{ + QDBusReply<QList<QDBusObjectPath> > reply = d->connectionInterface->call(QLatin1String("GetDevices")); + return reply.value(); +} + +void QNetworkManagerInterface::activateConnection( const QString &serviceName, + QDBusObjectPath connectionPath, + QDBusObjectPath devicePath, + QDBusObjectPath specificObject) +{ + QDBusPendingCall pendingCall = d->connectionInterface->asyncCall(QLatin1String("ActivateConnection"), + QVariant(serviceName), + QVariant::fromValue(connectionPath), + QVariant::fromValue(devicePath), + QVariant::fromValue(specificObject)); + + QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(pendingCall, this); + connect(callWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SIGNAL(activationFinished(QDBusPendingCallWatcher*))); +} + +void QNetworkManagerInterface::deactivateConnection(QDBusObjectPath connectionPath) const +{ + d->connectionInterface->call(QLatin1String("DeactivateConnection"), QVariant::fromValue(connectionPath)); +} + +bool QNetworkManagerInterface::wirelessEnabled() const +{ + return d->connectionInterface->property("WirelessEnabled").toBool(); +} + +bool QNetworkManagerInterface::wirelessHardwareEnabled() const +{ + return d->connectionInterface->property("WirelessHardwareEnabled").toBool(); +} + +QList <QDBusObjectPath> QNetworkManagerInterface::activeConnections() const +{ + QVariant prop = d->connectionInterface->property("ActiveConnections"); + return prop.value<QList<QDBusObjectPath> >(); +} + +quint32 QNetworkManagerInterface::state() +{ + return d->connectionInterface->property("State").toUInt(); +} + +class QNetworkManagerInterfaceAccessPointPrivate +{ +public: + QDBusInterface *connectionInterface; + QString path; + bool valid; +}; + +QNetworkManagerInterfaceAccessPoint::QNetworkManagerInterfaceAccessPoint(const QString &dbusPathName, QObject *parent) + : QObject(parent), nmDBusHelper(0) +{ + d = new QNetworkManagerInterfaceAccessPointPrivate(); + d->path = dbusPathName; + d->connectionInterface = new QDBusInterface(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_ACCESS_POINT), + dbusConnection); + if (!d->connectionInterface->isValid()) { + d->valid = false; + return; + } + d->valid = true; + +} + +QNetworkManagerInterfaceAccessPoint::~QNetworkManagerInterfaceAccessPoint() +{ + delete d->connectionInterface; + delete d; +} + +bool QNetworkManagerInterfaceAccessPoint::isValid() +{ + return d->valid; +} + +bool QNetworkManagerInterfaceAccessPoint::setConnections() +{ + if(!isValid() ) + return false; + + bool allOk = false; + delete nmDBusHelper; + nmDBusHelper = new QNmDBusHelper(this); + connect(nmDBusHelper, SIGNAL(pathForPropertiesChanged(const QString &,QMap<QString,QVariant>)), + this,SIGNAL(propertiesChanged( const QString &, QMap<QString,QVariant>))); + + if(dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_ACCESS_POINT), + QLatin1String("PropertiesChanged"), + nmDBusHelper,SLOT(slotPropertiesChanged( QMap<QString,QVariant>))) ) { + allOk = true; + + } + return allOk; +} + +QDBusInterface *QNetworkManagerInterfaceAccessPoint::connectionInterface() const +{ + return d->connectionInterface; +} + +quint32 QNetworkManagerInterfaceAccessPoint::flags() const +{ + return d->connectionInterface->property("Flags").toUInt(); +} + +quint32 QNetworkManagerInterfaceAccessPoint::wpaFlags() const +{ + return d->connectionInterface->property("WpaFlags").toUInt(); +} + +quint32 QNetworkManagerInterfaceAccessPoint::rsnFlags() const +{ + return d->connectionInterface->property("RsnFlags").toUInt(); +} + +QString QNetworkManagerInterfaceAccessPoint::ssid() const +{ + return d->connectionInterface->property("Ssid").toString(); +} + +quint32 QNetworkManagerInterfaceAccessPoint::frequency() const +{ + return d->connectionInterface->property("Frequency").toUInt(); +} + +QString QNetworkManagerInterfaceAccessPoint::hwAddress() const +{ + return d->connectionInterface->property("HwAddress").toString(); +} + +quint32 QNetworkManagerInterfaceAccessPoint::mode() const +{ + return d->connectionInterface->property("Mode").toUInt(); +} + +quint32 QNetworkManagerInterfaceAccessPoint::maxBitrate() const +{ + return d->connectionInterface->property("MaxBitrate").toUInt(); +} + +quint32 QNetworkManagerInterfaceAccessPoint::strength() const +{ + return d->connectionInterface->property("Strength").toUInt(); +} + +class QNetworkManagerInterfaceDevicePrivate +{ +public: + QDBusInterface *connectionInterface; + QString path; + bool valid; +}; + +QNetworkManagerInterfaceDevice::QNetworkManagerInterfaceDevice(const QString &deviceObjectPath, QObject *parent) + : QObject(parent), nmDBusHelper(0) +{ + d = new QNetworkManagerInterfaceDevicePrivate(); + d->path = deviceObjectPath; + d->connectionInterface = new QDBusInterface(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_DEVICE), + dbusConnection); + if (!d->connectionInterface->isValid()) { + d->valid = false; + return; + } + d->valid = true; +} + +QNetworkManagerInterfaceDevice::~QNetworkManagerInterfaceDevice() +{ + delete d->connectionInterface; + delete d; +} + +bool QNetworkManagerInterfaceDevice::isValid() +{ + return d->valid; +} + +bool QNetworkManagerInterfaceDevice::setConnections() +{ + if(!isValid() ) + return false; + + bool allOk = false; + delete nmDBusHelper; + nmDBusHelper = new QNmDBusHelper(this); + connect(nmDBusHelper,SIGNAL(pathForStateChanged(const QString &, quint32)), + this, SIGNAL(stateChanged(const QString&, quint32))); + if(dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_DEVICE), + QLatin1String("StateChanged"), + nmDBusHelper,SLOT(deviceStateChanged(quint32)))) { + allOk = true; + } + return allOk; +} + +QDBusInterface *QNetworkManagerInterfaceDevice::connectionInterface() const +{ + return d->connectionInterface; +} + +QString QNetworkManagerInterfaceDevice::udi() const +{ + return d->connectionInterface->property("Udi").toString(); +} + +QString QNetworkManagerInterfaceDevice::networkInterface() const +{ + return d->connectionInterface->property("Interface").toString(); +} + +quint32 QNetworkManagerInterfaceDevice::ip4Address() const +{ + return d->connectionInterface->property("Ip4Address").toUInt(); +} + +quint32 QNetworkManagerInterfaceDevice::state() const +{ + return d->connectionInterface->property("State").toUInt(); +} + +quint32 QNetworkManagerInterfaceDevice::deviceType() const +{ + return d->connectionInterface->property("DeviceType").toUInt(); +} + +QDBusObjectPath QNetworkManagerInterfaceDevice::ip4config() const +{ + QVariant prop = d->connectionInterface->property("Ip4Config"); + return prop.value<QDBusObjectPath>(); +} + +class QNetworkManagerInterfaceDeviceWiredPrivate +{ +public: + QDBusInterface *connectionInterface; + QString path; + bool valid; +}; + +QNetworkManagerInterfaceDeviceWired::QNetworkManagerInterfaceDeviceWired(const QString &ifaceDevicePath, QObject *parent) + : QObject(parent), nmDBusHelper(0) +{ + d = new QNetworkManagerInterfaceDeviceWiredPrivate(); + d->path = ifaceDevicePath; + d->connectionInterface = new QDBusInterface(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRED), + dbusConnection, parent); + if (!d->connectionInterface->isValid()) { + d->valid = false; + return; + } + d->valid = true; +} + +QNetworkManagerInterfaceDeviceWired::~QNetworkManagerInterfaceDeviceWired() +{ + delete d->connectionInterface; + delete d; +} + +bool QNetworkManagerInterfaceDeviceWired::isValid() +{ + + return d->valid; +} + +bool QNetworkManagerInterfaceDeviceWired::setConnections() +{ + if(!isValid() ) + return false; + + bool allOk = false; + + delete nmDBusHelper; + nmDBusHelper = new QNmDBusHelper(this); + connect(nmDBusHelper, SIGNAL(pathForPropertiesChanged(const QString &,QMap<QString,QVariant>)), + this,SIGNAL(propertiesChanged( const QString &, QMap<QString,QVariant>))); + if(dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRED), + QLatin1String("PropertiesChanged"), + nmDBusHelper,SLOT(slotPropertiesChanged( QMap<QString,QVariant>))) ) { + allOk = true; + } + return allOk; +} + +QDBusInterface *QNetworkManagerInterfaceDeviceWired::connectionInterface() const +{ + return d->connectionInterface; +} + +QString QNetworkManagerInterfaceDeviceWired::hwAddress() const +{ + return d->connectionInterface->property("HwAddress").toString(); +} + +quint32 QNetworkManagerInterfaceDeviceWired::speed() const +{ + return d->connectionInterface->property("Speed").toUInt(); +} + +bool QNetworkManagerInterfaceDeviceWired::carrier() const +{ + return d->connectionInterface->property("Carrier").toBool(); +} + +class QNetworkManagerInterfaceDeviceWirelessPrivate +{ +public: + QDBusInterface *connectionInterface; + QString path; + bool valid; +}; + +QNetworkManagerInterfaceDeviceWireless::QNetworkManagerInterfaceDeviceWireless(const QString &ifaceDevicePath, QObject *parent) + : QObject(parent), nmDBusHelper(0) +{ + d = new QNetworkManagerInterfaceDeviceWirelessPrivate(); + d->path = ifaceDevicePath; + d->connectionInterface = new QDBusInterface(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), + dbusConnection, parent); + if (!d->connectionInterface->isValid()) { + d->valid = false; + return; + } + d->valid = true; +} + +QNetworkManagerInterfaceDeviceWireless::~QNetworkManagerInterfaceDeviceWireless() +{ + delete d->connectionInterface; + delete d; +} + +bool QNetworkManagerInterfaceDeviceWireless::isValid() +{ + return d->valid; +} + +bool QNetworkManagerInterfaceDeviceWireless::setConnections() +{ + if(!isValid() ) + return false; + + bool allOk = false; + delete nmDBusHelper; + nmDBusHelper = new QNmDBusHelper(this); + connect(nmDBusHelper, SIGNAL(pathForPropertiesChanged(const QString &,QMap<QString,QVariant>)), + this,SIGNAL(propertiesChanged( const QString &, QMap<QString,QVariant>))); + + connect(nmDBusHelper, SIGNAL(pathForAccessPointAdded(const QString &,QDBusObjectPath)), + this,SIGNAL(accessPointAdded(const QString &,QDBusObjectPath))); + + connect(nmDBusHelper, SIGNAL(pathForAccessPointRemoved(const QString &,QDBusObjectPath)), + this,SIGNAL(accessPointRemoved(const QString &,QDBusObjectPath))); + + if(!dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), + QLatin1String("AccessPointAdded"), + nmDBusHelper, SLOT(slotAccessPointAdded( QDBusObjectPath )))) { + allOk = true; + } + + + if(!dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), + QLatin1String("AccessPointRemoved"), + nmDBusHelper, SLOT(slotAccessPointRemoved( QDBusObjectPath )))) { + allOk = true; + } + + + if(!dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), + QLatin1String("PropertiesChanged"), + nmDBusHelper,SLOT(slotPropertiesChanged( QMap<QString,QVariant>)))) { + allOk = true; + } + + return allOk; +} + +QDBusInterface *QNetworkManagerInterfaceDeviceWireless::connectionInterface() const +{ + return d->connectionInterface; +} + +QList <QDBusObjectPath> QNetworkManagerInterfaceDeviceWireless::getAccessPoints() +{ + QDBusReply<QList<QDBusObjectPath> > reply = d->connectionInterface->call(QLatin1String("GetAccessPoints")); + return reply.value(); +} + +QString QNetworkManagerInterfaceDeviceWireless::hwAddress() const +{ + return d->connectionInterface->property("HwAddress").toString(); +} + +quint32 QNetworkManagerInterfaceDeviceWireless::mode() const +{ + return d->connectionInterface->property("Mode").toUInt(); +} + +quint32 QNetworkManagerInterfaceDeviceWireless::bitrate() const +{ + return d->connectionInterface->property("Bitrate").toUInt(); +} + +QDBusObjectPath QNetworkManagerInterfaceDeviceWireless::activeAccessPoint() const +{ + return d->connectionInterface->property("ActiveAccessPoint").value<QDBusObjectPath>(); +} + +quint32 QNetworkManagerInterfaceDeviceWireless::wirelessCapabilities() const +{ + return d->connectionInterface->property("WirelelessCapabilities").toUInt(); +} + +class QNetworkManagerSettingsPrivate +{ +public: + QDBusInterface *connectionInterface; + QString path; + bool valid; +}; + +QNetworkManagerSettings::QNetworkManagerSettings(const QString &settingsService, QObject *parent) + : QObject(parent) +{ + d = new QNetworkManagerSettingsPrivate(); + d->path = settingsService; + d->connectionInterface = new QDBusInterface(settingsService, + QLatin1String(NM_DBUS_PATH_SETTINGS), + QLatin1String(NM_DBUS_IFACE_SETTINGS), + dbusConnection); + if (!d->connectionInterface->isValid()) { + d->valid = false; + return; + } + d->valid = true; +} + +QNetworkManagerSettings::~QNetworkManagerSettings() +{ + delete d->connectionInterface; + delete d; +} + +bool QNetworkManagerSettings::isValid() +{ + return d->valid; +} + +bool QNetworkManagerSettings::setConnections() +{ + bool allOk = false; + + if (!dbusConnection.connect(d->path, QLatin1String(NM_DBUS_PATH_SETTINGS), + QLatin1String(NM_DBUS_IFACE_SETTINGS), QLatin1String("NewConnection"), + this, SIGNAL(newConnection(QDBusObjectPath)))) { + allOk = true; + } + + return allOk; +} + +QList <QDBusObjectPath> QNetworkManagerSettings::listConnections() +{ + QDBusReply<QList<QDBusObjectPath> > reply = d->connectionInterface->call(QLatin1String("ListConnections")); + return reply.value(); +} + +QDBusInterface *QNetworkManagerSettings::connectionInterface() const +{ + return d->connectionInterface; +} + + +class QNetworkManagerSettingsConnectionPrivate +{ +public: + QDBusInterface *connectionInterface; + QString path; + QString service; + QNmSettingsMap settingsMap; + bool valid; +}; + +QNetworkManagerSettingsConnection::QNetworkManagerSettingsConnection(const QString &settingsService, const QString &connectionObjectPath, QObject *parent) + : QObject(parent), nmDBusHelper(0) +{ + qDBusRegisterMetaType<QNmSettingsMap>(); + d = new QNetworkManagerSettingsConnectionPrivate(); + d->path = connectionObjectPath; + d->service = settingsService; + d->connectionInterface = new QDBusInterface(settingsService, + d->path, + QLatin1String(NM_DBUS_IFACE_SETTINGS_CONNECTION), + dbusConnection, parent); + if (!d->connectionInterface->isValid()) { + d->valid = false; + return; + } + d->valid = true; + QDBusReply< QNmSettingsMap > rep = d->connectionInterface->call(QLatin1String("GetSettings")); + d->settingsMap = rep.value(); +} + +QNetworkManagerSettingsConnection::~QNetworkManagerSettingsConnection() +{ + delete d->connectionInterface; + delete d; +} + +bool QNetworkManagerSettingsConnection::isValid() +{ + return d->valid; +} + +bool QNetworkManagerSettingsConnection::setConnections() +{ + if(!isValid() ) + return false; + + bool allOk = false; + if(!dbusConnection.connect(d->service, d->path, + QLatin1String(NM_DBUS_IFACE_SETTINGS_CONNECTION), QLatin1String("Updated"), + this, SIGNAL(updated(QNmSettingsMap)))) { + allOk = true; + } else { + QDBusError error = dbusConnection.lastError(); + } + + delete nmDBusHelper; + nmDBusHelper = new QNmDBusHelper(this); + connect(nmDBusHelper, SIGNAL(pathForSettingsRemoved(const QString &)), + this,SIGNAL(removed( const QString &))); + + if (!dbusConnection.connect(d->service, d->path, + QLatin1String(NM_DBUS_IFACE_SETTINGS_CONNECTION), QLatin1String("Removed"), + nmDBusHelper, SIGNAL(slotSettingsRemoved()))) { + allOk = true; + } + + return allOk; +} + +QDBusInterface *QNetworkManagerSettingsConnection::connectionInterface() const +{ + return d->connectionInterface; +} + +QNmSettingsMap QNetworkManagerSettingsConnection::getSettings() +{ + QDBusReply< QNmSettingsMap > rep = d->connectionInterface->call(QLatin1String("GetSettings")); + d->settingsMap = rep.value(); + return d->settingsMap; +} + +NMDeviceType QNetworkManagerSettingsConnection::getType() +{ + const QString devType = + d->settingsMap.value(QLatin1String("connection")).value(QLatin1String("type")).toString(); + + if (devType == QLatin1String("802-3-ethernet")) + return DEVICE_TYPE_802_3_ETHERNET; + else if (devType == QLatin1String("802-11-wireless")) + return DEVICE_TYPE_802_11_WIRELESS; + else + return DEVICE_TYPE_UNKNOWN; +} + +bool QNetworkManagerSettingsConnection::isAutoConnect() +{ + const QVariant autoConnect = + d->settingsMap.value(QLatin1String("connection")).value(QLatin1String("autoconnect")); + + // NetworkManager default is to auto connect + if (!autoConnect.isValid()) + return true; + + return autoConnect.toBool(); +} + +quint64 QNetworkManagerSettingsConnection::getTimestamp() +{ + return d->settingsMap.value(QLatin1String("connection")) + .value(QLatin1String("timestamp")).toUInt(); +} + +QString QNetworkManagerSettingsConnection::getId() +{ + return d->settingsMap.value(QLatin1String("connection")).value(QLatin1String("id")).toString(); +} + +QString QNetworkManagerSettingsConnection::getUuid() +{ + const QString id = d->settingsMap.value(QLatin1String("connection")) + .value(QLatin1String("uuid")).toString(); + + // is no uuid, return the connection path + return id.isEmpty() ? d->connectionInterface->path() : id; +} + +QString QNetworkManagerSettingsConnection::getSsid() +{ + return d->settingsMap.value(QLatin1String("802-11-wireless")) + .value(QLatin1String("ssid")).toString(); +} + +QString QNetworkManagerSettingsConnection::getMacAddress() +{ + NMDeviceType type = getType(); + + if (type == DEVICE_TYPE_802_3_ETHERNET) { + return d->settingsMap.value(QLatin1String("802-3-ethernet")) + .value(QLatin1String("mac-address")).toString(); + } else if (type == DEVICE_TYPE_802_11_WIRELESS) { + return d->settingsMap.value(QLatin1String("802-11-wireless")) + .value(QLatin1String("mac-address")).toString(); + } else { + return QString(); + } +} + +QStringList QNetworkManagerSettingsConnection::getSeenBssids() +{ + if (getType() == DEVICE_TYPE_802_11_WIRELESS) { + return d->settingsMap.value(QLatin1String("802-11-wireless")) + .value(QLatin1String("seen-bssids")).toStringList(); + } else { + return QStringList(); + } +} + +class QNetworkManagerConnectionActivePrivate +{ +public: + QDBusInterface *connectionInterface; + QString path; + bool valid; +}; + +QNetworkManagerConnectionActive::QNetworkManagerConnectionActive( const QString &activeConnectionObjectPath, QObject *parent) + : QObject(parent), nmDBusHelper(0) +{ + d = new QNetworkManagerConnectionActivePrivate(); + d->path = activeConnectionObjectPath; + d->connectionInterface = new QDBusInterface(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_ACTIVE_CONNECTION), + dbusConnection, parent); + if (!d->connectionInterface->isValid()) { + d->valid = false; + return; + } + d->valid = true; +} + +QNetworkManagerConnectionActive::~QNetworkManagerConnectionActive() +{ + delete d->connectionInterface; + delete d; +} + +bool QNetworkManagerConnectionActive::isValid() +{ + return d->valid; +} + +bool QNetworkManagerConnectionActive::setConnections() +{ + if(!isValid() ) + return false; + + bool allOk = false; + delete nmDBusHelper; + nmDBusHelper = new QNmDBusHelper(this); + connect(nmDBusHelper, SIGNAL(pathForPropertiesChanged(const QString &,QMap<QString,QVariant>)), + this,SIGNAL(propertiesChanged( const QString &, QMap<QString,QVariant>))); + if(dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_ACTIVE_CONNECTION), + QLatin1String("PropertiesChanged"), + nmDBusHelper,SLOT(slotPropertiesChanged( QMap<QString,QVariant>))) ) { + allOk = true; + } + + return allOk; +} + +QDBusInterface *QNetworkManagerConnectionActive::connectionInterface() const +{ + return d->connectionInterface; +} + +QString QNetworkManagerConnectionActive::serviceName() const +{ + return d->connectionInterface->property("ServiceName").toString(); +} + +QDBusObjectPath QNetworkManagerConnectionActive::connection() const +{ + QVariant prop = d->connectionInterface->property("Connection"); + return prop.value<QDBusObjectPath>(); +} + +QDBusObjectPath QNetworkManagerConnectionActive::specificObject() const +{ + QVariant prop = d->connectionInterface->property("SpecificObject"); + return prop.value<QDBusObjectPath>(); +} + +QList<QDBusObjectPath> QNetworkManagerConnectionActive::devices() const +{ + QVariant prop = d->connectionInterface->property("Devices"); + return prop.value<QList<QDBusObjectPath> >(); +} + +quint32 QNetworkManagerConnectionActive::state() const +{ + return d->connectionInterface->property("State").toUInt(); +} + +bool QNetworkManagerConnectionActive::defaultRoute() const +{ + return d->connectionInterface->property("Default").toBool(); +} + +class QNetworkManagerIp4ConfigPrivate +{ +public: + QDBusInterface *connectionInterface; + QString path; + bool valid; +}; + +QNetworkManagerIp4Config::QNetworkManagerIp4Config( const QString &deviceObjectPath, QObject *parent) + : QObject(parent) +{ + d = new QNetworkManagerIp4ConfigPrivate(); + d->path = deviceObjectPath; + d->connectionInterface = new QDBusInterface(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_IP4_CONFIG), + dbusConnection, parent); + if (!d->connectionInterface->isValid()) { + d->valid = false; + return; + } + d->valid = true; +} + +QNetworkManagerIp4Config::~QNetworkManagerIp4Config() +{ + delete d->connectionInterface; + delete d; +} + +bool QNetworkManagerIp4Config::isValid() +{ + return d->valid; +} + +QStringList QNetworkManagerIp4Config::domains() const +{ + return d->connectionInterface->property("Domains").toStringList(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_DBUS diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h new file mode 100644 index 0000000..f006a20 --- /dev/null +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h @@ -0,0 +1,448 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNETWORKMANAGERSERVICE_H +#define QNETWORKMANAGERSERVICE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtDBus/QtDBus> +#include <QtDBus/QDBusConnection> +#include <QtDBus/QDBusError> +#include <QtDBus/QDBusInterface> +#include <QtDBus/QDBusMessage> +#include <QtDBus/QDBusReply> + +#include <QtDBus/QDBusPendingCallWatcher> +#include <QtDBus/QDBusObjectPath> +#include <QtDBus/QDBusContext> +#include <QMap> +#include "qnmdbushelper.h" + +#ifndef QT_NO_DBUS + +#ifndef NETWORK_MANAGER_H +typedef enum NMDeviceType +{ + DEVICE_TYPE_UNKNOWN = 0, + DEVICE_TYPE_802_3_ETHERNET, + DEVICE_TYPE_802_11_WIRELESS, + DEVICE_TYPE_GSM, + DEVICE_TYPE_CDMA +} NMDeviceType; + +typedef enum +{ + NM_DEVICE_STATE_UNKNOWN = 0, + NM_DEVICE_STATE_UNMANAGED, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_PREPARE, + NM_DEVICE_STATE_CONFIG, + NM_DEVICE_STATE_NEED_AUTH, + NM_DEVICE_STATE_IP_CONFIG, + NM_DEVICE_STATE_ACTIVATED, + NM_DEVICE_STATE_FAILED +} NMDeviceState; + +typedef enum +{ + NM_ACTIVE_CONNECTION_STATE_UNKNOWN = 0, + NM_ACTIVE_CONNECTION_STATE_ACTIVATING, + NM_ACTIVE_CONNECTION_STATE_ACTIVATED +} NMActiveConnectionState; + +#define NM_DBUS_SERVICE "org.freedesktop.NetworkManager" + +#define NM_DBUS_PATH "/org/freedesktop/NetworkManager" +#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager" +#define NM_DBUS_INTERFACE_DEVICE NM_DBUS_INTERFACE ".Device" +#define NM_DBUS_INTERFACE_DEVICE_WIRED NM_DBUS_INTERFACE_DEVICE ".Wired" +#define NM_DBUS_INTERFACE_DEVICE_WIRELESS NM_DBUS_INTERFACE_DEVICE ".Wireless" +#define NM_DBUS_PATH_ACCESS_POINT NM_DBUS_PATH "/AccessPoint" +#define NM_DBUS_INTERFACE_ACCESS_POINT NM_DBUS_INTERFACE ".AccessPoint" + +#define NM_DBUS_PATH_SETTINGS "/org/freedesktop/NetworkManagerSettings" + +#define NM_DBUS_IFACE_SETTINGS_CONNECTION "org.freedesktop.NetworkManagerSettings.Connection" +#define NM_DBUS_IFACE_SETTINGS "org.freedesktop.NetworkManagerSettings" +#define NM_DBUS_INTERFACE_ACTIVE_CONNECTION NM_DBUS_INTERFACE ".Connection.Active" +#define NM_DBUS_INTERFACE_IP4_CONFIG NM_DBUS_INTERFACE ".IP4Config" + +#define NM_DBUS_SERVICE_USER_SETTINGS "org.freedesktop.NetworkManagerUserSettings" +#define NM_DBUS_SERVICE_SYSTEM_SETTINGS "org.freedesktop.NetworkManagerSystemSettings" + +#define NM_802_11_AP_FLAGS_NONE 0x00000000 +#define NM_802_11_AP_FLAGS_PRIVACY 0x00000001 +#endif + +QT_BEGIN_NAMESPACE + +typedef QMap< QString, QMap<QString,QVariant> > QNmSettingsMap; +typedef QList<quint32> ServerThing; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QNmSettingsMap)) +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(ServerThing)) + +QT_BEGIN_NAMESPACE + +class QNetworkManagerInterfacePrivate; +class QNetworkManagerInterface : public QObject +{ + Q_OBJECT + +public: + + QNetworkManagerInterface(QObject *parent = 0); + ~QNetworkManagerInterface(); + + QList <QDBusObjectPath> getDevices() const; + void activateConnection(const QString &serviceName, QDBusObjectPath connection, QDBusObjectPath device, QDBusObjectPath specificObject); + void deactivateConnection(QDBusObjectPath connectionPath) const; + + QDBusObjectPath path() const; + QDBusInterface *connectionInterface() const; + + bool wirelessEnabled() const; + bool wirelessHardwareEnabled() const; + QList <QDBusObjectPath> activeConnections() const; + quint32 state(); + bool setConnections(); + bool isValid(); + +Q_SIGNALS: + void deviceAdded(QDBusObjectPath); + void deviceRemoved(QDBusObjectPath); + void propertiesChanged( const QString &, QMap<QString,QVariant>); + void stateChanged(const QString&, quint32); + void activationFinished(QDBusPendingCallWatcher*); + +private Q_SLOTS: +private: + QNetworkManagerInterfacePrivate *d; + QNmDBusHelper *nmDBusHelper; +}; + +class QNetworkManagerInterfaceAccessPointPrivate; +class QNetworkManagerInterfaceAccessPoint : public QObject +{ + Q_OBJECT + +public: + + enum DeviceState { + Unknown = 0, + Unmanaged, + Unavailable, + Disconnected, + Prepare, + Config, + NeedAuthentication, + IpConfig, + Activated, + Failed + }; + + enum ApFlag { + ApNone = 0x0, + Privacy = 0x1 + }; + + Q_DECLARE_FLAGS(ApFlags, ApFlag); + + enum ApSecurityFlag { + ApSecurityNone = 0x0, + PairWep40 = 0x1, + PairWep104 = 0x2, + PairTkip = 0x4, + PairCcmp = 0x8, + GroupWep40 = 0x10, + GroupWep104 = 0x20, + GroupTkip = 0x40, + GroupCcmp = 0x80, + KeyPsk = 0x100, + Key8021x = 0x200 + }; + + Q_DECLARE_FLAGS(ApSecurityFlags, ApSecurityFlag); + + explicit QNetworkManagerInterfaceAccessPoint(const QString &dbusPathName, QObject *parent = 0); + ~QNetworkManagerInterfaceAccessPoint(); + + QDBusInterface *connectionInterface() const; + + quint32 flags() const; + quint32 wpaFlags() const; + quint32 rsnFlags() const; + QString ssid() const; + quint32 frequency() const; + QString hwAddress() const; + quint32 mode() const; + quint32 maxBitrate() const; + quint32 strength() const; + bool setConnections(); + bool isValid(); + +Q_SIGNALS: + void propertiesChanged(QMap <QString,QVariant>); + void propertiesChanged( const QString &, QMap<QString,QVariant>); +private: + QNetworkManagerInterfaceAccessPointPrivate *d; + QNmDBusHelper *nmDBusHelper; + +}; + +class QNetworkManagerInterfaceDevicePrivate; +class QNetworkManagerInterfaceDevice : public QObject +{ + Q_OBJECT + +public: + + explicit QNetworkManagerInterfaceDevice(const QString &deviceObjectPath, QObject *parent = 0); + ~QNetworkManagerInterfaceDevice(); + + QString udi() const; + QString networkInterface() const; + QDBusInterface *connectionInterface() const; + quint32 ip4Address() const; + quint32 state() const; + quint32 deviceType() const; + + QDBusObjectPath ip4config() const; + bool setConnections(); + bool isValid(); + +Q_SIGNALS: + void stateChanged(const QString &, quint32); + +private: + QNetworkManagerInterfaceDevicePrivate *d; + QNmDBusHelper *nmDBusHelper; +}; + +class QNetworkManagerInterfaceDeviceWiredPrivate; +class QNetworkManagerInterfaceDeviceWired : public QObject +{ + Q_OBJECT + +public: + + explicit QNetworkManagerInterfaceDeviceWired(const QString &ifaceDevicePath, + QObject *parent = 0); + ~QNetworkManagerInterfaceDeviceWired(); + + QDBusInterface *connectionInterface() const; + QString hwAddress() const; + quint32 speed() const; + bool carrier() const; + bool setConnections(); + bool isValid(); + +Q_SIGNALS: + void propertiesChanged( const QString &, QMap<QString,QVariant>); +private: + QNetworkManagerInterfaceDeviceWiredPrivate *d; + QNmDBusHelper *nmDBusHelper; +}; + +class QNetworkManagerInterfaceDeviceWirelessPrivate; +class QNetworkManagerInterfaceDeviceWireless : public QObject +{ + Q_OBJECT + +public: + + enum DeviceCapability { + None = 0x0, + Wep40 = 0x1, + Wep104 = 0x2, + Tkip = 0x4, + Ccmp = 0x8, + Wpa = 0x10, + Rsn = 0x20 + }; + + explicit QNetworkManagerInterfaceDeviceWireless(const QString &ifaceDevicePath, + QObject *parent = 0); + ~QNetworkManagerInterfaceDeviceWireless(); + + QDBusObjectPath path() const; + QList <QDBusObjectPath> getAccessPoints(); + QDBusInterface *connectionInterface() const; + + QString hwAddress() const; + quint32 mode() const; + quint32 bitrate() const; + QDBusObjectPath activeAccessPoint() const; + quint32 wirelessCapabilities() const; + bool setConnections(); + bool isValid(); + +Q_SIGNALS: + void propertiesChanged( const QString &, QMap<QString,QVariant>); + void accessPointAdded(const QString &,QDBusObjectPath); + void accessPointRemoved(const QString &,QDBusObjectPath); +private: + QNetworkManagerInterfaceDeviceWirelessPrivate *d; + QNmDBusHelper *nmDBusHelper; +}; + +class QNetworkManagerSettingsPrivate; +class QNetworkManagerSettings : public QObject +{ + Q_OBJECT + +public: + + explicit QNetworkManagerSettings(const QString &settingsService, QObject *parent = 0); + ~QNetworkManagerSettings(); + + QDBusInterface *connectionInterface() const; + QList <QDBusObjectPath> listConnections(); + bool setConnections(); + bool isValid(); + +Q_SIGNALS: + void newConnection(QDBusObjectPath); +private: + QNetworkManagerSettingsPrivate *d; +}; + +class QNetworkManagerSettingsConnectionPrivate; +class QNetworkManagerSettingsConnection : public QObject +{ + Q_OBJECT + +public: + + QNetworkManagerSettingsConnection(const QString &settingsService, const QString &connectionObjectPath, QObject *parent = 0); + ~QNetworkManagerSettingsConnection(); + + QDBusInterface *connectionInterface() const; + QNmSettingsMap getSettings(); + bool setConnections(); + NMDeviceType getType(); + bool isAutoConnect(); + quint64 getTimestamp(); + QString getId(); + QString getUuid(); + QString getSsid(); + QString getMacAddress(); + QStringList getSeenBssids(); + bool isValid(); + +Q_SIGNALS: + + void updated(const QNmSettingsMap &settings); + void removed(const QString &path); + +private: + QNmDBusHelper *nmDBusHelper; + QNetworkManagerSettingsConnectionPrivate *d; +}; + +class QNetworkManagerConnectionActivePrivate; +class QNetworkManagerConnectionActive : public QObject +{ + Q_OBJECT + +public: + + enum ActiveConnectionState { + Unknown = 0, + Activating = 1, + Activated = 2 + }; + + explicit QNetworkManagerConnectionActive(const QString &dbusPathName, QObject *parent = 0); + ~ QNetworkManagerConnectionActive(); + + QDBusInterface *connectionInterface() const; + QString serviceName() const; + QDBusObjectPath connection() const; + QDBusObjectPath specificObject() const; + QList<QDBusObjectPath> devices() const; + quint32 state() const; + bool defaultRoute() const; + bool setConnections(); + bool isValid(); + + +Q_SIGNALS: + void propertiesChanged(QList<QDBusObjectPath>); + void propertiesChanged( const QString &, QMap<QString,QVariant>); +private: + QNetworkManagerConnectionActivePrivate *d; + QNmDBusHelper *nmDBusHelper; +}; + +class QNetworkManagerIp4ConfigPrivate; +class QNetworkManagerIp4Config : public QObject +{ + Q_OBJECT + +public: + explicit QNetworkManagerIp4Config(const QString &dbusPathName, QObject *parent = 0); + ~QNetworkManagerIp4Config(); + + QStringList domains() const; + bool isValid(); + + private: + QNetworkManagerIp4ConfigPrivate *d; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_DBUS +#endif //QNETWORKMANAGERSERVICE_H diff --git a/src/plugins/bearer/networkmanager/qnmdbushelper.cpp b/src/plugins/bearer/networkmanager/qnmdbushelper.cpp new file mode 100644 index 0000000..68dde6e --- /dev/null +++ b/src/plugins/bearer/networkmanager/qnmdbushelper.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// this class is for helping qdbus get stuff + +#include "qnmdbushelper.h" + +#include "qnetworkmanagerservice.h" + +#include <QDBusError> +#include <QDBusInterface> +#include <QDBusMessage> +#include <QDBusReply> + +#include <QDebug> + +#ifndef QT_NO_DBUS + +QT_BEGIN_NAMESPACE + +QNmDBusHelper::QNmDBusHelper(QObject * parent) + : QObject(parent) +{ +} + +QNmDBusHelper::~QNmDBusHelper() +{ +} + +void QNmDBusHelper::deviceStateChanged(quint32 state) + { + QDBusMessage msg = this->message(); + if(state == NM_DEVICE_STATE_ACTIVATED + || state == NM_DEVICE_STATE_DISCONNECTED + || state == NM_DEVICE_STATE_UNAVAILABLE + || state == NM_DEVICE_STATE_FAILED) { + emit pathForStateChanged(msg.path(), state); + } + } + +void QNmDBusHelper::slotAccessPointAdded(QDBusObjectPath path) +{ + if(path.path().length() > 2) { + QDBusMessage msg = this->message(); + emit pathForAccessPointAdded(msg.path(), path); + } +} + +void QNmDBusHelper::slotAccessPointRemoved(QDBusObjectPath path) +{ + if(path.path().length() > 2) { + QDBusMessage msg = this->message(); + emit pathForAccessPointRemoved(msg.path(), path); + } +} + +void QNmDBusHelper::slotPropertiesChanged(QMap<QString,QVariant> map) +{ + QDBusMessage msg = this->message(); + QMapIterator<QString, QVariant> i(map); + while (i.hasNext()) { + i.next(); + if( i.key() == "State") { //state only applies to device interfaces + quint32 state = i.value().toUInt(); + if( state == NM_DEVICE_STATE_ACTIVATED + || state == NM_DEVICE_STATE_DISCONNECTED + || state == NM_DEVICE_STATE_UNAVAILABLE + || state == NM_DEVICE_STATE_FAILED) { + emit pathForPropertiesChanged( msg.path(), map); + } + } else if( i.key() == "ActiveAccessPoint") { + emit pathForPropertiesChanged(msg.path(), map); + // qWarning() << __PRETTY_FUNCTION__ << i.key() << ": " << i.value().value<QDBusObjectPath>().path(); + // } else if( i.key() == "Strength") + // qWarning() << __PRETTY_FUNCTION__ << i.key() << ": " << i.value().toUInt(); + // else + // qWarning() << __PRETTY_FUNCTION__ << i.key() << ": " << i.value(); + } else if (i.key() == "ActiveConnections") { + emit pathForPropertiesChanged(msg.path(), map); + } + } +} + +void QNmDBusHelper::slotSettingsRemoved() +{ + QDBusMessage msg = this->message(); + emit pathForSettingsRemoved(msg.path()); +} + +QT_END_NAMESPACE + +#endif // QT_NO_DBUS diff --git a/src/plugins/bearer/networkmanager/qnmdbushelper.h b/src/plugins/bearer/networkmanager/qnmdbushelper.h new file mode 100644 index 0000000..7a9563d --- /dev/null +++ b/src/plugins/bearer/networkmanager/qnmdbushelper.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNMDBUSHELPERPRIVATE_H +#define QNMDBUSHELPERPRIVATE_H + +#include <QDBusObjectPath> +#include <QDBusContext> +#include <QMap> + +#ifndef QT_NO_DBUS + +QT_BEGIN_NAMESPACE + +class QNmDBusHelper: public QObject, protected QDBusContext + { + Q_OBJECT + public: + QNmDBusHelper(QObject *parent = 0); + ~QNmDBusHelper(); + + public slots: + void deviceStateChanged(quint32); + void slotAccessPointAdded( QDBusObjectPath ); + void slotAccessPointRemoved( QDBusObjectPath ); + void slotPropertiesChanged( QMap<QString,QVariant>); + void slotSettingsRemoved(); + +Q_SIGNALS: + void pathForStateChanged(const QString &, quint32); + void pathForAccessPointAdded(const QString &, QDBusObjectPath ); + void pathForAccessPointRemoved(const QString &, QDBusObjectPath ); + void pathForPropertiesChanged(const QString &, QMap<QString,QVariant>); + void pathForSettingsRemoved(const QString &); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_DBUS + +#endif// QNMDBUSHELPERPRIVATE_H diff --git a/src/plugins/imageformats/tiff/qtiffhandler.h b/src/plugins/bearer/nla/main.cpp index 4534ed5..479a933 100644 --- a/src/plugins/imageformats/tiff/qtiffhandler.h +++ b/src/plugins/bearer/nla/main.cpp @@ -39,40 +39,46 @@ ** ****************************************************************************/ -#ifndef QTIFFHANDLER_H -#define QTIFFHANDLER_H +#include "qnlaengine.h" -#include <QtGui/qimageiohandler.h> +#include <QtNetwork/private/qbearerplugin_p.h> + +#include <QtCore/qdebug.h> QT_BEGIN_NAMESPACE -class QTiffHandler : public QImageIOHandler +class QNlaEnginePlugin : public QBearerEnginePlugin { public: - QTiffHandler(); + QNlaEnginePlugin(); + ~QNlaEnginePlugin(); - bool canRead() const; - bool read(QImage *image); - bool write(const QImage &image); + QStringList keys() const; + QBearerEngine *create(const QString &key) const; +}; - QByteArray name() const; +QNlaEnginePlugin::QNlaEnginePlugin() +{ +} - static bool canRead(QIODevice *device); +QNlaEnginePlugin::~QNlaEnginePlugin() +{ +} - QVariant option(ImageOption option) const; - void setOption(ImageOption option, const QVariant &value); - bool supportsOption(ImageOption option) const; +QStringList QNlaEnginePlugin::keys() const +{ + return QStringList() << QLatin1String("nla"); +} - enum Compression { - NoCompression = 0, - LzwCompression = 1 - }; -private: - void convert32BitOrder(void *buffer, int width); - void convert32BitOrderBigEndian(void *buffer, int width); - int compression; -}; +QBearerEngine *QNlaEnginePlugin::create(const QString &key) const +{ + if (key == QLatin1String("nla")) + return new QNlaEngine; + else + return 0; +} -QT_END_NAMESPACE +Q_EXPORT_STATIC_PLUGIN(QNlaEnginePlugin) +Q_EXPORT_PLUGIN2(qnlabearer, QNlaEnginePlugin) -#endif // QTIFFHANDLER_H +QT_END_NAMESPACE diff --git a/src/plugins/bearer/nla/nla.pro b/src/plugins/bearer/nla/nla.pro new file mode 100644 index 0000000..5dfb6d7 --- /dev/null +++ b/src/plugins/bearer/nla/nla.pro @@ -0,0 +1,23 @@ +TARGET = qnlabearer +include(../../qpluginbase.pri) + +QT = core network + +!wince* { + LIBS += -lWs2_32 +} else { + LIBS += -lWs2 +} + +HEADERS += qnlaengine.h \ + ../platformdefs_win.h \ + ../qnetworksession_impl.h \ + ../qbearerengine_impl.h + +SOURCES += main.cpp \ + qnlaengine.cpp \ + ../qnetworksession_impl.cpp + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/bearer +target.path += $$[QT_INSTALL_PLUGINS]/bearer +INSTALLS += target diff --git a/src/plugins/bearer/nla/qnlaengine.cpp b/src/plugins/bearer/nla/qnlaengine.cpp new file mode 100644 index 0000000..fd50099 --- /dev/null +++ b/src/plugins/bearer/nla/qnlaengine.cpp @@ -0,0 +1,650 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnlaengine.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 "../platformdefs_win.h" + +QT_BEGIN_NAMESPACE + +QWindowsSockInit2::QWindowsSockInit2() +: version(0) +{ + //### should we try for 2.2 on all platforms ?? + WSAData wsadata; + + // IPv6 requires Winsock v2.0 or better. + if (WSAStartup(MAKEWORD(2,0), &wsadata) != 0) { + qWarning("QBearerManagementAPI: WinSock v2.0 initialization failed."); + } else { + version = 0x20; + } +} + +QWindowsSockInit2::~QWindowsSockInit2() +{ + WSACleanup(); +} + +#ifdef BEARER_MANAGEMENT_DEBUG +static void printBlob(NLA_BLOB *blob) +{ + qDebug() << "==== BEGIN NLA_BLOB ===="; + + qDebug() << "type:" << blob->header.type; + qDebug() << "size:" << blob->header.dwSize; + qDebug() << "next offset:" << blob->header.nextOffset; + + switch (blob->header.type) { + case NLA_RAW_DATA: + qDebug() << "Raw Data"; + qDebug() << '\t' << blob->data.rawData; + break; + case NLA_INTERFACE: + qDebug() << "Interface"; + qDebug() << "\ttype:" << blob->data.interfaceData.dwType; + qDebug() << "\tspeed:" << blob->data.interfaceData.dwSpeed; + qDebug() << "\tadapter:" << blob->data.interfaceData.adapterName; + break; + case NLA_802_1X_LOCATION: + qDebug() << "802.1x Location"; + qDebug() << '\t' << blob->data.locationData.information; + break; + case NLA_CONNECTIVITY: + qDebug() << "Connectivity"; + qDebug() << "\ttype:" << blob->data.connectivity.type; + qDebug() << "\tinternet:" << blob->data.connectivity.internet; + break; + case NLA_ICS: + qDebug() << "ICS"; + qDebug() << "\tspeed:" << blob->data.ICS.remote.speed; + qDebug() << "\ttype:" << blob->data.ICS.remote.type; + qDebug() << "\tstate:" << blob->data.ICS.remote.state; + qDebug() << "\tmachine name:" << blob->data.ICS.remote.machineName; + qDebug() << "\tshared adapter name:" << blob->data.ICS.remote.sharedAdapterName; + break; + default: + qDebug() << "UNKNOWN BLOB TYPE"; + } + + qDebug() << "===== END NLA_BLOB ====="; +} +#endif + +static QNetworkConfiguration::BearerType qGetInterfaceType(const QString &interface) +{ +#ifdef Q_OS_WINCE + Q_UNUSED(interface) +#else + unsigned long oid; + DWORD bytesWritten; + + NDIS_MEDIUM medium; + NDIS_PHYSICAL_MEDIUM physicalMedium; + + HANDLE handle = CreateFile((TCHAR *)QString::fromLatin1("\\\\.\\%1").arg(interface).utf16(), 0, + FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if (handle == INVALID_HANDLE_VALUE) + return QNetworkConfiguration::BearerUnknown; + + oid = OID_GEN_MEDIA_SUPPORTED; + bytesWritten = 0; + bool result = DeviceIoControl(handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof(oid), + &medium, sizeof(medium), &bytesWritten, 0); + if (!result) { + CloseHandle(handle); + return QNetworkConfiguration::BearerUnknown; + } + + oid = OID_GEN_PHYSICAL_MEDIUM; + bytesWritten = 0; + result = DeviceIoControl(handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof(oid), + &physicalMedium, sizeof(physicalMedium), &bytesWritten, 0); + if (!result) { + CloseHandle(handle); + + if (medium == NdisMedium802_3) + return QNetworkConfiguration::BearerEthernet; + else + return QNetworkConfiguration::BearerUnknown; + } + + CloseHandle(handle); + + if (medium == NdisMedium802_3) { + switch (physicalMedium) { + case NdisPhysicalMediumWirelessLan: + return QNetworkConfiguration::BearerWLAN; + case NdisPhysicalMediumBluetooth: + return QNetworkConfiguration::BearerBluetooth; + case NdisPhysicalMediumWiMax: + return QNetworkConfiguration::BearerWiMAX; + default: +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "Physical Medium" << physicalMedium; +#endif + return QNetworkConfiguration::BearerEthernet; + } + } + +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << medium << physicalMedium; +#endif + +#endif + + return QNetworkConfiguration::BearerUnknown; +} + +class QNlaThread : public QThread +{ + Q_OBJECT + +public: + QNlaThread(QNlaEngine *parent = 0); + ~QNlaThread(); + + QList<QNetworkConfigurationPrivate *> getConfigurations(); + + void forceUpdate(); + +protected: + virtual void run(); + +private: + void updateConfigurations(QList<QNetworkConfigurationPrivate *> &configs); + DWORD parseBlob(NLA_BLOB *blob, QNetworkConfigurationPrivate *cpPriv) const; + QNetworkConfigurationPrivate *parseQuerySet(const WSAQUERYSET *querySet) const; + void fetchConfigurations(); + +signals: + void networksChanged(); + +private: + QMutex mutex; + HANDLE handle; + bool done; + QList<QNetworkConfigurationPrivate *> fetchedConfigurations; +}; + +QNlaThread::QNlaThread(QNlaEngine *parent) +: QThread(parent), handle(0), done(false) +{ +} + +QNlaThread::~QNlaThread() +{ + mutex.lock(); + + done = true; + + if (handle) { + /* cancel completion event */ + if (WSALookupServiceEnd(handle) == SOCKET_ERROR) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("WSALookupServiceEnd error %d", WSAGetLastError()); +#endif + } + } + mutex.unlock(); + + wait(); +} + +QList<QNetworkConfigurationPrivate *> QNlaThread::getConfigurations() +{ + QMutexLocker locker(&mutex); + + QList<QNetworkConfigurationPrivate *> foundConfigurations = fetchedConfigurations; + fetchedConfigurations.clear(); + + return foundConfigurations; +} + +void QNlaThread::forceUpdate() +{ + mutex.lock(); + + if (handle) { + /* cancel completion event */ + if (WSALookupServiceEnd(handle) == SOCKET_ERROR) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("WSALookupServiceEnd error %d", WSAGetLastError()); +#endif + } + handle = 0; + } + mutex.unlock(); +} + +void QNlaThread::run() +{ + WSAEVENT changeEvent = WSACreateEvent(); + if (changeEvent == WSA_INVALID_EVENT) + return; + + while (true) { + fetchConfigurations(); + + WSAQUERYSET qsRestrictions; + + memset(&qsRestrictions, 0, sizeof(qsRestrictions)); + qsRestrictions.dwSize = sizeof(qsRestrictions); + qsRestrictions.dwNameSpace = NS_NLA; + + mutex.lock(); + if (done) { + mutex.unlock(); + break; + } + int result = WSALookupServiceBegin(&qsRestrictions, LUP_RETURN_ALL, &handle); + mutex.unlock(); + + if (result == SOCKET_ERROR) + break; + + WSACOMPLETION completion; + WSAOVERLAPPED overlapped; + + memset(&overlapped, 0, sizeof(overlapped)); + overlapped.hEvent = changeEvent; + + memset(&completion, 0, sizeof(completion)); + completion.Type = NSP_NOTIFY_EVENT; + completion.Parameters.Event.lpOverlapped = &overlapped; + + DWORD bytesReturned = 0; + result = WSANSPIoctl(handle, SIO_NSP_NOTIFY_CHANGE, 0, 0, 0, 0, + &bytesReturned, &completion); + if (result == SOCKET_ERROR) { + if (WSAGetLastError() != WSA_IO_PENDING) + break; + } + +#ifndef Q_OS_WINCE + // Not interested in unrelated IO completion events + // although we also don't want to block them + while (WaitForSingleObjectEx(changeEvent, WSA_INFINITE, true) != WAIT_IO_COMPLETION && + handle) + { + } +#else + WaitForSingleObject(changeEvent, WSA_INFINITE); +#endif + + mutex.lock(); + if (handle) { + result = WSALookupServiceEnd(handle); + if (result == SOCKET_ERROR) { + mutex.unlock(); + break; + } + handle = 0; + } + mutex.unlock(); + } + + WSACloseEvent(changeEvent); +} + +void QNlaThread::updateConfigurations(QList<QNetworkConfigurationPrivate *> &configs) +{ + mutex.lock(); + + while (!fetchedConfigurations.isEmpty()) + delete fetchedConfigurations.takeFirst(); + + fetchedConfigurations = configs; + + mutex.unlock(); + + emit networksChanged(); +} + +DWORD QNlaThread::parseBlob(NLA_BLOB *blob, QNetworkConfigurationPrivate *cpPriv) const +{ +#ifdef BEARER_MANAGEMENT_DEBUG + printBlob(blob); +#endif + + switch (blob->header.type) { + case NLA_RAW_DATA: +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: unhandled header type NLA_RAW_DATA", __FUNCTION__); +#endif + break; + case NLA_INTERFACE: + cpPriv->state = QNetworkConfiguration::Active; + if (QNlaEngine *engine = qobject_cast<QNlaEngine *>(parent())) { + engine->configurationInterface[cpPriv->id.toUInt()] = + QString::fromLatin1(blob->data.interfaceData.adapterName); + } + break; + case NLA_802_1X_LOCATION: +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: unhandled header type NLA_802_1X_LOCATION", __FUNCTION__); +#endif + break; + case NLA_CONNECTIVITY: +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: unhandled header type NLA_CONNECTIVITY", __FUNCTION__); +#endif + break; + case NLA_ICS: +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: unhandled header type NLA_ICS", __FUNCTION__); +#endif + break; + default: +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("%s: unhandled header type %d", __FUNCTION__, blob->header.type); +#endif + ; + } + + return blob->header.nextOffset; +} + +QNetworkConfigurationPrivate *QNlaThread::parseQuerySet(const WSAQUERYSET *querySet) const +{ + QNetworkConfigurationPrivate *cpPriv = new QNetworkConfigurationPrivate; + + cpPriv->name = QString::fromWCharArray(querySet->lpszServiceInstanceName); + cpPriv->isValid = true; + cpPriv->id = QString::number(qHash(QLatin1String("NLA:") + cpPriv->name)); + cpPriv->state = QNetworkConfiguration::Defined; + cpPriv->type = QNetworkConfiguration::InternetAccessPoint; + +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "size:" << querySet->dwSize; + qDebug() << "service instance name:" << QString::fromUtf16(querySet->lpszServiceInstanceName); + qDebug() << "service class id:" << querySet->lpServiceClassId; + qDebug() << "version:" << querySet->lpVersion; + qDebug() << "comment:" << QString::fromUtf16(querySet->lpszComment); + qDebug() << "namespace:" << querySet->dwNameSpace; + qDebug() << "namespace provider id:" << querySet->lpNSProviderId; + qDebug() << "context:" << QString::fromUtf16(querySet->lpszContext); + qDebug() << "number of protocols:" << querySet->dwNumberOfProtocols; + qDebug() << "protocols:" << querySet->lpafpProtocols; + qDebug() << "query string:" << QString::fromUtf16(querySet->lpszQueryString); + qDebug() << "number of cs addresses:" << querySet->dwNumberOfCsAddrs; + qDebug() << "cs addresses:" << querySet->lpcsaBuffer; + qDebug() << "output flags:" << querySet->dwOutputFlags; +#endif + + if (querySet->lpBlob) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "blob size:" << querySet->lpBlob->cbSize; + qDebug() << "blob data:" << querySet->lpBlob->pBlobData; +#endif + + DWORD offset = 0; + do { + NLA_BLOB *blob = reinterpret_cast<NLA_BLOB *>(querySet->lpBlob->pBlobData + offset); + DWORD nextOffset = parseBlob(blob, cpPriv); + if (nextOffset == offset) + break; + else + offset = nextOffset; + } while (offset != 0 && offset < querySet->lpBlob->cbSize); + } + + if (QNlaEngine *engine = qobject_cast<QNlaEngine *>(parent())) { + const QString interface = engine->getInterfaceFromId(cpPriv->id); + cpPriv->bearerType = qGetInterfaceType(interface); + } + + return cpPriv; +} + +void QNlaThread::fetchConfigurations() +{ + QList<QNetworkConfigurationPrivate *> foundConfigurations; + + WSAQUERYSET qsRestrictions; + HANDLE hLookup = 0; + + memset(&qsRestrictions, 0, sizeof(qsRestrictions)); + qsRestrictions.dwSize = sizeof(qsRestrictions); + qsRestrictions.dwNameSpace = NS_NLA; + + int result = WSALookupServiceBegin(&qsRestrictions, LUP_RETURN_ALL | LUP_DEEP, &hLookup); + if (result == SOCKET_ERROR) { + mutex.lock(); + fetchedConfigurations.clear(); + mutex.unlock(); + } + + char buffer[0x10000]; + while (result == 0) { + DWORD bufferLength = sizeof(buffer); + result = WSALookupServiceNext(hLookup, LUP_RETURN_ALL, + &bufferLength, reinterpret_cast<WSAQUERYSET *>(buffer)); + + if (result == SOCKET_ERROR) + break; + + QNetworkConfigurationPrivate *cpPriv = + parseQuerySet(reinterpret_cast<WSAQUERYSET *>(buffer)); + + foundConfigurations.append(cpPriv); + } + + if (hLookup) { + result = WSALookupServiceEnd(hLookup); + if (result == SOCKET_ERROR) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("WSALookupServiceEnd error %d", WSAGetLastError()); +#endif + } + } + + updateConfigurations(foundConfigurations); +} + +QNlaEngine::QNlaEngine(QObject *parent) +: QBearerEngineImpl(parent), nlaThread(0) +{ + nlaThread = new QNlaThread(this); + connect(nlaThread, SIGNAL(networksChanged()), + this, SLOT(networksChanged())); + nlaThread->start(); + + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); +} + +QNlaEngine::~QNlaEngine() +{ + delete nlaThread; +} + +void QNlaEngine::networksChanged() +{ + QMutexLocker locker(&mutex); + + QStringList previous = accessPointConfigurations.keys(); + + QList<QNetworkConfigurationPrivate *> foundConfigurations = nlaThread->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->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(); +} + +QString QNlaEngine::getInterfaceFromId(const QString &id) +{ + QMutexLocker locker(&mutex); + + return configurationInterface.value(id.toUInt()); +} + +bool QNlaEngine::hasIdentifier(const QString &id) +{ + QMutexLocker locker(&mutex); + + return configurationInterface.contains(id.toUInt()); +} + +void QNlaEngine::connectToId(const QString &id) +{ + emit connectionError(id, OperationNotSupported); +} + +void QNlaEngine::disconnectFromId(const QString &id) +{ + emit connectionError(id, OperationNotSupported); +} + +void QNlaEngine::requestUpdate() +{ + QMutexLocker locker(&mutex); + + nlaThread->forceUpdate(); +} + +QNetworkSession::State QNlaEngine::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 QNlaEngine::capabilities() const +{ + return QNetworkConfigurationManager::ForcedRoaming; +} + +QNetworkSessionPrivate *QNlaEngine::createSessionBackend() +{ + return new QNetworkSessionPrivateImpl; +} + +QNetworkConfigurationPrivatePointer QNlaEngine::defaultConfiguration() +{ + return QNetworkConfigurationPrivatePointer(); +} + +#include "qnlaengine.moc" +QT_END_NAMESPACE + diff --git a/src/plugins/bearer/nla/qnlaengine.h b/src/plugins/bearer/nla/qnlaengine.h new file mode 100644 index 0000000..69f54c9 --- /dev/null +++ b/src/plugins/bearer/nla/qnlaengine.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNLAENGINE_P_H +#define QNLAENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "../qbearerengine_impl.h" + +#include <QtNetwork/private/qnativesocketengine_p.h> + +#include <QMap> + +QT_BEGIN_NAMESPACE + +class QNetworkConfigurationPrivate; +class QNlaThread; + +class QWindowsSockInit2 +{ +public: + QWindowsSockInit2(); + ~QWindowsSockInit2(); + int version; +}; + +class QNlaEngine : public QBearerEngineImpl +{ + Q_OBJECT + + friend class QNlaThread; + +public: + QNlaEngine(QObject *parent = 0); + ~QNlaEngine(); + + QString getInterfaceFromId(const QString &id); + bool hasIdentifier(const QString &id); + + void connectToId(const QString &id); + void disconnectFromId(const QString &id); + + Q_INVOKABLE void requestUpdate(); + + QNetworkSession::State sessionStateForId(const QString &id); + + QNetworkConfigurationManager::Capabilities capabilities() const; + + QNetworkSessionPrivate *createSessionBackend(); + + QNetworkConfigurationPrivatePointer defaultConfiguration(); + +private Q_SLOTS: + void networksChanged(); + +private: + QWindowsSockInit2 winSock; + QNlaThread *nlaThread; + QMap<uint, QString> configurationInterface; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/bearer/platformdefs_win.h b/src/plugins/bearer/platformdefs_win.h new file mode 100644 index 0000000..1a10ba7 --- /dev/null +++ b/src/plugins/bearer/platformdefs_win.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPLATFORMDEFS_WIN_H +#define QPLATFORMDEFS_WIN_H + +#include <winsock2.h> +#include <mswsock.h> +#undef interface +#include <winioctl.h> + +QT_BEGIN_NAMESPACE + +#ifndef NS_NLA + +#define NS_NLA 15 + +enum NLA_BLOB_DATA_TYPE { + NLA_RAW_DATA = 0, + NLA_INTERFACE = 1, + NLA_802_1X_LOCATION = 2, + NLA_CONNECTIVITY = 3, + NLA_ICS = 4 +}; + +enum NLA_CONNECTIVITY_TYPE { + NLA_NETWORK_AD_HOC = 0, + NLA_NETWORK_MANAGED = 1, + NLA_NETWORK_UNMANAGED = 2, + NLA_NETWORK_UNKNOWN = 3 +}; + +enum NLA_INTERNET { + NLA_INTERNET_UNKNOWN = 0, + NLA_INTERNET_NO = 1, + NLA_INTERNET_YES = 2 +}; + +struct NLA_BLOB { + struct { + NLA_BLOB_DATA_TYPE type; + DWORD dwSize; + DWORD nextOffset; + } header; + + union { + // NLA_RAW_DATA + CHAR rawData[1]; + + // NLA_INTERFACE + struct { + DWORD dwType; + DWORD dwSpeed; + CHAR adapterName[1]; + } interfaceData; + + // NLA_802_1X_LOCATION + struct { + CHAR information[1]; + } locationData; + + // NLA_CONNECTIVITY + struct { + NLA_CONNECTIVITY_TYPE type; + NLA_INTERNET internet; + } connectivity; + + // NLA_ICS + struct { + struct { + DWORD speed; + DWORD type; + DWORD state; + WCHAR machineName[256]; + WCHAR sharedAdapterName[256]; + } remote; + } ICS; + } data; +}; +#endif + +enum NDIS_MEDIUM { + NdisMedium802_3 = 0, +}; + +enum NDIS_PHYSICAL_MEDIUM { + NdisPhysicalMediumWirelessLan = 1, + NdisPhysicalMediumBluetooth = 10, + NdisPhysicalMediumWiMax = 12, +}; + +#define OID_GEN_MEDIA_SUPPORTED 0x00010103 +#define OID_GEN_PHYSICAL_MEDIUM 0x00010202 + +#define IOCTL_NDIS_QUERY_GLOBAL_STATS \ + CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD, 0, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/bearer/qbearerengine_impl.h b/src/plugins/bearer/qbearerengine_impl.h new file mode 100644 index 0000000..6c30d0f --- /dev/null +++ b/src/plugins/bearer/qbearerengine_impl.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBEARERENGINE_IMPL_H +#define QBEARERENGINE_IMPL_H + +#include <QtNetwork/private/qbearerengine_p.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +class QBearerEngineImpl : public QBearerEngine +{ + Q_OBJECT + +public: + enum ConnectionError { + InterfaceLookupError = 0, + ConnectError, + OperationNotSupported, + DisconnectionError, + }; + + QBearerEngineImpl(QObject *parent = 0) : QBearerEngine(parent) { } + ~QBearerEngineImpl() { } + + virtual void connectToId(const QString &id) = 0; + virtual void disconnectFromId(const QString &id) = 0; + + virtual QString getInterfaceFromId(const QString &id) = 0; + + virtual QNetworkSession::State sessionStateForId(const QString &id) = 0; + + virtual quint64 bytesWritten(const QString &) { return Q_UINT64_C(0); } + virtual quint64 bytesReceived(const QString &) { return Q_UINT64_C(0); } + virtual quint64 startTime(const QString &) { return Q_UINT64_C(0); } + +Q_SIGNALS: + void connectionError(const QString &id, QBearerEngineImpl::ConnectionError error); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT +#endif diff --git a/src/plugins/bearer/qnetworksession_impl.cpp b/src/plugins/bearer/qnetworksession_impl.cpp new file mode 100644 index 0000000..ef5f347 --- /dev/null +++ b/src/plugins/bearer/qnetworksession_impl.cpp @@ -0,0 +1,446 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnetworksession_impl.h" +#include "qbearerengine_impl.h" + +#include <QtNetwork/qnetworksession.h> +#include <QtNetwork/private/qnetworkconfigmanager_p.h> + +#include <QtCore/qstringlist.h> +#include <QtCore/qdebug.h> +#include <QtCore/qmutex.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +static QBearerEngineImpl *getEngineFromId(const QString &id) +{ + QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate(); + + foreach (QBearerEngine *engine, priv->engines()) { + QBearerEngineImpl *engineImpl = qobject_cast<QBearerEngineImpl *>(engine); + if (engineImpl && engineImpl->hasIdentifier(id)) + return engineImpl; + } + + return 0; +} + +class QNetworkSessionManagerPrivate : public QObject +{ + Q_OBJECT + +public: + QNetworkSessionManagerPrivate(QObject *parent = 0); + ~QNetworkSessionManagerPrivate(); + + void forceSessionClose(const QNetworkConfiguration &config); + +Q_SIGNALS: + void forcedSessionClose(const QNetworkConfiguration &config); +}; + +#include "qnetworksession_impl.moc" + +Q_GLOBAL_STATIC(QNetworkSessionManagerPrivate, sessionManager); + +QNetworkSessionManagerPrivate::QNetworkSessionManagerPrivate(QObject *parent) +: QObject(parent) +{ +} + +QNetworkSessionManagerPrivate::~QNetworkSessionManagerPrivate() +{ +} + +void QNetworkSessionManagerPrivate::forceSessionClose(const QNetworkConfiguration &config) +{ + emit forcedSessionClose(config); +} + +void QNetworkSessionPrivateImpl::syncStateWithInterface() +{ + connect(sessionManager(), SIGNAL(forcedSessionClose(QNetworkConfiguration)), + this, SLOT(forcedSessionClose(QNetworkConfiguration))); + + opened = false; + isOpen = false; + state = QNetworkSession::Invalid; + lastError = QNetworkSession::UnknownSessionError; + + qRegisterMetaType<QBearerEngineImpl::ConnectionError> + ("QBearerEngineImpl::ConnectionError"); + + switch (publicConfig.type()) { + case QNetworkConfiguration::InternetAccessPoint: + activeConfig = publicConfig; + engine = getEngineFromId(activeConfig.identifier()); + if (engine) { + qRegisterMetaType<QNetworkConfigurationPrivatePointer>("QNetworkConfigurationPrivatePointer"); + connect(engine, SIGNAL(configurationChanged(QNetworkConfigurationPrivatePointer)), + this, SLOT(configurationChanged(QNetworkConfigurationPrivatePointer)), + Qt::QueuedConnection); + connect(engine, SIGNAL(connectionError(QString,QBearerEngineImpl::ConnectionError)), + this, SLOT(connectionError(QString,QBearerEngineImpl::ConnectionError)), + Qt::QueuedConnection); + } + break; + case QNetworkConfiguration::ServiceNetwork: + serviceConfig = publicConfig; + // Defer setting engine and signals until open(). + // fall through + case QNetworkConfiguration::UserChoice: + // Defer setting serviceConfig and activeConfig until open(). + // fall through + default: + engine = 0; + } + + networkConfigurationsChanged(); +} + +void QNetworkSessionPrivateImpl::open() +{ + if (serviceConfig.isValid()) { + lastError = QNetworkSession::OperationNotSupportedError; + emit QNetworkSessionPrivate::error(lastError); + } else if (!isOpen) { + if ((activeConfig.state() & QNetworkConfiguration::Discovered) != + QNetworkConfiguration::Discovered) { + lastError =QNetworkSession::InvalidConfigurationError; + state = QNetworkSession::Invalid; + emit stateChanged(state); + emit QNetworkSessionPrivate::error(lastError); + return; + } + opened = true; + + if ((activeConfig.state() & QNetworkConfiguration::Active) != QNetworkConfiguration::Active && + (activeConfig.state() & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered) { + state = QNetworkSession::Connecting; + emit stateChanged(state); + + engine->connectToId(activeConfig.identifier()); + } + + isOpen = (activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active; + if (isOpen) + emit quitPendingWaitsForOpened(); + } +} + +void QNetworkSessionPrivateImpl::close() +{ + if (serviceConfig.isValid()) { + lastError = QNetworkSession::OperationNotSupportedError; + emit QNetworkSessionPrivate::error(lastError); + } else if (isOpen) { + opened = false; + isOpen = false; + emit closed(); + } +} + +void QNetworkSessionPrivateImpl::stop() +{ + if (serviceConfig.isValid()) { + lastError = QNetworkSession::OperationNotSupportedError; + emit QNetworkSessionPrivate::error(lastError); + } else { + if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + state = QNetworkSession::Closing; + emit stateChanged(state); + + engine->disconnectFromId(activeConfig.identifier()); + + sessionManager()->forceSessionClose(activeConfig); + } + + opened = false; + isOpen = false; + emit closed(); + } +} + +void QNetworkSessionPrivateImpl::migrate() +{ +} + +void QNetworkSessionPrivateImpl::accept() +{ +} + +void QNetworkSessionPrivateImpl::ignore() +{ +} + +void QNetworkSessionPrivateImpl::reject() +{ +} + +#ifndef QT_NO_NETWORKINTERFACE +QNetworkInterface QNetworkSessionPrivateImpl::currentInterface() const +{ + if (!publicConfig.isValid() || !engine || state != QNetworkSession::Connected) + return QNetworkInterface(); + + QString interface = engine->getInterfaceFromId(activeConfig.identifier()); + + if (interface.isEmpty()) + return QNetworkInterface(); + return QNetworkInterface::interfaceFromName(interface); +} +#endif + +QVariant QNetworkSessionPrivateImpl::sessionProperty(const QString &key) const +{ + if (key == QLatin1String("AutoCloseSessionTimeout")) { + if (engine && engine->requiresPolling() && + !(engine->capabilities() & QNetworkConfigurationManager::CanStartAndStopInterfaces)) { + if (sessionTimeout >= 0) + return sessionTimeout * 10000; + else + return -1; + } + } + + return QVariant(); +} + +void QNetworkSessionPrivateImpl::setSessionProperty(const QString &key, const QVariant &value) +{ + if (key == QLatin1String("AutoCloseSessionTimeout")) { + if (engine && engine->requiresPolling() && + !(engine->capabilities() & QNetworkConfigurationManager::CanStartAndStopInterfaces)) { + int timeout = value.toInt(); + if (timeout >= 0) { + connect(engine, SIGNAL(updateCompleted()), + this, SLOT(decrementTimeout()), Qt::UniqueConnection); + sessionTimeout = timeout / 10000; // convert to poll intervals + } else { + disconnect(engine, SIGNAL(updateCompleted()), this, SLOT(decrementTimeout())); + sessionTimeout = -1; + } + } + } +} + +QString QNetworkSessionPrivateImpl::errorString() const +{ + switch (lastError) { + case QNetworkSession::UnknownSessionError: + return tr("Unknown session error."); + case QNetworkSession::SessionAbortedError: + return tr("The session was aborted by the user or system."); + case QNetworkSession::OperationNotSupportedError: + return tr("The requested operation is not supported by the system."); + case QNetworkSession::InvalidConfigurationError: + return tr("The specified configuration cannot be used."); + case QNetworkSession::RoamingError: + return tr("Roaming was aborted or is not possible."); + + } + + return QString(); +} + +QNetworkSession::SessionError QNetworkSessionPrivateImpl::error() const +{ + return lastError; +} + +quint64 QNetworkSessionPrivateImpl::bytesWritten() const +{ + if (engine && state == QNetworkSession::Connected) + return engine->bytesWritten(activeConfig.identifier()); + else + return Q_UINT64_C(0); +} + +quint64 QNetworkSessionPrivateImpl::bytesReceived() const +{ + if (engine && state == QNetworkSession::Connected) + return engine->bytesReceived(activeConfig.identifier()); + else + return Q_UINT64_C(0); +} + +quint64 QNetworkSessionPrivateImpl::activeTime() const +{ + if (state == QNetworkSession::Connected && startTime != Q_UINT64_C(0)) + return QDateTime::currentDateTime().toTime_t() - startTime; + else + return Q_UINT64_C(0); +} + +void QNetworkSessionPrivateImpl::updateStateFromServiceNetwork() +{ + QNetworkSession::State oldState = state; + + foreach (const QNetworkConfiguration &config, serviceConfig.children()) { + if ((config.state() & QNetworkConfiguration::Active) != QNetworkConfiguration::Active) + continue; + + if (activeConfig != config) { + if (engine) { + disconnect(engine, + SIGNAL(connectionError(QString,QBearerEngineImpl::ConnectionError)), + this, + SLOT(connectionError(QString,QBearerEngineImpl::ConnectionError))); + } + + activeConfig = config; + engine = getEngineFromId(activeConfig.identifier()); + if (engine) { + connect(engine, + SIGNAL(connectionError(QString,QBearerEngineImpl::ConnectionError)), + this, SLOT(connectionError(QString,QBearerEngineImpl::ConnectionError)), + Qt::QueuedConnection); + } + emit newConfigurationActivated(); + } + + state = QNetworkSession::Connected; + if (state != oldState) + emit stateChanged(state); + + return; + } + + if (serviceConfig.children().isEmpty()) + state = QNetworkSession::NotAvailable; + else + state = QNetworkSession::Disconnected; + + if (state != oldState) + emit stateChanged(state); +} + +void QNetworkSessionPrivateImpl::updateStateFromActiveConfig() +{ + if (!engine) + return; + + QNetworkSession::State oldState = state; + + state = engine->sessionStateForId(activeConfig.identifier()); + + bool oldActive = isOpen; + isOpen = (state == QNetworkSession::Connected) ? opened : false; + + if (!oldActive && isOpen) + emit quitPendingWaitsForOpened(); + if (oldActive && !isOpen) + emit closed(); + + if (oldState != state) + emit stateChanged(state); +} + +void QNetworkSessionPrivateImpl::networkConfigurationsChanged() +{ + if (serviceConfig.isValid()) + updateStateFromServiceNetwork(); + else + updateStateFromActiveConfig(); + + startTime = engine->startTime(activeConfig.identifier()); +} + +void QNetworkSessionPrivateImpl::configurationChanged(QNetworkConfigurationPrivatePointer config) +{ + if (serviceConfig.isValid() && + (config->id == serviceConfig.identifier() || config->id == activeConfig.identifier())) { + updateStateFromServiceNetwork(); + } else if (config->id == activeConfig.identifier()) { + updateStateFromActiveConfig(); + } +} + +void QNetworkSessionPrivateImpl::forcedSessionClose(const QNetworkConfiguration &config) +{ + if (activeConfig == config) { + opened = false; + isOpen = false; + + emit closed(); + + lastError = QNetworkSession::SessionAbortedError; + emit QNetworkSessionPrivate::error(lastError); + } +} + +void QNetworkSessionPrivateImpl::connectionError(const QString &id, + QBearerEngineImpl::ConnectionError error) +{ + if (activeConfig.identifier() == id) { + networkConfigurationsChanged(); + switch (error) { + case QBearerEngineImpl::OperationNotSupported: + lastError = QNetworkSession::OperationNotSupportedError; + opened = false; + break; + case QBearerEngineImpl::InterfaceLookupError: + case QBearerEngineImpl::ConnectError: + case QBearerEngineImpl::DisconnectionError: + default: + lastError = QNetworkSession::UnknownSessionError; + } + + emit QNetworkSessionPrivate::error(lastError); + } +} + +void QNetworkSessionPrivateImpl::decrementTimeout() +{ + if (--sessionTimeout <= 0) { + disconnect(engine, SIGNAL(updateCompleted()), this, SLOT(decrementTimeout())); + sessionTimeout = -1; + close(); + } +} + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT + diff --git a/src/plugins/bearer/qnetworksession_impl.h b/src/plugins/bearer/qnetworksession_impl.h new file mode 100644 index 0000000..a4902eb --- /dev/null +++ b/src/plugins/bearer/qnetworksession_impl.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNETWORKSESSION_IMPL_H +#define QNETWORKSESSION_IMPL_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qbearerengine_impl.h" + +#include <QtNetwork/private/qnetworkconfigmanager_p.h> +#include <QtNetwork/private/qnetworksession_p.h> + +#include <QtCore/qdatetime.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +class QBearerEngineImpl; + +class QNetworkSessionPrivateImpl : public QNetworkSessionPrivate +{ + Q_OBJECT +public: + QNetworkSessionPrivateImpl() + : startTime(0), sessionTimeout(-1) + { + } + + ~QNetworkSessionPrivateImpl() + { + } + + //called by QNetworkSession constructor and ensures + //that the state is immediately updated (w/o actually opening + //a session). Also this function should take care of + //notification hooks to discover future state changes. + void syncStateWithInterface(); + +#ifndef QT_NO_NETWORKINTERFACE + QNetworkInterface currentInterface() const; +#endif + QVariant sessionProperty(const QString& key) const; + void setSessionProperty(const QString& key, const QVariant& value); + + void open(); + void close(); + void stop(); + void migrate(); + void accept(); + void ignore(); + void reject(); + + QString errorString() const; //must return translated string + QNetworkSession::SessionError error() const; + + quint64 bytesWritten() const; + quint64 bytesReceived() const; + quint64 activeTime() const; + +private: + void updateStateFromServiceNetwork(); + void updateStateFromActiveConfig(); + +private Q_SLOTS: + void networkConfigurationsChanged(); + void configurationChanged(QNetworkConfigurationPrivatePointer config); + void forcedSessionClose(const QNetworkConfiguration &config); + void connectionError(const QString &id, QBearerEngineImpl::ConnectionError error); + void decrementTimeout(); + +private: + QBearerEngineImpl *engine; + + quint64 startTime; + + QNetworkSession::SessionError lastError; + + int sessionTimeout; + + bool opened; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT + +#endif //QNETWORKSESSION_IMPL_H + diff --git a/src/plugins/bearer/symbian/3_1/3_1.pro b/src/plugins/bearer/symbian/3_1/3_1.pro new file mode 100644 index 0000000..b7c6aef --- /dev/null +++ b/src/plugins/bearer/symbian/3_1/3_1.pro @@ -0,0 +1,9 @@ +include(../symbian.pri) + +is_using_gnupoc { + LIBS += -lapengine +} else { + LIBS += -lAPEngine +} +TARGET = $${TARGET}_3_1 +TARGET.UID3 = 0x2002131C diff --git a/src/plugins/bearer/symbian/3_2/3_2.pro b/src/plugins/bearer/symbian/3_2/3_2.pro new file mode 100644 index 0000000..ac3b3f8 --- /dev/null +++ b/src/plugins/bearer/symbian/3_2/3_2.pro @@ -0,0 +1,17 @@ +include(../symbian.pri) + +symbian { + contains(S60_VERSION, 3.1) { + is_using_gnupoc { + LIBS += -lapengine + } else { + LIBS += -lAPEngine + } + } else { + DEFINES += SNAP_FUNCTIONALITY_AVAILABLE + LIBS += -lcmmanager + } +} + +TARGET = $${TARGET}_3_2 +TARGET.UID3 = 0x2002131D diff --git a/src/plugins/bearer/symbian/main.cpp b/src/plugins/bearer/symbian/main.cpp new file mode 100644 index 0000000..c4f539b --- /dev/null +++ b/src/plugins/bearer/symbian/main.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "symbianengine.h" + +#include <QtNetwork/private/qbearerplugin_p.h> + +#include <QtCore/qdebug.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +class QSymbianEnginePlugin : public QBearerEnginePlugin +{ +public: + QSymbianEnginePlugin(); + ~QSymbianEnginePlugin(); + + QStringList keys() const; + QBearerEngine *create(const QString &key) const; +}; + +QSymbianEnginePlugin::QSymbianEnginePlugin() +{ +} + +QSymbianEnginePlugin::~QSymbianEnginePlugin() +{ +} + +QStringList QSymbianEnginePlugin::keys() const +{ + return QStringList() << QLatin1String("symbian"); +} + +QBearerEngine *QSymbianEnginePlugin::create(const QString &key) const +{ + if (key == QLatin1String("symbian")) + return new SymbianEngine; + else + return 0; +} + +Q_EXPORT_STATIC_PLUGIN(QSymbianEnginePlugin) +Q_EXPORT_PLUGIN2(qsymbianbearer, QSymbianEnginePlugin) + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.cpp b/src/plugins/bearer/symbian/qnetworksession_impl.cpp new file mode 100644 index 0000000..53a5b4d --- /dev/null +++ b/src/plugins/bearer/symbian/qnetworksession_impl.cpp @@ -0,0 +1,1582 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnetworksession_impl.h" +#include "symbianengine.h" + +#include <es_enum.h> +#include <es_sock.h> +#include <in_sock.h> +#include <stdapis/sys/socket.h> +#include <stdapis/net/if.h> + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE +#include <cmmanager.h> +#endif + +#if defined(OCC_FUNCTIONALITY_AVAILABLE) && defined(SNAP_FUNCTIONALITY_AVAILABLE) +#include <extendedconnpref.h> +#endif + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +QNetworkSessionPrivateImpl::QNetworkSessionPrivateImpl(SymbianEngine *engine) +: CActive(CActive::EPriorityUserInput), engine(engine), + iDynamicUnSetdefaultif(0), ipConnectionNotifier(0), + iHandleStateNotificationsFromManager(false), iFirstSync(true), iStoppedByUser(false), + iClosedByUser(false), iError(QNetworkSession::UnknownSessionError), iALREnabled(0), + iConnectInBackground(false), isOpening(false) +{ + CActiveScheduler::Add(this); + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + iMobility = NULL; +#endif + // Try to load "Open C" dll dynamically and + // try to attach to unsetdefaultif function dynamically. + // This is to avoid build breaks with old OpenC versions. + if (iOpenCLibrary.Load(_L("libc")) == KErrNone) { + iDynamicUnSetdefaultif = (TOpenCUnSetdefaultifFunction)iOpenCLibrary.Lookup(597); + } +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - "; + if (iDynamicUnSetdefaultif) + qDebug() << "dynamic unsetdefaultif() is present in PIPS library. "; + else + qDebug() << "dynamic unsetdefaultif() not present in PIPS library. "; +#endif + + TRAP_IGNORE(iConnectionMonitor.ConnectL()); +} + +QNetworkSessionPrivateImpl::~QNetworkSessionPrivateImpl() +{ + isOpen = false; + isOpening = false; + + // Cancel Connection Progress Notifications first. + // Note: ConnectionNotifier must be destroyed before Canceling RConnection::Start() + // => deleting ipConnectionNotifier results RConnection::CancelProgressNotification() + delete ipConnectionNotifier; + ipConnectionNotifier = NULL; + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + if (iMobility) { + delete iMobility; + iMobility = NULL; + } +#endif + + // Cancel possible RConnection::Start() + Cancel(); + iSocketServ.Close(); + + // Close global 'Open C' RConnection + // Clears also possible unsetdefaultif() flags. + setdefaultif(0); + + iConnectionMonitor.Close(); + iOpenCLibrary.Close(); +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) + << " - destroyed (and setdefaultif(0))"; +#endif +} + +void QNetworkSessionPrivateImpl::configurationStateChanged(quint32 accessPointId, quint32 connMonId, QNetworkSession::State newState) +{ + if (iHandleStateNotificationsFromManager) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "configurationStateChanged from manager for IAP : " << QString::number(accessPointId) + << "connMon ID : " << QString::number(connMonId) << " : to a state: " << newState + << "whereas my current state is: " << state; +#else + Q_UNUSED(connMonId); +#endif + this->newState(newState, accessPointId); + } +} + +void QNetworkSessionPrivateImpl::configurationRemoved(QNetworkConfigurationPrivatePointer config) +{ + if (!publicConfig.isValid()) + return; + + TUint32 publicNumericId = + toSymbianConfig(privateConfiguration(publicConfig))->numericIdentifier(); + + if (toSymbianConfig(config)->numericIdentifier() == publicNumericId) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "configurationRemoved IAP: " << QString::number(publicNumericId) << " : going to State: Invalid"; +#endif + this->newState(QNetworkSession::Invalid, publicNumericId); + } +} + +void QNetworkSessionPrivateImpl::configurationAdded(QNetworkConfigurationPrivatePointer config) +{ + Q_UNUSED(config); + // If session is based on service network, some other app may create new access points + // to the SNAP --> synchronize session's state with that of interface's. + if (!publicConfig.isValid() || publicConfig.type() != QNetworkConfiguration::ServiceNetwork) + return; + +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "configurationAdded IAP: " + << toSymbianConfig(privateConfiguration(config))->numericIdentifier(); +#endif + + syncStateWithInterface(); +} + +// Function sets the state of the session to match the state +// of the underlying interface (the configuration this session is based on) +void QNetworkSessionPrivateImpl::syncStateWithInterface() +{ + if (!publicConfig.isValid()) + return; + + if (iFirstSync) { + QObject::connect(engine, + SIGNAL(configurationStateChanged(quint32,quint32,QNetworkSession::State)), + this, + SLOT(configurationStateChanged(quint32,quint32,QNetworkSession::State))); + // Listen to configuration removals, so that in case the configuration + // this session is based on is removed, session knows to enter Invalid -state. + QObject::connect(engine, SIGNAL(configurationRemoved(QNetworkConfigurationPrivatePointer)), + this, SLOT(configurationRemoved(QNetworkConfigurationPrivatePointer))); + // Connect to configuration additions, so that in case a configuration is added + // in a SNAP this session is based on, the session knows to synch its state with its + // interface. + QObject::connect(engine, SIGNAL(configurationAdded(QNetworkConfigurationPrivatePointer)), + this, SLOT(configurationAdded(QNetworkConfigurationPrivatePointer))); + } + // Start listening IAP state changes from QNetworkConfigurationManagerPrivate + iHandleStateNotificationsFromManager = true; + + // Check what is the state of the configuration this session is based on + // and set the session in appropriate state. +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "syncStateWithInterface() state of publicConfig is: " << publicConfig.state(); +#endif + switch (publicConfig.state()) { + case QNetworkConfiguration::Active: + newState(QNetworkSession::Connected); + break; + case QNetworkConfiguration::Discovered: + newState(QNetworkSession::Disconnected); + break; + case QNetworkConfiguration::Defined: + newState(QNetworkSession::NotAvailable); + break; + case QNetworkConfiguration::Undefined: + default: + newState(QNetworkSession::Invalid); + } +} + +#ifndef QT_NO_NETWORKINTERFACE +QNetworkInterface QNetworkSessionPrivateImpl::interface(TUint iapId) const +{ + QString interfaceName; + + TSoInetInterfaceInfo ifinfo; + TPckg<TSoInetInterfaceInfo> ifinfopkg(ifinfo); + TSoInetIfQuery ifquery; + TPckg<TSoInetIfQuery> ifquerypkg(ifquery); + + // Open dummy socket for interface queries + RSocket socket; + TInt retVal = socket.Open(iSocketServ, _L("udp")); + if (retVal != KErrNone) { + return QNetworkInterface(); + } + + // Start enumerating interfaces + socket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl); + while(socket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, ifinfopkg) == KErrNone) { + ifquery.iName = ifinfo.iName; + TInt err = socket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, ifquerypkg); + if(err == KErrNone && ifquery.iZone[1] == iapId) { // IAP ID is index 1 of iZone + if(ifinfo.iAddress.Address() > 0) { + interfaceName = QString::fromUtf16(ifinfo.iName.Ptr(),ifinfo.iName.Length()); + break; + } + } + } + + socket.Close(); + + if (interfaceName.isEmpty()) { + return QNetworkInterface(); + } + + return QNetworkInterface::interfaceFromName(interfaceName); +} +#endif + +#ifndef QT_NO_NETWORKINTERFACE +QNetworkInterface QNetworkSessionPrivateImpl::currentInterface() const +{ +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "currentInterface() requested, state: " << state + << "publicConfig validity: " << publicConfig.isValid(); + if (activeInterface.isValid()) + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "interface is: " << activeInterface.humanReadableName(); +#endif + + if (!publicConfig.isValid() || state != QNetworkSession::Connected) { + return QNetworkInterface(); + } + + return activeInterface; +} +#endif + +QVariant QNetworkSessionPrivateImpl::sessionProperty(const QString& key) const +{ + if (key == "ConnectInBackground") { + return QVariant(iConnectInBackground); + } + return QVariant(); +} + +void QNetworkSessionPrivateImpl::setSessionProperty(const QString& key, const QVariant& value) +{ + // Valid value means adding property, invalid means removing it. + if (key == "ConnectInBackground") { + if (value.isValid()) { + iConnectInBackground = value.toBool(); + } else { + iConnectInBackground = EFalse; + } + } +} + +QString QNetworkSessionPrivateImpl::errorString() const +{ + switch (iError) { + case QNetworkSession::UnknownSessionError: + return tr("Unknown session error."); + case QNetworkSession::SessionAbortedError: + return tr("The session was aborted by the user or system."); + case QNetworkSession::OperationNotSupportedError: + return tr("The requested operation is not supported by the system."); + case QNetworkSession::InvalidConfigurationError: + return tr("The specified configuration cannot be used."); + case QNetworkSession::RoamingError: + return tr("Roaming was aborted or is not possible."); + } + + return QString(); +} + +QNetworkSession::SessionError QNetworkSessionPrivateImpl::error() const +{ + return iError; +} + +void QNetworkSessionPrivateImpl::open() +{ +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "open() called, session state is: " << state << " and isOpen is: " + << isOpen << isOpening; +#endif + + if (isOpen || isOpening) + return; + + isOpening = true; + + // Stop handling IAP state change signals from QNetworkConfigurationManagerPrivate + // => RConnection::ProgressNotification will be used for IAP/SNAP monitoring + iHandleStateNotificationsFromManager = false; + + // Configuration may have been invalidated after session creation by platform + // (e.g. configuration has been deleted). + if (!publicConfig.isValid()) { + newState(QNetworkSession::Invalid); + iError = QNetworkSession::InvalidConfigurationError; + emit QNetworkSessionPrivate::error(iError); + return; + } + // If opening a undefined configuration, session emits error and enters + // NotAvailable -state. Note that we will try ones in 'defined' state to avoid excessive + // need for WLAN scans (via updateConfigurations()), because user may have walked + // into a WLAN range, but periodic background scan has not occurred yet --> + // we don't want to force application to make frequent updateConfigurations() calls + // to be able to try if e.g. home WLAN is available. + if (publicConfig.state() == QNetworkConfiguration::Undefined) { + newState(QNetworkSession::NotAvailable); + iError = QNetworkSession::InvalidConfigurationError; + emit QNetworkSessionPrivate::error(iError); + return; + } + // Clear possible previous states + iStoppedByUser = false; + iClosedByUser = false; + + TInt error = iSocketServ.Connect(); + if (error != KErrNone) { + // Could not open RSocketServ + newState(QNetworkSession::Invalid); + iError = QNetworkSession::UnknownSessionError; + emit QNetworkSessionPrivate::error(iError); + syncStateWithInterface(); + return; + } + + error = iConnection.Open(iSocketServ); + if (error != KErrNone) { + // Could not open RConnection + iSocketServ.Close(); + newState(QNetworkSession::Invalid); + iError = QNetworkSession::UnknownSessionError; + emit QNetworkSessionPrivate::error(iError); + syncStateWithInterface(); + return; + } + + // Use RConnection::ProgressNotification for IAP/SNAP monitoring + // (<=> ConnectionProgressNotifier uses RConnection::ProgressNotification) + if (!ipConnectionNotifier) { + ipConnectionNotifier = new ConnectionProgressNotifier(*this,iConnection); + } + if (ipConnectionNotifier) { + ipConnectionNotifier->StartNotifications(); + } + + if (publicConfig.type() == QNetworkConfiguration::InternetAccessPoint) { + SymbianNetworkConfigurationPrivate *symbianConfig = + toSymbianConfig(privateConfiguration(publicConfig)); + +#if defined(OCC_FUNCTIONALITY_AVAILABLE) && defined(SNAP_FUNCTIONALITY_AVAILABLE) + // With One Click Connectivity (Symbian^3 onwards) it is possible + // to connect silently, without any popups. + TConnPrefList pref; + TExtendedConnPref prefs; + + prefs.SetIapId(symbianConfig->numericIdentifier()); + if (iConnectInBackground) { + prefs.SetNoteBehaviour( TExtendedConnPref::ENoteBehaviourConnSilent ); + } + pref.AppendL(&prefs); +#else + TCommDbConnPref pref; + pref.SetDialogPreference(ECommDbDialogPrefDoNotPrompt); + + pref.SetIapId(symbianConfig->numericIdentifier()); +#endif + iConnection.Start(pref, iStatus); + if (!IsActive()) { + SetActive(); + } + // Avoid flip flop of states if the configuration is already + // active. IsOpen/opened() will indicate when ready. + if (state != QNetworkSession::Connected) { + newState(QNetworkSession::Connecting); + } + } else if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) { + SymbianNetworkConfigurationPrivate *symbianConfig = + toSymbianConfig(privateConfiguration(publicConfig)); + +#if defined(OCC_FUNCTIONALITY_AVAILABLE) && defined(SNAP_FUNCTIONALITY_AVAILABLE) + // On Symbian^3 if service network is not reachable, it triggers a UI (aka EasyWLAN) where + // user can create new IAPs. To detect this, we need to store the number of IAPs + // there was before connection was started. + iKnownConfigsBeforeConnectionStart = engine->accessPointConfigurationIdentifiers(); + TConnPrefList snapPref; + TExtendedConnPref prefs; + prefs.SetSnapId(symbianConfig->numericIdentifier()); + if (iConnectInBackground) { + prefs.SetNoteBehaviour( TExtendedConnPref::ENoteBehaviourConnSilent ); + } + snapPref.AppendL(&prefs); +#else + TConnSnapPref snapPref(symbianConfig->numericIdentifier()); +#endif + iConnection.Start(snapPref, iStatus); + if (!IsActive()) { + SetActive(); + } + // Avoid flip flop of states if the configuration is already + // active. IsOpen/opened() will indicate when ready. + if (state != QNetworkSession::Connected) { + newState(QNetworkSession::Connecting); + } + } else if (publicConfig.type() == QNetworkConfiguration::UserChoice) { + iKnownConfigsBeforeConnectionStart = engine->accessPointConfigurationIdentifiers(); + iConnection.Start(iStatus); + if (!IsActive()) { + SetActive(); + } + newState(QNetworkSession::Connecting); + } + + if (error != KErrNone) { + isOpen = false; + isOpening = false; + iError = QNetworkSession::UnknownSessionError; + emit QNetworkSessionPrivate::error(iError); + if (ipConnectionNotifier) { + ipConnectionNotifier->StopNotifications(); + } + syncStateWithInterface(); + } +} + +TUint QNetworkSessionPrivateImpl::iapClientCount(TUint aIAPId) const +{ + TRequestStatus status; + TUint connectionCount; + iConnectionMonitor.GetConnectionCount(connectionCount, status); + User::WaitForRequest(status); + if (status.Int() == KErrNone) { + for (TUint i = 1; i <= connectionCount; i++) { + TUint connectionId; + TUint subConnectionCount; + iConnectionMonitor.GetConnectionInfo(i, connectionId, subConnectionCount); + TUint apId; + iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status); + User::WaitForRequest(status); + if (apId == aIAPId) { + TConnMonClientEnumBuf buf; + iConnectionMonitor.GetPckgAttribute(connectionId, 0, KClientInfo, buf, status); + User::WaitForRequest(status); + if (status.Int() == KErrNone) { + return buf().iCount; + } + } + } + } + return 0; +} + +void QNetworkSessionPrivateImpl::close(bool allowSignals) +{ +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "close() called, session state is: " << state << " and isOpen is : " + << isOpen; +#endif + + if (!isOpen && state != QNetworkSession::Connecting) { + return; + } + // Mark this session as closed-by-user so that we are able to report + // distinguish between stop() and close() state transitions + // when reporting. + iClosedByUser = true; + isOpen = false; + isOpening = false; + + serviceConfig = QNetworkConfiguration(); + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + if (iMobility) { + delete iMobility; + iMobility = NULL; + } +#endif + + if (ipConnectionNotifier && !iHandleStateNotificationsFromManager) { + ipConnectionNotifier->StopNotifications(); + // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate + iHandleStateNotificationsFromManager = true; + } + + Cancel(); // closes iConnection + iSocketServ.Close(); + + // Close global 'Open C' RConnection. If OpenC supports, + // close the defaultif for good to avoid difficult timing + // and bouncing issues of network going immediately back up + // because of e.g. select() thread etc. + if (iDynamicUnSetdefaultif) { + iDynamicUnSetdefaultif(); + } else { + setdefaultif(0); + } + + // If UserChoice, go down immediately. If some other configuration, + // go down immediately if there is no reports expected from the platform; + // in practice Connection Monitor is aware of connections only after + // KFinishedSelection event, and hence reports only after that event, but + // that does not seem to be trusted on all Symbian versions --> safest + // to go down. + if (publicConfig.type() == QNetworkConfiguration::UserChoice || state == QNetworkSession::Connecting) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "going disconnected right away, since either UserChoice or Connecting"; +#endif + newState(QNetworkSession::Closing); + newState(QNetworkSession::Disconnected); + } + if (allowSignals) { + emit closed(); + } +} + +void QNetworkSessionPrivateImpl::stop() +{ +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "stop() called, session state is: " << state << " and isOpen is : " + << isOpen; +#endif + if (!isOpen && + publicConfig.isValid() && + publicConfig.type() == QNetworkConfiguration::InternetAccessPoint) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "since session is not open, using RConnectionMonitor to stop() the interface"; +#endif + iStoppedByUser = true; + // If the publicConfig is type of IAP, enumerate through connections at + // connection monitor. If publicConfig is active in that list, stop it. + // Otherwise there is nothing to stop. Note: because this QNetworkSession is not open, + // activeConfig is not usable. + TUint count; + TRequestStatus status; + iConnectionMonitor.GetConnectionCount(count, status); + User::WaitForRequest(status); + if (status.Int() != KErrNone) { + return; + } + TUint numSubConnections; // Not used but needed by GetConnectionInfo i/f + TUint connectionId; + for (TUint i = 1; i <= count; ++i) { + // Get (connection monitor's assigned) connection ID + TInt ret = iConnectionMonitor.GetConnectionInfo(i, connectionId, numSubConnections); + if (ret == KErrNone) { + SymbianNetworkConfigurationPrivate *symbianConfig = + toSymbianConfig(privateConfiguration(publicConfig)); + + // See if connection Id matches with our Id. If so, stop() it. + if (symbianConfig->connectionIdentifier() == connectionId) { + ret = iConnectionMonitor.SetBoolAttribute(connectionId, + 0, // subConnectionId don't care + KConnectionStop, + ETrue); + } + } + // Enter disconnected state right away since the session is not even open. + // Symbian^3 connection monitor does not emit KLinkLayerClosed when + // connection is stopped via connection monitor. + newState(QNetworkSession::Disconnected); + } + } else if (isOpen) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "since session is open, using RConnection to stop() the interface"; +#endif + // Since we are open, use RConnection to stop the interface + isOpen = false; + isOpening = false; + iStoppedByUser = true; + newState(QNetworkSession::Closing); + if (ipConnectionNotifier) { + ipConnectionNotifier->StopNotifications(); + // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate + iHandleStateNotificationsFromManager = true; + } + iConnection.Stop(RConnection::EStopAuthoritative); + isOpen = true; + isOpening = false; + close(false); + emit closed(); + } +} + +void QNetworkSessionPrivateImpl::migrate() +{ +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + if (iMobility) { + // Close global 'Open C' RConnection. If openC supports, use the 'heavy' + // version to block all subsequent requests. + if (iDynamicUnSetdefaultif) { + iDynamicUnSetdefaultif(); + } else { + setdefaultif(0); + } + // Start migrating to new IAP + iMobility->MigrateToPreferredCarrier(); + } +#endif +} + +void QNetworkSessionPrivateImpl::ignore() +{ +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + if (iMobility) { + iMobility->IgnorePreferredCarrier(); + + if (!iALRUpgradingConnection) { + newState(QNetworkSession::Disconnected); + } else { + newState(QNetworkSession::Connected,iOldRoamingIap); + } + } +#endif +} + +void QNetworkSessionPrivateImpl::accept() +{ +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + if (iMobility) { + iMobility->NewCarrierAccepted(); + + QNetworkConfiguration newActiveConfig = activeConfiguration(iNewRoamingIap); + + // Use name of the new IAP to open global 'Open C' RConnection + QByteArray nameAsByteArray = newActiveConfig.name().toUtf8(); + ifreq ifr; + memset(&ifr, 0, sizeof(struct ifreq)); + strcpy(ifr.ifr_name, nameAsByteArray.constData()); + setdefaultif(&ifr); + + newState(QNetworkSession::Connected, iNewRoamingIap); + } +#endif +} + +void QNetworkSessionPrivateImpl::reject() +{ +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + if (iMobility) { + iMobility->NewCarrierRejected(); + + if (!iALRUpgradingConnection) { + newState(QNetworkSession::Disconnected); + } else { + QNetworkConfiguration newActiveConfig = activeConfiguration(iOldRoamingIap); + + // Use name of the old IAP to open global 'Open C' RConnection + QByteArray nameAsByteArray = newActiveConfig.name().toUtf8(); + ifreq ifr; + memset(&ifr, 0, sizeof(struct ifreq)); + strcpy(ifr.ifr_name, nameAsByteArray.constData()); + setdefaultif(&ifr); + + newState(QNetworkSession::Connected, iOldRoamingIap); + } + } +#endif +} + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE +void QNetworkSessionPrivateImpl::PreferredCarrierAvailable(TAccessPointInfo aOldAPInfo, + TAccessPointInfo aNewAPInfo, + TBool aIsUpgrade, + TBool aIsSeamless) +{ + iOldRoamingIap = aOldAPInfo.AccessPoint(); + iNewRoamingIap = aNewAPInfo.AccessPoint(); + newState(QNetworkSession::Roaming); + if (iALREnabled > 0) { + iALRUpgradingConnection = aIsUpgrade; + QList<QNetworkConfiguration> configs = publicConfig.children(); + for (int i=0; i < configs.count(); i++) { + SymbianNetworkConfigurationPrivate *symbianConfig = + toSymbianConfig(privateConfiguration(configs[i])); + + if (symbianConfig->numericIdentifier() == aNewAPInfo.AccessPoint()) { + // Any slot connected to the signal might throw an std::exception, + // which must not propagate into Symbian code (this function is a callback + // from platform). We could convert exception to a symbian Leave, but since the + // prototype of this function bans this (no trailing 'L'), we just catch + // and drop. + QT_TRY { + emit preferredConfigurationChanged(configs[i], aIsSeamless); + } + QT_CATCH (std::exception&) {} + } + } + } else { + migrate(); + } +} + +void QNetworkSessionPrivateImpl::NewCarrierActive(TAccessPointInfo /*aNewAPInfo*/, TBool /*aIsSeamless*/) +{ + if (iALREnabled > 0) { + QT_TRY { + emit newConfigurationActivated(); + } + QT_CATCH (std::exception&) {} + } else { + accept(); + } +} + +void QNetworkSessionPrivateImpl::Error(TInt /*aError*/) +{ +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "roaming Error() occurred, isOpen is: " << isOpen; +#endif + if (isOpen) { + isOpen = false; + isOpening = false; + activeConfig = QNetworkConfiguration(); + serviceConfig = QNetworkConfiguration(); + iError = QNetworkSession::RoamingError; + emit QNetworkSessionPrivate::error(iError); + Cancel(); + if (ipConnectionNotifier) { + ipConnectionNotifier->StopNotifications(); + } + QT_TRY { + syncStateWithInterface(); + // In some cases IAP is still in Connected state when + // syncStateWithInterface(); is called + // => Following call makes sure that Session state + // changes immediately to Disconnected. + newState(QNetworkSession::Disconnected); + emit closed(); + } + QT_CATCH (std::exception&) {} + } else if (iStoppedByUser) { + // If the user of this session has called the stop() and + // configuration is based on internet SNAP, this needs to be + // done here because platform might roam. + QT_TRY { + newState(QNetworkSession::Disconnected); + } + QT_CATCH (std::exception&) {} + } +} +#endif + +void QNetworkSessionPrivateImpl::setALREnabled(bool enabled) +{ + if (enabled) { + iALREnabled++; + } else { + iALREnabled--; + } +} + +QNetworkConfiguration QNetworkSessionPrivateImpl::bestConfigFromSNAP(const QNetworkConfiguration& snapConfig) const +{ + QNetworkConfiguration config; + QList<QNetworkConfiguration> subConfigurations = snapConfig.children(); + for (int i = 0; i < subConfigurations.count(); i++ ) { + if (subConfigurations[i].state() == QNetworkConfiguration::Active) { + config = subConfigurations[i]; + break; + } else if (!config.isValid() && subConfigurations[i].state() == QNetworkConfiguration::Discovered) { + config = subConfigurations[i]; + } + } + if (!config.isValid() && subConfigurations.count() > 0) { + config = subConfigurations[0]; + } + return config; +} + +quint64 QNetworkSessionPrivateImpl::bytesWritten() const +{ + return transferredData(KUplinkData); +} + +quint64 QNetworkSessionPrivateImpl::bytesReceived() const +{ + return transferredData(KDownlinkData); +} + +quint64 QNetworkSessionPrivateImpl::transferredData(TUint dataType) const +{ + if (!publicConfig.isValid()) { + return 0; + } + + QNetworkConfiguration config; + if (publicConfig.type() == QNetworkConfiguration::UserChoice) { + if (serviceConfig.isValid()) { + config = serviceConfig; + } else { + if (activeConfig.isValid()) { + config = activeConfig; + } + } + } else { + config = publicConfig; + } + + if (!config.isValid()) { + return 0; + } + + TUint count; + TRequestStatus status; + iConnectionMonitor.GetConnectionCount(count, status); + User::WaitForRequest(status); + if (status.Int() != KErrNone) { + return 0; + } + + TUint transferredData = 0; + TUint numSubConnections; + TUint connectionId; + bool configFound; + for (TUint i = 1; i <= count; i++) { + TInt ret = iConnectionMonitor.GetConnectionInfo(i, connectionId, numSubConnections); + if (ret == KErrNone) { + TUint apId; + iConnectionMonitor.GetUintAttribute(connectionId, 0, KIAPId, apId, status); + User::WaitForRequest(status); + if (status.Int() == KErrNone) { + configFound = false; + if (config.type() == QNetworkConfiguration::ServiceNetwork) { + QList<QNetworkConfiguration> configs = config.children(); + for (int i=0; i < configs.count(); i++) { + SymbianNetworkConfigurationPrivate *symbianConfig = + toSymbianConfig(privateConfiguration(configs[i])); + + if (symbianConfig->numericIdentifier() == apId) { + configFound = true; + break; + } + } + } else { + SymbianNetworkConfigurationPrivate *symbianConfig = + toSymbianConfig(privateConfiguration(config)); + + if (symbianConfig->numericIdentifier() == apId) + configFound = true; + } + if (configFound) { + TUint tData; + iConnectionMonitor.GetUintAttribute(connectionId, 0, dataType, tData, status ); + User::WaitForRequest(status); + if (status.Int() == KErrNone) { + transferredData += tData; + } + } + } + } + } + + return transferredData; +} + +quint64 QNetworkSessionPrivateImpl::activeTime() const +{ + if (!isOpen || startTime.isNull()) { + return 0; + } + return startTime.secsTo(QDateTime::currentDateTime()); +} + +QNetworkConfiguration QNetworkSessionPrivateImpl::activeConfiguration(TUint32 iapId) const +{ + if (iapId == 0) { + _LIT(KSetting, "IAP\\Id"); + iConnection.GetIntSetting(KSetting, iapId); +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + // Check if this is an Easy WLAN configuration. On Symbian^3 RConnection may report + // the used configuration as 'EasyWLAN' IAP ID if someone has just opened the configuration + // from WLAN Scan dialog, _and_ that connection is still up. We need to find the + // real matching configuration. Function alters the Easy WLAN ID to real IAP ID (only if + // easy WLAN): + easyWlanTrueIapId(iapId); +#endif + } + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) { + // Try to search IAP from the used SNAP using IAP Id + QList<QNetworkConfiguration> children = publicConfig.children(); + for (int i=0; i < children.count(); i++) { + SymbianNetworkConfigurationPrivate *childConfig = + toSymbianConfig(privateConfiguration(children[i])); + + if (childConfig->numericIdentifier() == iapId) + return children[i]; + } + + // Given IAP Id was not found from the used SNAP + // => Try to search matching IAP using mappingName + // mappingName contains: + // 1. "Access point name" for "Packet data" Bearer + // 2. "WLAN network name" (= SSID) for "Wireless LAN" Bearer + // 3. "Dial-up number" for "Data call Bearer" or "High Speed (GSM)" Bearer + // <=> Note: It's possible that in this case reported IAP is + // clone of the one of the IAPs of the used SNAP + // => If mappingName matches, clone has been found + QNetworkConfiguration pt = QNetworkConfigurationManager().configurationFromIdentifier( + QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId))); + + SymbianNetworkConfigurationPrivate *symbianConfig = + toSymbianConfig(privateConfiguration(pt)); + if (symbianConfig) { + for (int i=0; i < children.count(); i++) { + SymbianNetworkConfigurationPrivate *childConfig = + toSymbianConfig(privateConfiguration(children[i])); + + if (childConfig->configMappingName() == symbianConfig->configMappingName()) { + return children[i]; + } + } + } else { +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + // On Symbian^3 (only, not earlier or Symbian^4) if the SNAP was not reachable, it + // triggers user choice type of activity (EasyWLAN). As a result, a new IAP may be + // created, and hence if was not found yet. Therefore update configurations and see if + // there is something new. + + // 1. Update knowledge from the databases. + if (thread() != engine->thread()) + QMetaObject::invokeMethod(engine, "requestUpdate", Qt::BlockingQueuedConnection); + else + engine->requestUpdate(); + + // 2. Check if new configuration was created during connection creation + QList<QString> knownConfigs = engine->accessPointConfigurationIdentifiers(); +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "opened configuration was not known beforehand, looking for new."; +#endif + if (knownConfigs.count() > iKnownConfigsBeforeConnectionStart.count()) { + // Configuration count increased => new configuration was created + // => Search new, created configuration + QString newIapId; + for (int i=0; i < iKnownConfigsBeforeConnectionStart.count(); i++) { + if (knownConfigs[i] != iKnownConfigsBeforeConnectionStart[i]) { + newIapId = knownConfigs[i]; + break; + } + } + if (newIapId.isEmpty()) { + newIapId = knownConfigs[knownConfigs.count()-1]; + } + pt = QNetworkConfigurationManager().configurationFromIdentifier(newIapId); + if (pt.isValid()) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "new configuration was found, name, IAP id: " << pt.name() << pt.identifier(); +#endif + return pt; + } + } +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "configuration was not found, returning invalid."; +#endif +#endif + // Given IAP Id was not found from known IAPs array + return QNetworkConfiguration(); + } + // Matching IAP was not found from used SNAP + // => IAP from another SNAP is returned + // (Note: Returned IAP matches to given IAP Id) + return pt; + } +#endif + if (publicConfig.type() == QNetworkConfiguration::UserChoice) { + if (engine) { + QNetworkConfiguration pt = QNetworkConfigurationManager().configurationFromIdentifier( + QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId))); + // Try to found User Selected IAP from known IAPs (accessPointConfigurations) + if (pt.isValid()) { + return pt; + } else { + // Check if new (WLAN) IAP was created in IAP/SNAP dialog + // 1. Sync internal configurations array to commsdb first + if (thread() != engine->thread()) { + QMetaObject::invokeMethod(engine, "requestUpdate", + Qt::BlockingQueuedConnection); + } else { + engine->requestUpdate(); + } + // 2. Check if new configuration was created during connection creation + QStringList knownConfigs = engine->accessPointConfigurationIdentifiers(); + if (knownConfigs.count() > iKnownConfigsBeforeConnectionStart.count()) { + // Configuration count increased => new configuration was created + // => Search new, created configuration + QString newIapId; + for (int i=0; i < iKnownConfigsBeforeConnectionStart.count(); i++) { + if (knownConfigs[i] != iKnownConfigsBeforeConnectionStart[i]) { + newIapId = knownConfigs[i]; + break; + } + } + if (newIapId.isEmpty()) { + newIapId = knownConfigs[knownConfigs.count()-1]; + } + pt = QNetworkConfigurationManager().configurationFromIdentifier(newIapId); + if (pt.isValid()) + return pt; + } + } + } + return QNetworkConfiguration(); + } + + return publicConfig; +} + +void QNetworkSessionPrivateImpl::RunL() +{ +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "RConnection::RunL with status code: " << iStatus.Int(); +#endif + TInt statusCode = iStatus.Int(); + + switch (statusCode) { + case KErrNone: // Connection created successfully + { + TInt error = KErrNone; + QNetworkConfiguration newActiveConfig = activeConfiguration(); + if (!newActiveConfig.isValid()) { + // RConnection startup was successful but no configuration + // was found. That indicates that user has chosen to create a + // new WLAN configuration (from scan results), but that new + // configuration does not have access to Internet (Internet + // Connectivity Test, ICT, failed). + error = KErrGeneral; + } else { + // Use name of the IAP to open global 'Open C' RConnection + ifreq ifr; + memset(&ifr, 0, sizeof(struct ifreq)); + QByteArray nameAsByteArray = newActiveConfig.name().toUtf8(); + strcpy(ifr.ifr_name, nameAsByteArray.constData()); + error = setdefaultif(&ifr); + } + if (error != KErrNone) { + isOpen = false; + isOpening = false; + iError = QNetworkSession::UnknownSessionError; + QT_TRYCATCH_LEAVING(emit QNetworkSessionPrivate::error(iError)); + if (ipConnectionNotifier) { + ipConnectionNotifier->StopNotifications(); + } + if (!newActiveConfig.isValid()) { + // No valid configuration, bail out. + // Status updates from QNCM won't be received correctly + // because there is no configuration to associate them with so transit here. + iConnection.Close(); + newState(QNetworkSession::Closing); + newState(QNetworkSession::Disconnected); + } else { + Cancel(); + } + QT_TRYCATCH_LEAVING(syncStateWithInterface()); + return; + } + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) { + // Activate ALR monitoring + iMobility = CActiveCommsMobilityApiExt::NewL(iConnection, *this); + } +#endif + + isOpen = true; + isOpening = false; + activeConfig = newActiveConfig; + + SymbianNetworkConfigurationPrivate *symbianConfig = + toSymbianConfig(privateConfiguration(activeConfig)); + +#ifndef QT_NO_NETWORKINTERFACE + activeInterface = interface(symbianConfig->numericIdentifier()); +#endif + if (publicConfig.type() == QNetworkConfiguration::UserChoice) { + serviceConfig = QNetworkConfigurationManager() + .configurationFromIdentifier(activeConfig.identifier()); + } + + startTime = QDateTime::currentDateTime(); + + QT_TRYCATCH_LEAVING({ + newState(QNetworkSession::Connected); + emit quitPendingWaitsForOpened(); + }); + } + break; + case KErrNotFound: // Connection failed + isOpen = false; + isOpening = false; + activeConfig = QNetworkConfiguration(); + serviceConfig = QNetworkConfiguration(); + iError = QNetworkSession::InvalidConfigurationError; + QT_TRYCATCH_LEAVING(emit QNetworkSessionPrivate::error(iError)); + if (ipConnectionNotifier) { + ipConnectionNotifier->StopNotifications(); + } + Cancel(); + QT_TRYCATCH_LEAVING(syncStateWithInterface()); + break; + case KErrCancel: // Connection attempt cancelled + case KErrAlreadyExists: // Connection already exists + default: + isOpen = false; + isOpening = false; + activeConfig = QNetworkConfiguration(); + serviceConfig = QNetworkConfiguration(); + if (statusCode == KErrCancel) { + iError = QNetworkSession::SessionAbortedError; + } else if (publicConfig.state() == QNetworkConfiguration::Undefined || + publicConfig.state() == QNetworkConfiguration::Defined) { + iError = QNetworkSession::InvalidConfigurationError; + } else { + iError = QNetworkSession::UnknownSessionError; + } + QT_TRYCATCH_LEAVING(emit QNetworkSessionPrivate::error(iError)); + if (ipConnectionNotifier) { + ipConnectionNotifier->StopNotifications(); + } + Cancel(); + QT_TRYCATCH_LEAVING(syncStateWithInterface()); + break; + } +} + +void QNetworkSessionPrivateImpl::DoCancel() +{ + iConnection.Close(); +} + +// Enters newState if feasible according to current state. +// AccessPointId may be given as parameter. If it is zero, state-change is assumed to +// concern this session's configuration. If non-zero, the configuration is looked up +// and checked if it matches the configuration this session is based on. +bool QNetworkSessionPrivateImpl::newState(QNetworkSession::State newState, TUint accessPointId) +{ +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "NEW STATE, IAP ID : " << QString::number(accessPointId) << " , newState : " << QString::number(newState); +#endif + // Make sure that activeConfig is always updated when SNAP is signaled to be + // connected. + if (isOpen && publicConfig.type() == QNetworkConfiguration::ServiceNetwork && + newState == QNetworkSession::Connected) { + activeConfig = activeConfiguration(accessPointId); + +#ifndef QT_NO_NETWORKINTERFACE + SymbianNetworkConfigurationPrivate *symbianConfig = + toSymbianConfig(privateConfiguration(activeConfig)); + + activeInterface = interface(symbianConfig->numericIdentifier()); +#endif + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + // Use name of the IAP to set default IAP + QByteArray nameAsByteArray = activeConfig.name().toUtf8(); + ifreq ifr; + strcpy(ifr.ifr_name, nameAsByteArray.constData()); + + setdefaultif(&ifr); +#endif + } + + // Make sure that same state is not signaled twice in a row. + if (state == newState) { + return true; + } + + // Make sure that Connecting state does not overwrite Roaming state + if (state == QNetworkSession::Roaming && newState == QNetworkSession::Connecting) { + return false; + } + + // Make sure that Connected state is not reported when Connection is + // already Closing. + // Note: Stopping connection results sometimes KLinkLayerOpen + // to be reported first (just before KLinkLayerClosed). + if (state == QNetworkSession::Closing && newState == QNetworkSession::Connected) { + return false; + } + + // Make sure that some lagging 'closing' state-changes do not overwrite + // if we are already disconnected or closed. + if (state == QNetworkSession::Disconnected && newState == QNetworkSession::Closing) { + return false; + } + + // Make sure that some lagging 'connecting' state-changes do not overwrite + // if we are already connected (may righfully still happen with roaming though). + if (state == QNetworkSession::Connected && newState == QNetworkSession::Connecting) { + return false; + } + + bool emitSessionClosed = false; + + // If we abruptly go down and user hasn't closed the session, we've been aborted. + // Note that session may be in 'closing' state and not in 'connected' state, because + // depending on platform the platform may report KConfigDaemonStartingDeregistration + // event before KLinkLayerClosed + if ((isOpen && state == QNetworkSession::Connected && newState == QNetworkSession::Disconnected) || + (isOpen && !iClosedByUser && newState == QNetworkSession::Disconnected)) { + // Active & Connected state should change directly to Disconnected state + // only when something forces connection to close (eg. when another + // application or session stops connection or when network drops + // unexpectedly). + isOpen = false; + isOpening = false; + activeConfig = QNetworkConfiguration(); + serviceConfig = QNetworkConfiguration(); + iError = QNetworkSession::SessionAbortedError; + emit QNetworkSessionPrivate::error(iError); + if (ipConnectionNotifier) { + ipConnectionNotifier->StopNotifications(); + } + Cancel(); + // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate + iHandleStateNotificationsFromManager = true; + emitSessionClosed = true; // Emit SessionClosed after state change has been reported + } + + bool retVal = false; + if (accessPointId == 0) { + state = newState; +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed A to: " << state; +#endif + emit stateChanged(state); + retVal = true; + } else { + if (publicConfig.type() == QNetworkConfiguration::InternetAccessPoint) { + SymbianNetworkConfigurationPrivate *symbianConfig = + toSymbianConfig(privateConfiguration(publicConfig)); + + if (symbianConfig->numericIdentifier() == accessPointId) { + state = newState; +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed B to: " << state; +#endif + emit stateChanged(state); + retVal = true; + } + } else if (publicConfig.type() == QNetworkConfiguration::UserChoice && isOpen) { + SymbianNetworkConfigurationPrivate *symbianConfig = + toSymbianConfig(privateConfiguration(activeConfig)); + + if (symbianConfig->numericIdentifier() == accessPointId) { + state = newState; +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed C to: " << state; +#endif + emit stateChanged(state); + retVal = true; + } + } else if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) { + QList<QNetworkConfiguration> subConfigurations = publicConfig.children(); + for (int i = 0; i < subConfigurations.count(); i++) { + SymbianNetworkConfigurationPrivate *symbianConfig = + toSymbianConfig(privateConfiguration(subConfigurations[i])); + + if (symbianConfig->numericIdentifier() == accessPointId) { + if (newState != QNetworkSession::Disconnected) { + state = newState; +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed D to: " << state; +#endif + emit stateChanged(state); + retVal = true; + } else { + QNetworkConfiguration config = bestConfigFromSNAP(publicConfig); + if ((config.state() == QNetworkConfiguration::Defined) || + (config.state() == QNetworkConfiguration::Discovered)) { + activeConfig = QNetworkConfiguration(); + state = newState; +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed E to: " << state; +#endif + emit stateChanged(state); + retVal = true; + } else if (config.state() == QNetworkConfiguration::Active) { + // Connection to used IAP was closed, but there is another + // IAP that's active in used SNAP + // => Change state back to Connected + state = QNetworkSession::Connected; + emit stateChanged(state); + retVal = true; +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed F to: " << state; +#endif + } + } + } + } +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + // If the retVal is not true here, it means that the status update may apply to an IAP outside of + // SNAP (session is based on SNAP but follows IAP outside of it), which may occur on Symbian^3 EasyWlan. + if (retVal == false && activeConfig.isValid() && + toSymbianConfig(privateConfiguration(activeConfig))->numericIdentifier() == accessPointId) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed G to: " << state; +#endif + if (newState == QNetworkSession::Disconnected) { + activeConfig = QNetworkConfiguration(); + } + state = newState; + emit stateChanged(state); + retVal = true; + } +#endif + } + } + if (emitSessionClosed) { + emit closed(); + } + if (state == QNetworkSession::Disconnected) { + // Just in case clear activeConfiguration. + activeConfig = QNetworkConfiguration(); + } + return retVal; +} + +void QNetworkSessionPrivateImpl::handleSymbianConnectionStatusChange(TInt aConnectionStatus, + TInt aError, + TUint accessPointId) +{ +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << QString::number(accessPointId) << " , status : " << QString::number(aConnectionStatus); +#endif + switch (aConnectionStatus) + { + // Connection unitialised + case KConnectionUninitialised: + break; + + // Starting connetion selection + case KStartingSelection: + break; + + // Selection finished + case KFinishedSelection: + if (aError == KErrNone) + { + break; + } + else + { + // The user pressed e.g. "Cancel" and did not select an IAP + newState(QNetworkSession::Disconnected,accessPointId); + } + break; + + // Connection failure + case KConnectionFailure: + newState(QNetworkSession::NotAvailable); + break; + + // Prepearing connection (e.g. dialing) + case KPsdStartingConfiguration: + case KPsdFinishedConfiguration: + case KCsdFinishedDialling: + case KCsdScanningScript: + case KCsdGettingLoginInfo: + case KCsdGotLoginInfo: + break; + + case KConfigDaemonStartingRegistration: + // Creating connection (e.g. GPRS activation) + case KCsdStartingConnect: + case KCsdFinishedConnect: + newState(QNetworkSession::Connecting,accessPointId); + break; + + // Starting log in + case KCsdStartingLogIn: + break; + + // Finished login + case KCsdFinishedLogIn: + break; + + // Connection open + case KConnectionOpen: + break; + + case KLinkLayerOpen: + newState(QNetworkSession::Connected,accessPointId); + break; + + // Connection blocked or suspended + case KDataTransferTemporarilyBlocked: + break; + + case KConfigDaemonStartingDeregistration: + // Hangup or GRPS deactivation + case KConnectionStartingClose: + newState(QNetworkSession::Closing,accessPointId); + break; + + // Connection closed + case KConnectionClosed: + case KLinkLayerClosed: + newState(QNetworkSession::Disconnected,accessPointId); + // Report manager about this to make sure this event + // is received by all interseted parties (mediated by + // manager because it does always receive all events from + // connection monitor). +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "reporting disconnection to manager."; +#endif + if (publicConfig.isValid()) { + SymbianNetworkConfigurationPrivate *symbianConfig = + toSymbianConfig(privateConfiguration(publicConfig)); + + engine->configurationStateChangeReport(symbianConfig->numericIdentifier(), + QNetworkSession::Disconnected); + } + break; + // Unhandled state + default: + break; + } +} + +#if defined(SNAP_FUNCTIONALITY_AVAILABLE) +bool QNetworkSessionPrivateImpl::easyWlanTrueIapId(TUint32 &trueIapId) const +{ + RCmManager iCmManager; + TRAPD(err, iCmManager.OpenL()); + if (err != KErrNone) + return false; + + // Check if this is easy wlan id in the first place + if (trueIapId != iCmManager.EasyWlanIdL()) { + iCmManager.Close(); + return false; + } + + iCmManager.Close(); + + // Loop through all connections that connection monitor is aware + // and check for IAPs based on easy WLAN + TRequestStatus status; + TUint connectionCount; + iConnectionMonitor.GetConnectionCount(connectionCount, status); + User::WaitForRequest(status); + TUint connectionId; + TUint subConnectionCount; + TUint apId; + if (status.Int() == KErrNone) { + for (TUint i = 1; i <= connectionCount; i++) { + iConnectionMonitor.GetConnectionInfo(i, connectionId, subConnectionCount); + iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, + KIAPId, apId, status); + User::WaitForRequest(status); + if (apId == trueIapId) { + TBuf<50>easyWlanNetworkName; + iConnectionMonitor.GetStringAttribute(connectionId, 0, KNetworkName, + easyWlanNetworkName, status); + User::WaitForRequest(status); + if (status.Int() != KErrNone) + continue; + + const QString ssid = QString::fromUtf16(easyWlanNetworkName.Ptr(), + easyWlanNetworkName.Length()); + + QNetworkConfigurationPrivatePointer ptr = engine->configurationFromSsid(ssid); + if (ptr) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNCM easyWlanTrueIapId(), found true IAP ID: " + << toSymbianConfig(ptr)->numericIdentifier(); +#endif + trueIapId = toSymbianConfig(ptr)->numericIdentifier(); + return true; + } + } + } + } + return false; +} +#endif + +ConnectionProgressNotifier::ConnectionProgressNotifier(QNetworkSessionPrivateImpl& owner, RConnection& connection) + : CActive(CActive::EPriorityUserInput), iOwner(owner), iConnection(connection) +{ + CActiveScheduler::Add(this); +} + +ConnectionProgressNotifier::~ConnectionProgressNotifier() +{ + Cancel(); +} + +void ConnectionProgressNotifier::StartNotifications() +{ + if (!IsActive()) { + SetActive(); + } + iConnection.ProgressNotification(iProgress, iStatus); +} + +void ConnectionProgressNotifier::StopNotifications() +{ + Cancel(); +} + +void ConnectionProgressNotifier::DoCancel() +{ + iConnection.CancelProgressNotification(); +} + +void ConnectionProgressNotifier::RunL() +{ + if (iStatus == KErrNone) { + QT_TRYCATCH_LEAVING(iOwner.handleSymbianConnectionStatusChange(iProgress().iStage, iProgress().iError)); + + SetActive(); + iConnection.ProgressNotification(iProgress, iStatus); + } +} + +QT_END_NAMESPACE + +#endif //QT_NO_BEARERMANAGEMENT + diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.h b/src/plugins/bearer/symbian/qnetworksession_impl.h new file mode 100644 index 0000000..8e3e997 --- /dev/null +++ b/src/plugins/bearer/symbian/qnetworksession_impl.h @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNETWORKSESSION_IMPL_H +#define QNETWORKSESSION_IMPL_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtNetwork/private/qnetworksession_p.h> + +#include <QDateTime> + +#include <e32base.h> +#include <commdbconnpref.h> +#include <es_sock.h> +#include <rconnmon.h> +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + #include <comms-infras/cs_mobility_apiext.h> +#endif + +QT_BEGIN_NAMESPACE + +class ConnectionProgressNotifier; +class SymbianEngine; + +typedef void (*TOpenCUnSetdefaultifFunction)(); + +class QNetworkSessionPrivateImpl : public QNetworkSessionPrivate, public CActive +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + , public MMobilityProtocolResp +#endif +{ + Q_OBJECT +public: + QNetworkSessionPrivateImpl(SymbianEngine *engine); + ~QNetworkSessionPrivateImpl(); + + //called by QNetworkSession constructor and ensures + //that the state is immediately updated (w/o actually opening + //a session). Also this function should take care of + //notification hooks to discover future state changes. + void syncStateWithInterface(); + +#ifndef QT_NO_NETWORKINTERFACE + QNetworkInterface currentInterface() const; +#endif + QVariant sessionProperty(const QString& key) const; + void setSessionProperty(const QString& key, const QVariant& value); + + void setALREnabled(bool enabled); + + void open(); + inline void close() { close(true); } + void close(bool allowSignals); + void stop(); + void migrate(); + void accept(); + void ignore(); + void reject(); + + QString errorString() const; //must return translated string + QNetworkSession::SessionError error() const; + + quint64 bytesWritten() const; + quint64 bytesReceived() const; + quint64 activeTime() const; + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE +public: // From MMobilityProtocolResp + void PreferredCarrierAvailable(TAccessPointInfo aOldAPInfo, + TAccessPointInfo aNewAPInfo, + TBool aIsUpgrade, + TBool aIsSeamless); + + void NewCarrierActive(TAccessPointInfo aNewAPInfo, TBool aIsSeamless); + + void Error(TInt aError); +#endif + +protected: // From CActive + void RunL(); + void DoCancel(); + +private Q_SLOTS: + void configurationStateChanged(quint32 accessPointId, quint32 connMonId, + QNetworkSession::State newState); + void configurationRemoved(QNetworkConfigurationPrivatePointer config); + void configurationAdded(QNetworkConfigurationPrivatePointer config); + +private: + TUint iapClientCount(TUint aIAPId) const; + quint64 transferredData(TUint dataType) const; + bool newState(QNetworkSession::State newState, TUint accessPointId = 0); + void handleSymbianConnectionStatusChange(TInt aConnectionStatus, TInt aError, TUint accessPointId = 0); + QNetworkConfiguration bestConfigFromSNAP(const QNetworkConfiguration& snapConfig) const; + QNetworkConfiguration activeConfiguration(TUint32 iapId = 0) const; +#ifndef QT_NO_NETWORKINTERFACE + QNetworkInterface interface(TUint iapId) const; +#endif + +#if defined(SNAP_FUNCTIONALITY_AVAILABLE) + bool easyWlanTrueIapId(TUint32 &trueIapId) const; +#endif + + +private: // data + SymbianEngine *engine; + +#ifndef QT_NO_NETWORKINTERFACE + mutable QNetworkInterface activeInterface; +#endif + + QDateTime startTime; + + RLibrary iOpenCLibrary; + TOpenCUnSetdefaultifFunction iDynamicUnSetdefaultif; + + mutable RSocketServ iSocketServ; + mutable RConnection iConnection; + mutable RConnectionMonitor iConnectionMonitor; + ConnectionProgressNotifier* ipConnectionNotifier; + + bool iHandleStateNotificationsFromManager; + bool iFirstSync; + bool iStoppedByUser; + bool iClosedByUser; + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + CActiveCommsMobilityApiExt* iMobility; +#endif + + QNetworkSession::SessionError iError; + TInt iALREnabled; + TBool iALRUpgradingConnection; + TBool iConnectInBackground; + + QList<QString> iKnownConfigsBeforeConnectionStart; + + TUint32 iOldRoamingIap; + TUint32 iNewRoamingIap; + + bool isOpening; + + friend class ConnectionProgressNotifier; +}; + +class ConnectionProgressNotifier : public CActive +{ +public: + ConnectionProgressNotifier(QNetworkSessionPrivateImpl &owner, RConnection &connection); + ~ConnectionProgressNotifier(); + + void StartNotifications(); + void StopNotifications(); + +protected: // From CActive + void RunL(); + void DoCancel(); + +private: // Data + QNetworkSessionPrivateImpl &iOwner; + RConnection& iConnection; + TNifProgressBuf iProgress; + +}; + +QT_END_NAMESPACE + +#endif //QNETWORKSESSION_IMPL_H + diff --git a/src/plugins/bearer/symbian/symbian.pri b/src/plugins/bearer/symbian/symbian.pri new file mode 100644 index 0000000..8d92f57 --- /dev/null +++ b/src/plugins/bearer/symbian/symbian.pri @@ -0,0 +1,32 @@ +TARGET = qsymbianbearer +include(../../qpluginbase.pri) + +QT = core network + +HEADERS += ../symbianengine.h \ + ../qnetworksession_impl.h + +SOURCES += ../symbianengine.cpp \ + ../qnetworksession_impl.cpp \ + ../main.cpp + +INCLUDEPATH += $$APP_LAYER_SYSTEMINCLUDE +symbian-abld:INCLUDEPATH += $$QT_BUILD_TREE/include/QtNetwork/private + +LIBS += -lcommdb \ + -lcentralrepository \ + -lesock \ + -linsock \ + -lecom \ + -lefsrv \ + -lnetmeta + +is_using_gnupoc { + LIBS += -lconnmon +} else { + LIBS += -lConnMon +} + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/bearer +target.path += $$[QT_INSTALL_PLUGINS]/bearer +INSTALLS += target diff --git a/src/plugins/bearer/symbian/symbian.pro b/src/plugins/bearer/symbian/symbian.pro new file mode 100644 index 0000000..91f8217 --- /dev/null +++ b/src/plugins/bearer/symbian/symbian.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs + +contains(S60_VERSION, 3.1)|contains(S60_VERSION, 3.2)|contains(S60_VERSION, 5.0) { + SUBDIRS += 3_1 3_2 +} + +# Symbian3 builds the default plugin for winscw so it is always needed +SUBDIRS += symbian_3
\ No newline at end of file diff --git a/src/plugins/bearer/symbian/symbian_3/symbian_3.pro b/src/plugins/bearer/symbian/symbian_3/symbian_3.pro new file mode 100644 index 0000000..ef90ad2 --- /dev/null +++ b/src/plugins/bearer/symbian/symbian_3/symbian_3.pro @@ -0,0 +1,21 @@ +include(../symbian.pri) + +symbian { + contains(S60_VERSION, 3.1) { + is_using_gnupoc { + LIBS += -lapengine + } else { + LIBS += -lAPEngine + } + } else { + DEFINES += SNAP_FUNCTIONALITY_AVAILABLE + LIBS += -lcmmanager + + !contains(S60_VERSION, 3.2):!contains(S60_VERSION, 5.0) { + DEFINES += OCC_FUNCTIONALITY_AVAILABLE + LIBS += -lextendedconnpref + } + } +} + +TARGET.UID3 = 0x20021319 diff --git a/src/plugins/bearer/symbian/symbianengine.cpp b/src/plugins/bearer/symbian/symbianengine.cpp new file mode 100644 index 0000000..33fa508 --- /dev/null +++ b/src/plugins/bearer/symbian/symbianengine.cpp @@ -0,0 +1,1407 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "symbianengine.h" +#include "qnetworksession_impl.h" + +#include <commdb.h> +#include <cdbcols.h> +#include <d32dbms.h> +#include <nifvar.h> +#include <QTimer> +#include <QTime> // For randgen seeding +#include <QtCore> // For randgen seeding + + +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG +#include <QDebug> +#endif + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + #include <cmdestination.h> + #include <cmconnectionmethod.h> + #include <cmconnectionmethoddef.h> + #include <cmpluginwlandef.h> + #include <cmpluginpacketdatadef.h> + #include <cmplugindialcommondefs.h> +#else + #include <ApAccessPointItem.h> + #include <ApDataHandler.h> + #include <ApUtils.h> +#endif + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +static const int KUserChoiceIAPId = 0; + +SymbianNetworkConfigurationPrivate::SymbianNetworkConfigurationPrivate() +: numericId(0), connectionId(0) +{ +} + +SymbianNetworkConfigurationPrivate::~SymbianNetworkConfigurationPrivate() +{ +} + +SymbianEngine::SymbianEngine(QObject *parent) +: QBearerEngine(parent), CActive(CActive::EPriorityHigh), iFirstUpdate(true), ipCommsDB(0), + iInitOk(true), iUpdatePending(false), ipAccessPointsAvailabilityScanner(0) +{ +} + +void SymbianEngine::initialize() +{ + QMutexLocker locker(&mutex); + + CActiveScheduler::Add(this); + + // Seed the randomgenerator + qsrand(QTime(0,0,0).secsTo(QTime::currentTime()) + QCoreApplication::applicationPid()); + + TRAPD(error, ipCommsDB = CCommsDatabase::NewL(EDatabaseTypeIAP)); + if (error != KErrNone) { + iInitOk = false; + return; + } + + TRAP_IGNORE(iConnectionMonitor.ConnectL()); +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + TRAP_IGNORE(iConnectionMonitor.SetUintAttribute(EBearerIdAll, 0, KBearerGroupThreshold, 1)); +#endif + TRAP_IGNORE(iConnectionMonitor.NotifyEventL(*this)); + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + TRAP(error, iCmManager.OpenL()); + if (error != KErrNone) { + iInitOk = false; + return; + } +#endif + + SymbianNetworkConfigurationPrivate *cpPriv = new SymbianNetworkConfigurationPrivate; + cpPriv->name = "UserChoice"; + cpPriv->bearerType = QNetworkConfiguration::BearerUnknown; + cpPriv->state = QNetworkConfiguration::Discovered; + cpPriv->isValid = true; + cpPriv->id = QString::number(qHash(KUserChoiceIAPId)); + cpPriv->numericId = KUserChoiceIAPId; + cpPriv->connectionId = 0; + cpPriv->type = QNetworkConfiguration::UserChoice; + cpPriv->purpose = QNetworkConfiguration::UnknownPurpose; + cpPriv->roamingSupported = false; + + QNetworkConfigurationPrivatePointer ptr(cpPriv); + userChoiceConfigurations.insert(ptr->id, ptr); + + updateConfigurations(); + updateStatesToSnaps(); + updateAvailableAccessPoints(); // On first time updates (without WLAN scans) + // Start monitoring IAP and/or SNAP changes in Symbian CommsDB + startCommsDatabaseNotifications(); +} + +SymbianEngine::~SymbianEngine() +{ + Cancel(); + + iConnectionMonitor.CancelNotifications(); + iConnectionMonitor.Close(); + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + iCmManager.Close(); +#endif + + delete ipAccessPointsAvailabilityScanner; + + // CCommsDatabase destructor uses cleanup stack. Since QNetworkConfigurationManager + // is a global static, but the time we are here, E32Main() has been exited already and + // the thread's default cleanup stack has been deleted. Without this line, a + // 'E32USER-CBase 69' -panic will occur. + CTrapCleanup* cleanup = CTrapCleanup::New(); + delete ipCommsDB; + delete cleanup; +} + +void SymbianEngine::delayedConfigurationUpdate() +{ + QMutexLocker locker(&mutex); + + if (iUpdatePending) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug("QNCM delayed configuration update (ECommit or ERecover occurred)."); +#endif + TRAPD(error, updateConfigurationsL()); + if (error == KErrNone) { + updateStatesToSnaps(); + } + iUpdatePending = false; + // Start monitoring again. + if (!IsActive()) { + SetActive(); + // Start waiting for new notification + ipCommsDB->RequestNotification(iStatus); + } + } +} + +bool SymbianEngine::hasIdentifier(const QString &id) +{ + QMutexLocker locker(&mutex); + + return accessPointConfigurations.contains(id) || + snapConfigurations.contains(id) || + userChoiceConfigurations.contains(id); +} + +QNetworkConfigurationManager::Capabilities SymbianEngine::capabilities() const +{ + QNetworkConfigurationManager::Capabilities capFlags; + + capFlags = QNetworkConfigurationManager::CanStartAndStopInterfaces | + QNetworkConfigurationManager::DirectConnectionRouting | + QNetworkConfigurationManager::SystemSessionSupport | + QNetworkConfigurationManager::DataStatistics | + QNetworkConfigurationManager::NetworkSessionRequired; + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + capFlags |= QNetworkConfigurationManager::ApplicationLevelRoaming | + QNetworkConfigurationManager::ForcedRoaming; +#endif + + return capFlags; +} + +QNetworkSessionPrivate *SymbianEngine::createSessionBackend() +{ + return new QNetworkSessionPrivateImpl(this); +} + +void SymbianEngine::requestUpdate() +{ + QMutexLocker locker(&mutex); + + if (!iInitOk || iUpdateGoingOn) { + return; + } + iUpdateGoingOn = true; + + stopCommsDatabaseNotifications(); + updateConfigurations(); // Synchronous call + updateAvailableAccessPoints(); // Asynchronous call +} + +void SymbianEngine::updateConfigurations() +{ + if (!iInitOk) + return; + + TRAP_IGNORE(updateConfigurationsL()); +} + +void SymbianEngine::updateConfigurationsL() +{ + QList<QString> knownConfigs = accessPointConfigurations.keys(); + QList<QString> knownSnapConfigs = snapConfigurations.keys(); + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + // S60 version is >= Series60 3rd Edition Feature Pack 2 + TInt error = KErrNone; + + // Loop through all IAPs + RArray<TUint32> connectionMethods; // IAPs + CleanupClosePushL(connectionMethods); + iCmManager.ConnectionMethodL(connectionMethods); + for(int i = 0; i < connectionMethods.Count(); i++) { + RCmConnectionMethod connectionMethod = iCmManager.ConnectionMethodL(connectionMethods[i]); + CleanupClosePushL(connectionMethod); + TUint32 iapId = connectionMethod.GetIntAttributeL(CMManager::ECmIapId); + QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId)); + if (accessPointConfigurations.contains(ident)) { + knownConfigs.removeOne(ident); + } else { + SymbianNetworkConfigurationPrivate* cpPriv = NULL; + TRAP(error, cpPriv = configFromConnectionMethodL(connectionMethod)); + if (error == KErrNone) { + QNetworkConfigurationPrivatePointer ptr(cpPriv); + accessPointConfigurations.insert(ptr->id, ptr); + if (!iFirstUpdate) { + // Emit configuration added. Connected slots may throw execptions + // which propagate here --> must be converted to leaves (standard + // std::exception would cause any TRAP trapping this function to terminate + // program). + QT_TRYCATCH_LEAVING(updateActiveAccessPoints()); + updateStatesToSnaps(); + mutex.unlock(); + QT_TRYCATCH_LEAVING(emit configurationAdded(ptr)); + mutex.lock(); + } + } + } + CleanupStack::PopAndDestroy(&connectionMethod); + } + CleanupStack::PopAndDestroy(&connectionMethods); + + // Loop through all SNAPs + RArray<TUint32> destinations; + CleanupClosePushL(destinations); + iCmManager.AllDestinationsL(destinations); + for(int i = 0; i < destinations.Count(); i++) { + RCmDestination destination; + + // Some destinatsions require ReadDeviceData -capability (MMS/WAP) + // The below function will leave in these cases. Don't. Proceed to + // next destination (if any). + TRAPD(error, destination = iCmManager.DestinationL(destinations[i])); + if (error == KErrPermissionDenied) { + continue; + } else { + User::LeaveIfError(error); + } + + CleanupClosePushL(destination); + QString ident = QT_BEARERMGMT_CONFIGURATION_SNAP_PREFIX + + QString::number(qHash(destination.Id())); + if (snapConfigurations.contains(ident)) { + knownSnapConfigs.removeOne(ident); + } else { + SymbianNetworkConfigurationPrivate *cpPriv = new SymbianNetworkConfigurationPrivate; + + HBufC *pName = destination.NameLC(); + QT_TRYCATCH_LEAVING(cpPriv->name = QString::fromUtf16(pName->Ptr(),pName->Length())); + CleanupStack::PopAndDestroy(pName); + pName = NULL; + + cpPriv->isValid = true; + cpPriv->id = ident; + cpPriv->numericId = destination.Id(); + cpPriv->connectionId = 0; + cpPriv->state = QNetworkConfiguration::Defined; + cpPriv->type = QNetworkConfiguration::ServiceNetwork; + cpPriv->purpose = QNetworkConfiguration::UnknownPurpose; + cpPriv->roamingSupported = false; + + QNetworkConfigurationPrivatePointer ptr(cpPriv); + snapConfigurations.insert(ident, ptr); + if (!iFirstUpdate) { + QT_TRYCATCH_LEAVING(updateActiveAccessPoints()); + updateStatesToSnaps(); + mutex.unlock(); + QT_TRYCATCH_LEAVING(emit configurationAdded(ptr)); + mutex.lock(); + } + } + + // Loop through all connection methods in this SNAP + QMap<unsigned int, QNetworkConfigurationPrivatePointer> connections; + for (int j=0; j < destination.ConnectionMethodCount(); j++) { + RCmConnectionMethod connectionMethod = destination.ConnectionMethodL(j); + CleanupClosePushL(connectionMethod); + + TUint32 iapId = connectionMethod.GetIntAttributeL(CMManager::ECmIapId); + QString iface = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId)); + // Check that IAP can be found from accessPointConfigurations list + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iface); + if (!ptr) { + SymbianNetworkConfigurationPrivate *cpPriv = NULL; + TRAP(error, cpPriv = configFromConnectionMethodL(connectionMethod)); + if (error == KErrNone) { + ptr = QNetworkConfigurationPrivatePointer(cpPriv); + accessPointConfigurations.insert(ptr->id, ptr); + + if (!iFirstUpdate) { + QT_TRYCATCH_LEAVING(updateActiveAccessPoints()); + updateStatesToSnaps(); + mutex.unlock(); + QT_TRYCATCH_LEAVING(emit configurationAdded(ptr)); + mutex.lock(); + } + } + } else { + knownConfigs.removeOne(iface); + } + + if (ptr) { + unsigned int priority; + TRAPD(error, priority = destination.PriorityL(connectionMethod)); + if (!error) + connections.insert(priority, ptr); + } + + CleanupStack::PopAndDestroy(&connectionMethod); + } + + QNetworkConfigurationPrivatePointer privSNAP = snapConfigurations.value(ident); + QMutexLocker snapConfigLocker(&privSNAP->mutex); + + if (privSNAP->serviceNetworkMembers != connections) { + privSNAP->serviceNetworkMembers = connections; + + // Roaming is supported only if SNAP contains more than one IAP + privSNAP->roamingSupported = privSNAP->serviceNetworkMembers.count() > 1; + + snapConfigLocker.unlock(); + + updateStatesToSnaps(); + + mutex.unlock(); + QT_TRYCATCH_LEAVING(emit configurationChanged(privSNAP)); + mutex.lock(); + } + + CleanupStack::PopAndDestroy(&destination); + } + CleanupStack::PopAndDestroy(&destinations); +#else + // S60 version is < Series60 3rd Edition Feature Pack 2 + CCommsDbTableView* pDbTView = ipCommsDB->OpenTableLC(TPtrC(IAP)); + + // Loop through all IAPs + TUint32 apId = 0; + TInt retVal = pDbTView->GotoFirstRecord(); + while (retVal == KErrNone) { + pDbTView->ReadUintL(TPtrC(COMMDB_ID), apId); + QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(apId)); + if (accessPointConfigurations.contains(ident)) { + knownConfigs.removeOne(ident); + } else { + SymbianNetworkConfigurationPrivate *cpPriv = new SymbianNetworkConfigurationPrivate; + if (readNetworkConfigurationValuesFromCommsDb(apId, cpPriv)) { + QNetworkConfigurationPrivatePointer ptr(cpPriv); + accessPointConfigurations.insert(ident, ptr); + if (!iFirstUpdate) { + QT_TRYCATCH_LEAVING(updateActiveAccessPoints()); + updateStatesToSnaps(); + mutex.unlock(); + QT_TRYCATCH_LEAVING(emit configurationAdded(ptr)); + mutex.lock(); + } + } else { + delete cpPriv; + } + } + retVal = pDbTView->GotoNextRecord(); + } + CleanupStack::PopAndDestroy(pDbTView); +#endif + + QT_TRYCATCH_LEAVING(updateActiveAccessPoints()); + + foreach (const QString &oldIface, knownConfigs) { + //remove non existing IAP + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(oldIface); + + mutex.unlock(); + emit configurationRemoved(ptr); + QT_TRYCATCH_LEAVING(emit configurationRemoved(ptr)); + mutex.lock(); + + // Remove non existing IAP from SNAPs + foreach (const QString &iface, snapConfigurations.keys()) { + QNetworkConfigurationPrivatePointer ptr2 = snapConfigurations.value(iface); + // => Check if one of the IAPs of the SNAP is active + QMutexLocker snapConfigLocker(&ptr2->mutex); + QMutableMapIterator<unsigned int, QNetworkConfigurationPrivatePointer> i(ptr2->serviceNetworkMembers); + while (i.hasNext()) { + i.next(); + + if (toSymbianConfig(i.value())->numericIdentifier() == + toSymbianConfig(ptr)->numericIdentifier()) { + i.remove(); + break; + } + } + } + } + + foreach (const QString &oldIface, knownSnapConfigs) { + //remove non existing SNAPs + QNetworkConfigurationPrivatePointer ptr = snapConfigurations.take(oldIface); + + mutex.unlock(); + emit configurationRemoved(ptr); + QT_TRYCATCH_LEAVING(emit configurationRemoved(ptr)); + mutex.lock(); + } + + // find default configuration. + stopCommsDatabaseNotifications(); + TRAP_IGNORE(defaultConfig = defaultConfigurationL()); + startCommsDatabaseNotifications(); + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + updateStatesToSnaps(); +#endif +} + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE +SymbianNetworkConfigurationPrivate *SymbianEngine::configFromConnectionMethodL( + RCmConnectionMethod& connectionMethod) +{ + SymbianNetworkConfigurationPrivate *cpPriv = new SymbianNetworkConfigurationPrivate; + TUint32 iapId = connectionMethod.GetIntAttributeL(CMManager::ECmIapId); + QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId)); + + HBufC *pName = connectionMethod.GetStringAttributeL(CMManager::ECmName); + CleanupStack::PushL(pName); + QT_TRYCATCH_LEAVING(cpPriv->name = QString::fromUtf16(pName->Ptr(),pName->Length())); + CleanupStack::PopAndDestroy(pName); + pName = NULL; + + TUint32 bearerId = connectionMethod.GetIntAttributeL(CMManager::ECmCommsDBBearerType); + switch (bearerId) { + case KCommDbBearerCSD: + cpPriv->bearerType = QNetworkConfiguration::Bearer2G; + break; + case KCommDbBearerWcdma: + cpPriv->bearerType = QNetworkConfiguration::BearerWCDMA; + break; + case KCommDbBearerLAN: + cpPriv->bearerType = QNetworkConfiguration::BearerEthernet; + break; + case KCommDbBearerVirtual: + cpPriv->bearerType = QNetworkConfiguration::BearerUnknown; + break; + case KCommDbBearerPAN: + cpPriv->bearerType = QNetworkConfiguration::BearerUnknown; + break; + case KCommDbBearerWLAN: + cpPriv->bearerType = QNetworkConfiguration::BearerWLAN; + break; + default: + cpPriv->bearerType = QNetworkConfiguration::BearerUnknown; + break; + } + + TInt error = KErrNone; + TUint32 bearerType = connectionMethod.GetIntAttributeL(CMManager::ECmBearerType); + switch (bearerType) { + case KUidPacketDataBearerType: + // "Packet data" Bearer => Mapping is done using "Access point name" + TRAP(error, pName = connectionMethod.GetStringAttributeL(CMManager::EPacketDataAPName)); + break; + case KUidWlanBearerType: + // "Wireless LAN" Bearer => Mapping is done using "WLAN network name" = SSID + TRAP(error, pName = connectionMethod.GetStringAttributeL(CMManager::EWlanSSID)); + break; + } + if (!pName) { + // "Data call" Bearer or "High Speed (GSM)" Bearer => Mapping is done using "Dial-up number" + TRAP(error, pName = connectionMethod.GetStringAttributeL(CMManager::EDialDefaultTelNum)); + } + + if (error == KErrNone && pName) { + CleanupStack::PushL(pName); + QT_TRYCATCH_LEAVING(cpPriv->mappingName = QString::fromUtf16(pName->Ptr(),pName->Length())); + CleanupStack::PopAndDestroy(pName); + pName = NULL; + } + + cpPriv->state = QNetworkConfiguration::Defined; + TBool isConnected = connectionMethod.GetBoolAttributeL(CMManager::ECmConnected); + if (isConnected) { + cpPriv->state = QNetworkConfiguration::Active; + } + + cpPriv->isValid = true; + cpPriv->id = ident; + cpPriv->numericId = iapId; + cpPriv->connectionId = 0; + cpPriv->type = QNetworkConfiguration::InternetAccessPoint; + cpPriv->purpose = QNetworkConfiguration::UnknownPurpose; + cpPriv->roamingSupported = false; + return cpPriv; +} +#else +bool SymbianEngine::readNetworkConfigurationValuesFromCommsDb( + TUint32 aApId, SymbianNetworkConfigurationPrivate *apNetworkConfiguration) +{ + TRAPD(error, readNetworkConfigurationValuesFromCommsDbL(aApId,apNetworkConfiguration)); + if (error != KErrNone) { + return false; + } + return true; +} + +void SymbianEngine::readNetworkConfigurationValuesFromCommsDbL( + TUint32 aApId, SymbianNetworkConfigurationPrivate *apNetworkConfiguration) +{ + CApDataHandler* pDataHandler = CApDataHandler::NewLC(*ipCommsDB); + CApAccessPointItem* pAPItem = CApAccessPointItem::NewLC(); + TBuf<KCommsDbSvrMaxColumnNameLength> name; + + CApUtils* pApUtils = CApUtils::NewLC(*ipCommsDB); + TUint32 apId = pApUtils->WapIdFromIapIdL(aApId); + + pDataHandler->AccessPointDataL(apId,*pAPItem); + pAPItem->ReadTextL(EApIapName, name); + if (name.Compare(_L("Easy WLAN")) == 0) { + // "Easy WLAN" won't be accepted to the Configurations list + User::Leave(KErrNotFound); + } + + QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(aApId)); + + QT_TRYCATCH_LEAVING(apNetworkConfiguration->name = QString::fromUtf16(name.Ptr(),name.Length())); + apNetworkConfiguration->isValid = true; + apNetworkConfiguration->id = ident; + apNetworkConfiguration->numericId = aApId; + apNetworkConfiguration->connectionId = 0; + apNetworkConfiguration->state = (QNetworkConfiguration::Defined); + apNetworkConfiguration->type = QNetworkConfiguration::InternetAccessPoint; + apNetworkConfiguration->purpose = QNetworkConfiguration::UnknownPurpose; + apNetworkConfiguration->roamingSupported = false; + switch (pAPItem->BearerTypeL()) { + case EApBearerTypeCSD: + apNetworkConfiguration->bearerType = QNetworkConfiguration::Bearer2G; + break; + case EApBearerTypeGPRS: + apNetworkConfiguration->bearerType = QNetworkConfiguration::Bearer2G; + break; + case EApBearerTypeHSCSD: + apNetworkConfiguration->bearerType = QNetworkConfiguration::BearerHSPA; + break; + case EApBearerTypeCDMA: + apNetworkConfiguration->bearerType = QNetworkConfiguration::BearerCDMA2000; + break; + case EApBearerTypeWLAN: + apNetworkConfiguration->bearerType = QNetworkConfiguration::BearerWLAN; + break; + case EApBearerTypeLAN: + apNetworkConfiguration->bearerType = QNetworkConfiguration::BearerEthernet; + break; + case EApBearerTypeLANModem: + apNetworkConfiguration->bearerType = QNetworkConfiguration::BearerEthernet; + break; + default: + apNetworkConfiguration->bearerType = QNetworkConfiguration::BearerUnknown; + break; + } + + CleanupStack::PopAndDestroy(pApUtils); + CleanupStack::PopAndDestroy(pAPItem); + CleanupStack::PopAndDestroy(pDataHandler); +} +#endif + +QNetworkConfigurationPrivatePointer SymbianEngine::defaultConfiguration() +{ + QMutexLocker locker(&mutex); + + return defaultConfig; +} + +QStringList SymbianEngine::accessPointConfigurationIdentifiers() +{ + QMutexLocker locker(&mutex); + + return accessPointConfigurations.keys(); +} + +QNetworkConfigurationPrivatePointer SymbianEngine::defaultConfigurationL() +{ + QNetworkConfigurationPrivatePointer ptr; + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + // Check Default Connection (SNAP or IAP) + TCmDefConnValue defaultConnectionValue; + iCmManager.ReadDefConnL(defaultConnectionValue); + if (defaultConnectionValue.iType == ECmDefConnDestination) { + QString iface = QT_BEARERMGMT_CONFIGURATION_SNAP_PREFIX + + QString::number(qHash(defaultConnectionValue.iId)); + ptr = snapConfigurations.value(iface); + } else if (defaultConnectionValue.iType == ECmDefConnConnectionMethod) { + QString iface = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX + + QString::number(qHash(defaultConnectionValue.iId)); + ptr = accessPointConfigurations.value(iface); + } +#endif + + if (ptr) { + QMutexLocker configLocker(&ptr->mutex); + if (ptr->isValid) + return ptr; + } + + QString iface = QString::number(qHash(KUserChoiceIAPId)); + return userChoiceConfigurations.value(iface); +} + +void SymbianEngine::updateActiveAccessPoints() +{ + bool online = false; + QList<QString> inactiveConfigs = accessPointConfigurations.keys(); + + TRequestStatus status; + TUint connectionCount; + iConnectionMonitor.GetConnectionCount(connectionCount, status); + User::WaitForRequest(status); + + // Go through all connections and set state of related IAPs to Active. + // Status needs to be checked carefully, because ConnMon lists also e.g. + // WLAN connections that are being currently tried --> we don't want to + // state these as active. + TUint connectionId; + TUint subConnectionCount; + TUint apId; + TInt connectionStatus; + if (status.Int() == KErrNone) { + for (TUint i = 1; i <= connectionCount; i++) { + iConnectionMonitor.GetConnectionInfo(i, connectionId, subConnectionCount); + iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status); + User::WaitForRequest(status); + QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(apId)); + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident); +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + if (!ptr) { + // If IAP was not found, check if the update was about EasyWLAN + ptr = configurationFromEasyWlan(apId, connectionId); + // Change the ident correspondingly + if (ptr) { + ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX + + QString::number(qHash(toSymbianConfig(ptr)->numericIdentifier())); + } + } +#endif + if (ptr) { + iConnectionMonitor.GetIntAttribute(connectionId, subConnectionCount, KConnectionStatus, connectionStatus, status); + User::WaitForRequest(status); + + if (connectionStatus == KLinkLayerOpen) { + online = true; + inactiveConfigs.removeOne(ident); + + ptr->mutex.lock(); + toSymbianConfig(ptr)->connectionId = connectionId; + ptr->mutex.unlock(); + + // Configuration is Active + changeConfigurationStateTo(ptr, QNetworkConfiguration::Active); + } + } + } + } + + // Make sure that state of rest of the IAPs won't be Active + foreach (const QString &iface, inactiveConfigs) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iface); + if (ptr) { + // Configuration is either Defined or Discovered + changeConfigurationStateAtMaxTo(ptr, QNetworkConfiguration::Discovered); + } + } + + if (iOnline != online) { + iOnline = online; + mutex.unlock(); + emit this->onlineStateChanged(online); + mutex.lock(); + } +} + +void SymbianEngine::updateAvailableAccessPoints() +{ + if (!ipAccessPointsAvailabilityScanner) { + ipAccessPointsAvailabilityScanner = new AccessPointsAvailabilityScanner(*this, iConnectionMonitor); + } + if (ipAccessPointsAvailabilityScanner) { + // Scanning may take a while because WLAN scanning will be done (if device supports WLAN). + ipAccessPointsAvailabilityScanner->StartScanning(); + } +} + +void SymbianEngine::accessPointScanningReady(TBool scanSuccessful, TConnMonIapInfo iapInfo) +{ + iUpdateGoingOn = false; + if (scanSuccessful) { + QList<QString> unavailableConfigs = accessPointConfigurations.keys(); + + // Set state of returned IAPs to Discovered + // if state is not already Active + for(TUint i=0; i<iapInfo.iCount; i++) { + QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX + + QString::number(qHash(iapInfo.iIap[i].iIapId)); + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident); + if (ptr) { + unavailableConfigs.removeOne(ident); + + QMutexLocker configLocker(&ptr->mutex); + if (ptr->state < QNetworkConfiguration::Active) { + // Configuration is either Discovered or Active + changeConfigurationStateAtMinTo(ptr, QNetworkConfiguration::Discovered); + } + } + } + + // Make sure that state of rest of the IAPs won't be Active + foreach (const QString &iface, unavailableConfigs) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iface); + if (ptr) { + // Configuration is Defined + changeConfigurationStateAtMaxTo(ptr, QNetworkConfiguration::Discovered); + } + } + } + + updateStatesToSnaps(); + + if (!iFirstUpdate) { + startCommsDatabaseNotifications(); + mutex.unlock(); + emit updateCompleted(); + mutex.lock(); + } else { + iFirstUpdate = false; + if (iScanInQueue) { + iScanInQueue = EFalse; + updateAvailableAccessPoints(); + } + } +} + +void SymbianEngine::updateStatesToSnaps() +{ + // Go through SNAPs and set correct state to SNAPs + foreach (const QString &iface, snapConfigurations.keys()) { + bool discovered = false; + bool active = false; + QNetworkConfigurationPrivatePointer ptr = snapConfigurations.value(iface); + + QMutexLocker snapConfigLocker(&ptr->mutex); + + // => Check if one of the IAPs of the SNAP is discovered or active + // => If one of IAPs is active, also SNAP is active + // => If one of IAPs is discovered but none of the IAPs is active, SNAP is discovered + QMapIterator<unsigned int, QNetworkConfigurationPrivatePointer> i(ptr->serviceNetworkMembers); + while (i.hasNext()) { + i.next(); + + const QNetworkConfigurationPrivatePointer child = i.value(); + + QMutexLocker configLocker(&child->mutex); + + if ((child->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + active = true; + break; + } else if ((child->state & QNetworkConfiguration::Discovered) == + QNetworkConfiguration::Discovered) { + discovered = true; + } + } + if (active) { + changeConfigurationStateTo(ptr, QNetworkConfiguration::Active); + } else if (discovered) { + changeConfigurationStateTo(ptr, QNetworkConfiguration::Discovered); + } else { + changeConfigurationStateTo(ptr, QNetworkConfiguration::Defined); + } + } +} + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE +void SymbianEngine::updateMobileBearerToConfigs(TConnMonBearerInfo bearerInfo) +{ + QHash<QString, QNetworkConfigurationPrivatePointer>::const_iterator i = + accessPointConfigurations.constBegin(); + while (i != accessPointConfigurations.constEnd()) { + QNetworkConfigurationPrivatePointer ptr = i.value(); + + QMutexLocker locker(&ptr->mutex); + + SymbianNetworkConfigurationPrivate *p = toSymbianConfig(ptr); + + if (p->bearerType >= QNetworkConfiguration::Bearer2G && + p->bearerType <= QNetworkConfiguration::BearerHSPA) { + switch (bearerInfo) { + case EBearerInfoCSD: + p->bearerType = QNetworkConfiguration::Bearer2G; + break; + case EBearerInfoWCDMA: + p->bearerType = QNetworkConfiguration::BearerWCDMA; + break; + case EBearerInfoCDMA2000: + p->bearerType = QNetworkConfiguration::BearerCDMA2000; + break; + case EBearerInfoGPRS: + p->bearerType = QNetworkConfiguration::Bearer2G; + break; + case EBearerInfoHSCSD: + p->bearerType = QNetworkConfiguration::Bearer2G; + break; + case EBearerInfoEdgeGPRS: + p->bearerType = QNetworkConfiguration::Bearer2G; + break; + case EBearerInfoWcdmaCSD: + p->bearerType = QNetworkConfiguration::BearerWCDMA; + break; + case EBearerInfoHSDPA: + p->bearerType = QNetworkConfiguration::BearerHSPA; + break; + case EBearerInfoHSUPA: + p->bearerType = QNetworkConfiguration::BearerHSPA; + break; + case EBearerInfoHSxPA: + p->bearerType = QNetworkConfiguration::BearerHSPA; + break; + } + } + + ++i; + } +} +#endif + +bool SymbianEngine::changeConfigurationStateTo(QNetworkConfigurationPrivatePointer ptr, + QNetworkConfiguration::StateFlags newState) +{ + ptr->mutex.lock(); + if (newState != ptr->state) { + ptr->state = newState; + ptr->mutex.unlock(); + + mutex.unlock(); + emit configurationChanged(ptr); + mutex.lock(); + + return true; + } else { + ptr->mutex.unlock(); + } + return false; +} + +/* changeConfigurationStateAtMinTo function does not overwrite possible better + * state (e.g. Discovered state does not overwrite Active state) but + * makes sure that state is at minimum given state. +*/ +bool SymbianEngine::changeConfigurationStateAtMinTo(QNetworkConfigurationPrivatePointer ptr, + QNetworkConfiguration::StateFlags newState) +{ + ptr->mutex.lock(); + if ((newState | ptr->state) != ptr->state) { + ptr->state = (ptr->state | newState); + ptr->mutex.unlock(); + + mutex.unlock(); + emit configurationChanged(ptr); + mutex.lock(); + + return true; + } else { + ptr->mutex.unlock(); + } + return false; +} + +/* changeConfigurationStateAtMaxTo function overwrites possible better + * state (e.g. Discovered state overwrites Active state) and + * makes sure that state is at maximum given state (e.g. Discovered state + * does not overwrite Defined state). +*/ +bool SymbianEngine::changeConfigurationStateAtMaxTo(QNetworkConfigurationPrivatePointer ptr, + QNetworkConfiguration::StateFlags newState) +{ + ptr->mutex.lock(); + if ((newState & ptr->state) != ptr->state) { + ptr->state = (newState & ptr->state); + ptr->mutex.unlock(); + + mutex.unlock(); + emit configurationChanged(ptr); + mutex.lock(); + + return true; + } else { + ptr->mutex.unlock(); + } + return false; +} + +void SymbianEngine::startCommsDatabaseNotifications() +{ + if (!iWaitingCommsDatabaseNotifications) { + iWaitingCommsDatabaseNotifications = ETrue; + if (!IsActive()) { + SetActive(); + // Start waiting for new notification + ipCommsDB->RequestNotification(iStatus); + } + } +} + +void SymbianEngine::stopCommsDatabaseNotifications() +{ + if (iWaitingCommsDatabaseNotifications) { + iWaitingCommsDatabaseNotifications = EFalse; + Cancel(); + } +} + +void SymbianEngine::RunL() +{ + QMutexLocker locker(&mutex); + + if (iStatus != KErrCancel) { + // By default, start relistening notifications. Stop only if interesting event occured. + iWaitingCommsDatabaseNotifications = true; + RDbNotifier::TEvent event = STATIC_CAST(RDbNotifier::TEvent, iStatus.Int()); + switch (event) { + case RDbNotifier::ECommit: /** A transaction has been committed. */ + case RDbNotifier::ERecover: /** The database has been recovered */ +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug("QNCM CommsDB event (of type RDbNotifier::TEvent) received: %d", iStatus.Int()); +#endif + // Mark that there is update pending. No need to ask more events, + // as we know we will be updating anyway when the timer expires. + if (!iUpdatePending) { + iUpdatePending = true; + iWaitingCommsDatabaseNotifications = false; + // Update after random time, so that many processes won't + // start updating simultaneously + updateConfigurationsAfterRandomTime(); + } + break; + default: + // Do nothing + break; + } + } + + if (iWaitingCommsDatabaseNotifications) { + if (!IsActive()) { + SetActive(); + // Start waiting for new notification + ipCommsDB->RequestNotification(iStatus); + } + } +} + +void SymbianEngine::DoCancel() +{ + QMutexLocker locker(&mutex); + + ipCommsDB->CancelRequestNotification(); +} + +void SymbianEngine::EventL(const CConnMonEventBase& aEvent) +{ + QMutexLocker locker(&mutex); + + switch (aEvent.EventType()) { +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + case EConnMonBearerInfoChange: + { + CConnMonBearerInfoChange* realEvent; + realEvent = (CConnMonBearerInfoChange*) &aEvent; + TUint connectionId = realEvent->ConnectionId(); + if (connectionId == EBearerIdAll) { + //Network level event + TConnMonBearerInfo bearerInfo = (TConnMonBearerInfo)realEvent->BearerInfo(); + updateMobileBearerToConfigs(bearerInfo); + } + break; + } +#endif + case EConnMonConnectionStatusChange: + { + CConnMonConnectionStatusChange* realEvent; + realEvent = (CConnMonConnectionStatusChange*) &aEvent; + TInt connectionStatus = realEvent->ConnectionStatus(); +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNCM Connection status : " << QString::number(connectionStatus) << " , connection monitor Id : " << realEvent->ConnectionId(); +#endif + if (connectionStatus == KConfigDaemonStartingRegistration) { + TUint connectionId = realEvent->ConnectionId(); + TUint subConnectionCount = 0; + TUint apId; + TRequestStatus status; + iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status); + User::WaitForRequest(status); + + QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(apId)); + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident); +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + if (!ptr) { + // Check if status was regarding EasyWLAN + ptr = configurationFromEasyWlan(apId, connectionId); + } +#endif + if (ptr) { + ptr->mutex.lock(); + toSymbianConfig(ptr)->connectionId = connectionId; + ptr->mutex.unlock(); + QT_TRYCATCH_LEAVING( + emit configurationStateChanged(toSymbianConfig(ptr)->numericIdentifier(), + connectionId, QNetworkSession::Connecting) + ); + } + } else if (connectionStatus == KLinkLayerOpen) { + // Connection has been successfully opened + TUint connectionId = realEvent->ConnectionId(); + TUint subConnectionCount = 0; + TUint apId; + TRequestStatus status; + iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status); + User::WaitForRequest(status); + QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(apId)); + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident); +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + if (!ptr) { + // Check for EasyWLAN + ptr = configurationFromEasyWlan(apId, connectionId); + } +#endif + if (ptr) { + ptr->mutex.lock(); + toSymbianConfig(ptr)->connectionId = connectionId; + ptr->mutex.unlock(); + + // Configuration is Active + QT_TRYCATCH_LEAVING( + if (changeConfigurationStateTo(ptr, QNetworkConfiguration::Active)) { + updateStatesToSnaps(); + } + emit configurationStateChanged(toSymbianConfig(ptr)->numericIdentifier(), + connectionId, QNetworkSession::Connected); + + if (!iOnline) { + iOnline = true; + emit this->onlineStateChanged(iOnline); + } + ); + } + } else if (connectionStatus == KConfigDaemonStartingDeregistration) { + TUint connectionId = realEvent->ConnectionId(); + QNetworkConfigurationPrivatePointer ptr = dataByConnectionId(connectionId); + if (ptr) { + QT_TRYCATCH_LEAVING( + emit configurationStateChanged(toSymbianConfig(ptr)->numericIdentifier(), + connectionId, QNetworkSession::Closing) + ); + } + } else if (connectionStatus == KLinkLayerClosed || + connectionStatus == KConnectionClosed) { + // Connection has been closed. Which of the above events is reported, depends on the Symbian + // platform. + TUint connectionId = realEvent->ConnectionId(); + QNetworkConfigurationPrivatePointer ptr = dataByConnectionId(connectionId); + if (ptr) { + // Configuration is either Defined or Discovered + QT_TRYCATCH_LEAVING( + if (changeConfigurationStateAtMaxTo(ptr, QNetworkConfiguration::Discovered)) { + updateStatesToSnaps(); + } + emit configurationStateChanged(toSymbianConfig(ptr)->numericIdentifier(), + connectionId, QNetworkSession::Disconnected); + ); + } + + bool online = false; + foreach (const QString &iface, accessPointConfigurations.keys()) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iface); + QMutexLocker configLocker(&ptr->mutex); + if (ptr->state == QNetworkConfiguration::Active) { + online = true; + break; + } + } + if (iOnline != online) { + iOnline = online; + QT_TRYCATCH_LEAVING(emit this->onlineStateChanged(iOnline)); + } + } + } + break; + + case EConnMonIapAvailabilityChange: + { + CConnMonIapAvailabilityChange* realEvent; + realEvent = (CConnMonIapAvailabilityChange*) &aEvent; + TConnMonIapInfo iaps = realEvent->IapAvailability(); + QList<QString> unDiscoveredConfigs = accessPointConfigurations.keys(); + for ( TUint i = 0; i < iaps.Count(); i++ ) { + QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX + + QString::number(qHash(iaps.iIap[i].iIapId)); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident); + if (ptr) { + // Configuration is either Discovered or Active + QT_TRYCATCH_LEAVING(changeConfigurationStateAtMinTo(ptr, QNetworkConfiguration::Discovered)); + unDiscoveredConfigs.removeOne(ident); + } + } + foreach (const QString &iface, unDiscoveredConfigs) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iface); + if (ptr) { + // Configuration is Defined + QT_TRYCATCH_LEAVING(changeConfigurationStateAtMaxTo(ptr, QNetworkConfiguration::Defined)); + } + } + // Something has in IAPs, update states to SNAPs + updateStatesToSnaps(); + } + break; + + case EConnMonCreateConnection: + { + // This event is caught to keep connection monitor IDs up-to-date. + CConnMonCreateConnection* realEvent; + realEvent = (CConnMonCreateConnection*) &aEvent; + TUint subConnectionCount = 0; + TUint apId; + TUint connectionId = realEvent->ConnectionId(); + TRequestStatus status; + iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status); + User::WaitForRequest(status); + QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(apId)); + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident); +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + if (!ptr) { + // If IAP was not found, check if the update was about EasyWLAN + ptr = configurationFromEasyWlan(apId, connectionId); + } +#endif + if (ptr) { + QMutexLocker configLocker(&ptr->mutex); +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNCM updating connection monitor ID : from, to, whose: " << toSymbianConfig(ptr)->connectionId << connectionId << ptr->name; +#endif + toSymbianConfig(ptr)->connectionId = connectionId; + } + } + break; + default: + // For unrecognized events + break; + } +} + +/* + Returns the network configuration that matches the given SSID. +*/ +QNetworkConfigurationPrivatePointer SymbianEngine::configurationFromSsid(const QString &ssid) +{ + QMutexLocker locker(&mutex); + + // Browser through all items and check their name for match + QHash<QString, QNetworkConfigurationPrivatePointer>::ConstIterator i = + accessPointConfigurations.constBegin(); + while (i != accessPointConfigurations.constEnd()) { + QNetworkConfigurationPrivatePointer ptr = i.value(); + + QMutexLocker configLocker(&ptr->mutex); + + if (ptr->name == ssid) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNCM EasyWlan uses real SSID: " << ssid; +#endif + return ptr; + } + ++i; + } + + return QNetworkConfigurationPrivatePointer(); +} + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE +// Tries to derive configuration from EasyWLAN. +// First checks if the interface brought up was EasyWLAN, then derives the real SSID, +// and looks up configuration based on that one. +QNetworkConfigurationPrivatePointer SymbianEngine::configurationFromEasyWlan(TUint32 apId, + TUint connectionId) +{ + if (apId == iCmManager.EasyWlanIdL()) { + TRequestStatus status; + TBuf<50> easyWlanNetworkName; + iConnectionMonitor.GetStringAttribute( connectionId, 0, KNetworkName, + easyWlanNetworkName, status ); + User::WaitForRequest(status); + if (status.Int() == KErrNone) { + const QString realSSID = QString::fromUtf16(easyWlanNetworkName.Ptr(), + easyWlanNetworkName.Length()); + + // Browser through all items and check their name for match + QHash<QString, QNetworkConfigurationPrivatePointer>::ConstIterator i = + accessPointConfigurations.constBegin(); + while (i != accessPointConfigurations.constEnd()) { + QNetworkConfigurationPrivatePointer ptr = i.value(); + + QMutexLocker configLocker(&ptr->mutex); + + if (ptr->name == realSSID) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNCM EasyWlan uses real SSID: " << realSSID; +#endif + return ptr; + } + ++i; + } + } + } + return QNetworkConfigurationPrivatePointer(); +} +#endif + +// Sessions may use this function to report configuration state changes, +// because on some Symbian platforms (especially Symbian^3) all state changes are not +// reported by the RConnectionMonitor, in particular in relation to stop() call, +// whereas they _are_ reported on RConnection progress notifier used by sessions --> centralize +// this data here so that other sessions may benefit from it too (not all sessions necessarily have +// RConnection progress notifiers available but they relay on having e.g. disconnected information from +// manager). Currently only 'Disconnected' state is of interest because it has proven to be troublesome. +void SymbianEngine::configurationStateChangeReport(TUint32 accessPointId, QNetworkSession::State newState) +{ + QMutexLocker locker(&mutex); + +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNCM A session reported state change for IAP ID: " << accessPointId << " whose new state is: " << newState; +#endif + switch (newState) { + case QNetworkSession::Disconnected: + { + QString ident = QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX + + QString::number(qHash(accessPointId)); + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(ident); + if (ptr) { + // Configuration is either Defined or Discovered + if (changeConfigurationStateAtMaxTo(ptr, QNetworkConfiguration::Discovered)) { + updateStatesToSnaps(); + } + + locker.unlock(); + emit configurationStateChanged(toSymbianConfig(ptr)->numericIdentifier(), + toSymbianConfig(ptr)->connectionIdentifier(), + QNetworkSession::Disconnected); + locker.relock(); + } + } + break; + default: + break; + } +} + +// Waits for 2..6 seconds. +void SymbianEngine::updateConfigurationsAfterRandomTime() +{ + int iTimeToWait = qMax(1000, (qAbs(qrand()) % 68) * 100); +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug("QNCM waiting random time: %d ms", iTimeToWait); +#endif + QTimer::singleShot(iTimeToWait, this, SLOT(delayedConfigurationUpdate())); +} + +QNetworkConfigurationPrivatePointer SymbianEngine::dataByConnectionId(TUint aConnectionId) +{ + QNetworkConfiguration item; + QHash<QString, QNetworkConfigurationPrivatePointer>::const_iterator i = + accessPointConfigurations.constBegin(); + while (i != accessPointConfigurations.constEnd()) { + QNetworkConfigurationPrivatePointer ptr = i.value(); + if (toSymbianConfig(ptr)->connectionIdentifier() == aConnectionId) + return ptr; + + ++i; + } + + return QNetworkConfigurationPrivatePointer(); +} + +AccessPointsAvailabilityScanner::AccessPointsAvailabilityScanner(SymbianEngine& owner, + RConnectionMonitor& connectionMonitor) + : CActive(CActive::EPriorityHigh), iOwner(owner), iConnectionMonitor(connectionMonitor) +{ + CActiveScheduler::Add(this); +} + +AccessPointsAvailabilityScanner::~AccessPointsAvailabilityScanner() +{ + Cancel(); +} + +void AccessPointsAvailabilityScanner::DoCancel() +{ + iConnectionMonitor.CancelAsyncRequest(EConnMonGetPckgAttribute); + iScanActive = EFalse; + iOwner.iScanInQueue = EFalse; +} + +void AccessPointsAvailabilityScanner::StartScanning() +{ + if (!iScanActive) { + iScanActive = ETrue; + if (iOwner.iFirstUpdate) { + // On first update (the mgr is being instantiated) update only those bearers who + // don't need time-consuming scans (WLAN). + // Note: EBearerIdWCDMA covers also GPRS bearer + iConnectionMonitor.GetPckgAttribute(EBearerIdWCDMA, 0, KIapAvailability, iIapBuf, iStatus); + } else { + iConnectionMonitor.GetPckgAttribute(EBearerIdAll, 0, KIapAvailability, iIapBuf, iStatus); + } + + if (!IsActive()) { + SetActive(); + } + } else { + // Queue scan for getting WLAN info after first request returns + if (iOwner.iFirstUpdate) { + iOwner.iScanInQueue = ETrue; + } + } +} + +void AccessPointsAvailabilityScanner::RunL() +{ + QMutexLocker locker(&iOwner.mutex); + + iScanActive = EFalse; + if (iStatus.Int() != KErrNone) { + iIapBuf().iCount = 0; + QT_TRYCATCH_LEAVING(iOwner.accessPointScanningReady(false,iIapBuf())); + } else { + QT_TRYCATCH_LEAVING(iOwner.accessPointScanningReady(true,iIapBuf())); + } +} + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/symbian/symbianengine.h b/src/plugins/bearer/symbian/symbianengine.h new file mode 100644 index 0000000..337d4d1 --- /dev/null +++ b/src/plugins/bearer/symbian/symbianengine.h @@ -0,0 +1,246 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SYMBIANENGINE_H +#define SYMBIANENGINE_H + +#include <QtCore/qstringlist.h> +#include <QtNetwork/private/qbearerengine_p.h> +#include <QtNetwork/qnetworkconfigmanager.h> + +#include <QHash> +#include <rconnmon.h> +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + #include <cmmanager.h> +#endif + +// Uncomment and compile QtBearer to gain detailed state tracing +// #define QT_BEARERMGMT_SYMBIAN_DEBUG + +#define QT_BEARERMGMT_CONFIGURATION_SNAP_PREFIX QLatin1String("S_") +#define QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX QLatin1String("I_") + +class CCommsDatabase; +class QEventLoop; + +QT_BEGIN_NAMESPACE +class QTimer; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class QNetworkSessionPrivate; +class AccessPointsAvailabilityScanner; + +class SymbianNetworkConfigurationPrivate : public QNetworkConfigurationPrivate +{ +public: + SymbianNetworkConfigurationPrivate(); + ~SymbianNetworkConfigurationPrivate(); + + inline TUint32 numericIdentifier() const + { + QMutexLocker locker(&mutex); + return numericId; + } + + inline TUint connectionIdentifier() const + { + QMutexLocker locker(&mutex); + return connectionId; + } + + inline QString configMappingName() const + { + QMutexLocker locker(&mutex); + return mappingName; + } + + QString mappingName; + + // So called IAP id from the platform. Remains constant as long as the + // platform is aware of the configuration ie. it is stored in the databases + // --> does not depend on whether connections are currently open or not. + // In practice is the same for the lifetime of the QNetworkConfiguration. + TUint32 numericId; + // So called connection id, or connection monitor ID. A dynamic ID assigned + // by RConnectionMonitor whenever a new connection is opened. ConnectionID and + // numericId/IAP id have 1-to-1 mapping during the lifetime of the connection at + // connection monitor. Notably however it changes whenever a new connection to + // a given IAP is created. In a sense it is constant during the time the + // configuration remains between states Discovered..Active..Discovered, do not + // however relay on this. + TUint connectionId; +}; + +inline SymbianNetworkConfigurationPrivate *toSymbianConfig(QNetworkConfigurationPrivatePointer ptr) +{ + return static_cast<SymbianNetworkConfigurationPrivate *>(ptr.data()); +} + +class SymbianEngine : public QBearerEngine, public CActive, + public MConnectionMonitorObserver +{ + Q_OBJECT + +public: + SymbianEngine(QObject *parent = 0); + virtual ~SymbianEngine(); + + bool hasIdentifier(const QString &id); + + Q_INVOKABLE void initialize(); + Q_INVOKABLE void requestUpdate(); + + QNetworkConfigurationManager::Capabilities capabilities() const; + + QNetworkSessionPrivate *createSessionBackend(); + + QNetworkConfigurationPrivatePointer defaultConfiguration(); + + QStringList accessPointConfigurationIdentifiers(); + + QNetworkConfigurationPrivatePointer configurationFromSsid(const QString &ssid); + + // For QNetworkSessionPrivateImpl to indicate about state changes + void configurationStateChangeReport(TUint32 accessPointId, QNetworkSession::State newState); + +Q_SIGNALS: + void onlineStateChanged(bool isOnline); + + void configurationStateChanged(quint32 accessPointId, quint32 connMonId, + QNetworkSession::State newState); + +public Q_SLOTS: + void updateConfigurations(); + void delayedConfigurationUpdate(); + +private: + void updateStatesToSnaps(); + bool changeConfigurationStateTo(QNetworkConfigurationPrivatePointer ptr, + QNetworkConfiguration::StateFlags newState); + bool changeConfigurationStateAtMinTo(QNetworkConfigurationPrivatePointer ptr, + QNetworkConfiguration::StateFlags newState); + bool changeConfigurationStateAtMaxTo(QNetworkConfigurationPrivatePointer ptr, + QNetworkConfiguration::StateFlags newState); +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + void updateMobileBearerToConfigs(TConnMonBearerInfo bearerInfo); + SymbianNetworkConfigurationPrivate *configFromConnectionMethodL(RCmConnectionMethod& connectionMethod); +#else + bool readNetworkConfigurationValuesFromCommsDb( + TUint32 aApId, SymbianNetworkConfigurationPrivate *apNetworkConfiguration); + void readNetworkConfigurationValuesFromCommsDbL( + TUint32 aApId, SymbianNetworkConfigurationPrivate *apNetworkConfiguration); +#endif + + void updateConfigurationsL(); + void updateActiveAccessPoints(); + void updateAvailableAccessPoints(); + void accessPointScanningReady(TBool scanSuccessful, TConnMonIapInfo iapInfo); + void startCommsDatabaseNotifications(); + void stopCommsDatabaseNotifications(); + void updateConfigurationsAfterRandomTime(); + + QNetworkConfigurationPrivatePointer defaultConfigurationL(); + TBool GetS60PlatformVersion(TUint& aMajor, TUint& aMinor) const; + void startMonitoringIAPData(TUint32 aIapId); + QNetworkConfigurationPrivatePointer dataByConnectionId(TUint aConnectionId); + +protected: + // From CActive + void RunL(); + void DoCancel(); + +private: + // MConnectionMonitorObserver + void EventL(const CConnMonEventBase& aEvent); +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + QNetworkConfigurationPrivatePointer configurationFromEasyWlan(TUint32 apId, + TUint connectionId); +#endif + +private: // Data + bool iFirstUpdate; + CCommsDatabase* ipCommsDB; + RConnectionMonitor iConnectionMonitor; + + TBool iWaitingCommsDatabaseNotifications; + TBool iOnline; + TBool iInitOk; + TBool iUpdateGoingOn; + TBool iUpdatePending; + TBool iScanInQueue; + + AccessPointsAvailabilityScanner* ipAccessPointsAvailabilityScanner; + + QNetworkConfigurationPrivatePointer defaultConfig; + + friend class QNetworkSessionPrivate; + friend class AccessPointsAvailabilityScanner; + +#ifdef SNAP_FUNCTIONALITY_AVAILABLE + RCmManager iCmManager; +#endif +}; + +class AccessPointsAvailabilityScanner : public CActive +{ +public: + AccessPointsAvailabilityScanner(SymbianEngine& owner, + RConnectionMonitor& connectionMonitor); + ~AccessPointsAvailabilityScanner(); + + void StartScanning(); + +protected: // From CActive + void RunL(); + void DoCancel(); + +private: // Data + SymbianEngine& iOwner; + RConnectionMonitor& iConnectionMonitor; + TConnMonIapInfoBuf iIapBuf; + TBool iScanActive; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/codecs/cn/qgb18030codec.cpp b/src/plugins/codecs/cn/qgb18030codec.cpp index 5537cf7..e10c8b1 100644 --- a/src/plugins/codecs/cn/qgb18030codec.cpp +++ b/src/plugins/codecs/cn/qgb18030codec.cpp @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE #define Is3rdByte(c) (InRange((c), 0x81, 0xFE)) #define Is4thByte(c) (InRange((c), 0x30, 0x39)) -#define QValidChar(u) ((u) ? QChar((ushort)(u)) : QChar(QChar::ReplacementCharacter)) +#define qValidChar(u) ((u) ? (u) : static_cast<ushort>(QChar::ReplacementCharacter)) /* User-defined areas: UDA 1: 0xAAA1 - 0xAFFE (564/0) UDA 2: 0xF8A1 - 0xFEFE (658/0) @@ -160,7 +160,7 @@ QString QGb18030Codec::convertToUnicode(const char* chars, int len, ConverterSta { uchar buf[4]; int nbuf = 0; - QChar replacement = QChar::ReplacementCharacter; + ushort replacement = QChar::ReplacementCharacter; if (state) { if (state->flags & ConvertInvalidToNull) replacement = QChar::Null; @@ -173,6 +173,9 @@ QString QGb18030Codec::convertToUnicode(const char* chars, int len, ConverterSta int invalid = 0; QString result; + result.resize(len); + int unicodeLen = 0; + ushort *const resultData = reinterpret_cast<ushort*>(result.data()); //qDebug("QGb18030Decoder::toUnicode(const char* chars, int len = %d)", len); for (int i = 0; i < len; i++) { uchar ch = chars[i]; @@ -180,14 +183,16 @@ QString QGb18030Codec::convertToUnicode(const char* chars, int len, ConverterSta case 0: if (ch < 0x80) { // ASCII - result += QLatin1Char(ch); + resultData[unicodeLen] = ch; + ++unicodeLen; } else if (Is1stByte(ch)) { // GB18030? buf[0] = ch; nbuf = 1; } else { // Invalid - result += replacement; + resultData[unicodeLen] = replacement; + ++unicodeLen; ++invalid; } break; @@ -198,9 +203,11 @@ QString QGb18030Codec::convertToUnicode(const char* chars, int len, ConverterSta int clen = 2; uint u = qt_Gb18030ToUnicode(buf, clen); if (clen == 2) { - result += QValidChar(u); + resultData[unicodeLen] = qValidChar(static_cast<ushort>(u)); + ++unicodeLen; } else { - result += replacement; + resultData[unicodeLen] = replacement; + ++unicodeLen; ++invalid; } nbuf = 0; @@ -209,7 +216,8 @@ QString QGb18030Codec::convertToUnicode(const char* chars, int len, ConverterSta nbuf = 2; } else { // Error - result += replacement; + resultData[unicodeLen] = replacement; + ++unicodeLen; ++invalid; nbuf = 0; } @@ -220,7 +228,8 @@ QString QGb18030Codec::convertToUnicode(const char* chars, int len, ConverterSta buf[2] = ch; nbuf = 3; } else { - result += replacement; + resultData[unicodeLen] = replacement; + ++unicodeLen; ++invalid; nbuf = 0; } @@ -232,19 +241,24 @@ QString QGb18030Codec::convertToUnicode(const char* chars, int len, ConverterSta int clen = 4; uint u = qt_Gb18030ToUnicode(buf, clen); if (clen == 4) { - result += QValidChar(u); + resultData[unicodeLen] = qValidChar(u); + ++unicodeLen; } else { - result += replacement; + resultData[unicodeLen] = replacement; + ++unicodeLen; ++invalid; } } else { - result += replacement; + resultData[unicodeLen] = replacement; + ++unicodeLen; ++invalid; } nbuf = 0; break; } } + result.resize(unicodeLen); + if (state) { state->remainingChars = nbuf; state->state_data[0] = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; @@ -305,7 +319,7 @@ QString QGbkCodec::convertToUnicode(const char* chars, int len, ConverterState * { uchar buf[2]; int nbuf = 0; - QChar replacement = QChar::ReplacementCharacter; + ushort replacement = QChar::ReplacementCharacter; if (state) { if (state->flags & ConvertInvalidToNull) replacement = QChar::Null; @@ -316,6 +330,9 @@ QString QGbkCodec::convertToUnicode(const char* chars, int len, ConverterState * int invalid = 0; QString result; + result.resize(len); + int unicodeLen = 0; + ushort *const resultData = reinterpret_cast<ushort*>(result.data()); //qDebug("QGbkDecoder::toUnicode(const char* chars = \"%s\", int len = %d)", chars, len); for (int i=0; i<len; i++) { @@ -324,14 +341,16 @@ QString QGbkCodec::convertToUnicode(const char* chars, int len, ConverterState * case 0: if (ch < 0x80) { // ASCII - result += QLatin1Char(ch); + resultData[unicodeLen] = ch; + ++unicodeLen; } else if (Is1stByte(ch)) { // GBK 1st byte? buf[0] = ch; nbuf = 1; } else { // Invalid - result += replacement; + resultData[unicodeLen] = replacement; + ++unicodeLen; ++invalid; } break; @@ -342,21 +361,25 @@ QString QGbkCodec::convertToUnicode(const char* chars, int len, ConverterState * int clen = 2; uint u = qt_Gb18030ToUnicode(buf, clen); if (clen == 2) { - result += QValidChar(u); + resultData[unicodeLen] = qValidChar(static_cast<ushort>(u)); + ++unicodeLen; } else { - result += replacement; + resultData[unicodeLen] = replacement; + ++unicodeLen; ++invalid; } nbuf = 0; } else { // Error - result += replacement; + resultData[unicodeLen] = replacement; + ++unicodeLen; ++invalid; nbuf = 0; } break; } } + result.resize(unicodeLen); if (state) { state->remainingChars = nbuf; @@ -445,7 +468,7 @@ QString QGb2312Codec::convertToUnicode(const char* chars, int len, ConverterStat { uchar buf[2]; int nbuf = 0; - QChar replacement = QChar::ReplacementCharacter; + ushort replacement = QChar::ReplacementCharacter; if (state) { if (state->flags & ConvertInvalidToNull) replacement = QChar::Null; @@ -456,6 +479,9 @@ QString QGb2312Codec::convertToUnicode(const char* chars, int len, ConverterStat int invalid = 0; QString result; + result.resize(len); + int unicodeLen = 0; + ushort *const resultData = reinterpret_cast<ushort*>(result.data()); //qDebug("QGb2312Decoder::toUnicode(const char* chars, int len = %d)", len); for (int i=0; i<len; i++) { uchar ch = chars[i]; @@ -463,14 +489,16 @@ QString QGb2312Codec::convertToUnicode(const char* chars, int len, ConverterStat case 0: if (ch < 0x80) { // ASCII - result += QLatin1Char(ch); + resultData[unicodeLen] = ch; + ++unicodeLen; } else if (IsByteInGb2312(ch)) { // GB2312 1st byte? buf[0] = ch; nbuf = 1; } else { // Invalid - result += replacement; + resultData[unicodeLen] = replacement; + ++unicodeLen; ++invalid; } break; @@ -481,21 +509,25 @@ QString QGb2312Codec::convertToUnicode(const char* chars, int len, ConverterStat int clen = 2; uint u = qt_Gb18030ToUnicode(buf, clen); if (clen == 2) { - result += QValidChar(u); + resultData[unicodeLen] = qValidChar(static_cast<ushort>(u)); + ++unicodeLen; } else { - result += replacement; + resultData[unicodeLen] = replacement; + ++unicodeLen; ++invalid; } nbuf = 0; } else { // Error - result += replacement; + resultData[unicodeLen] = replacement; + ++unicodeLen; ++invalid; nbuf = 0; } break; } } + result.resize(unicodeLen); if (state) { state->remainingChars = nbuf; diff --git a/src/plugins/gfxdrivers/directfb/directfb.pro b/src/plugins/gfxdrivers/directfb/directfb.pro index 0706f01..d397050 100644 --- a/src/plugins/gfxdrivers/directfb/directfb.pro +++ b/src/plugins/gfxdrivers/directfb/directfb.pro @@ -11,5 +11,5 @@ SOURCES += qdirectfbscreenplugin.cpp QMAKE_CXXFLAGS += $$QT_CFLAGS_DIRECTFB LIBS += $$QT_LIBS_DIRECTFB -DEFINES += $$QT_DEFINES_DIRECTFB QT_DIRECTFB_PLUGIN +DEFINES += $$QT_DEFINES_DIRECTFB contains(gfx-plugins, directfb):DEFINES += QT_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp index b76c6a7..ceed7ae 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -55,6 +55,7 @@ #include <private/qpixmap_raster_p.h> #include <private/qimagepixmapcleanuphooks_p.h> + QT_BEGIN_NAMESPACE class SurfaceCache; @@ -67,6 +68,15 @@ public: Matrix_BlitsUnsupported = (Matrix_NegativeScale|Matrix_RectsUnsupported) }; + inline static uint getTransformationType(const QTransform &transform) + { + int ret = transform.type(); + if (qMin(transform.m11(), transform.m22()) < 0) { + ret |= QDirectFBPaintEnginePrivate::Matrix_NegativeScale; + } + return ret; + } + enum CompositionModeStatus { PorterDuff_None = 0x0, PorterDuff_Supported = 0x1, @@ -98,7 +108,7 @@ public: inline bool isSimpleBrush(const QBrush &brush) const; - void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &pos); + void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &pos, const QTransform &pixmapTransform); void blit(const QRectF &dest, IDirectFBSurface *surface, const QRectF &src); inline bool supportsStretchBlit() const; @@ -112,7 +122,11 @@ public: static inline int cacheCost(const QImage &img) { return img.width() * img.height() * img.depth() / 8; } #endif - void prepareForBlit(bool alpha); + enum BlitFlag { + HasAlpha = 0x1, + Premultiplied = 0x2 + }; + void prepareForBlit(uint blitFlags); IDirectFBSurface *surface; @@ -167,7 +181,6 @@ struct CachedImage static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB #endif -#if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS || defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS || defined QT_DEBUG #define VOID_ARG() static_cast<bool>(false) enum PaintOperation { DRAW_RECTS = 0x0001, DRAW_LINES = 0x0002, DRAW_IMAGE = 0x0004, @@ -175,91 +188,84 @@ enum PaintOperation { DRAW_PATH = 0x0040, DRAW_POINTS = 0x0080, DRAW_ELLIPSE = 0x0100, DRAW_POLYGON = 0x0200, DRAW_TEXT = 0x0400, FILL_PATH = 0x0800, FILL_RECT = 0x1000, DRAW_COLORSPANS = 0x2000, DRAW_ROUNDED_RECT = 0x4000, - ALL = 0xffff + DRAW_STATICTEXT = 0x8000, ALL = 0xffff }; -#ifdef QT_DEBUG -static void initRasterFallbacksMasks(int *warningMask, int *disableMask) -{ - struct { - const char *name; - PaintOperation operation; - } const operations[] = { - { "DRAW_RECTS", DRAW_RECTS }, - { "DRAW_LINES", DRAW_LINES }, - { "DRAW_IMAGE", DRAW_IMAGE }, - { "DRAW_PIXMAP", DRAW_PIXMAP }, - { "DRAW_TILED_PIXMAP", DRAW_TILED_PIXMAP }, - { "STROKE_PATH", STROKE_PATH }, - { "DRAW_PATH", DRAW_PATH }, - { "DRAW_POINTS", DRAW_POINTS }, - { "DRAW_ELLIPSE", DRAW_ELLIPSE }, - { "DRAW_POLYGON", DRAW_POLYGON }, - { "DRAW_TEXT", DRAW_TEXT }, - { "FILL_PATH", FILL_PATH }, - { "FILL_RECT", FILL_RECT }, - { "DRAW_COLORSPANS", DRAW_COLORSPANS }, - { "DRAW_ROUNDED_RECT", DRAW_ROUNDED_RECT }, - { "ALL", ALL }, - { 0, ALL } - }; - - QStringList warning = QString::fromLatin1(qgetenv("QT_DIRECTFB_WARN_ON_RASTERFALLBACKS")).toUpper().split(QLatin1Char('|'), - QString::SkipEmptyParts); - QStringList disable = QString::fromLatin1(qgetenv("QT_DIRECTFB_DISABLE_RASTERFALLBACKS")).toUpper().split(QLatin1Char('|'), - QString::SkipEmptyParts); - *warningMask = 0; - *disableMask = 0; - if (!warning.isEmpty() || !disable.isEmpty()) { - for (int i=0; operations[i].name; ++i) { - const QString name = QString::fromLatin1(operations[i].name); - int idx = warning.indexOf(name); - if (idx != -1) { - *warningMask |= operations[i].operation; - warning.erase(warning.begin() + idx); - } - idx = disable.indexOf(name); - if (idx != -1) { - *disableMask |= operations[i].operation; - disable.erase(disable.begin() + idx); - } - } - } - if (!warning.isEmpty()) { - qWarning("QDirectFBPaintEngine QT_DIRECTFB_WARN_ON_RASTERFALLBACKS Unknown operation(s): %s", - qPrintable(warning.join(QLatin1String("|")))); - } - if (!disable.isEmpty()) { - qWarning("QDirectFBPaintEngine QT_DIRECTFB_DISABLE_RASTERFALLBACKS Unknown operation(s): %s", - qPrintable(disable.join(QLatin1String("|")))); - } - -} -#endif - -static inline int rasterFallbacksMask(bool warn) +enum { RasterWarn = 1, RasterDisable = 2 }; +static inline uint rasterFallbacksMask(PaintOperation op) { + uint ret = 0; #ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS - if (warn) - return QT_DIRECTFB_WARN_ON_RASTERFALLBACKS; + if (op & QT_DIRECTFB_WARN_ON_RASTERFALLBACKS) + ret |= RasterWarn; #endif #ifdef QT_DIRECTFB_DISABLE_RASTERFALLBACKS - if (!warn) - return QT_DIRECTFB_DISABLE_RASTERFALLBACKS; + if (op & QT_DIRECTFB_DISABLE_RASTERFALLBACKS) + ret |= RasterDisable; #endif -#ifndef QT_DEBUG - return 0; -#else - static int warnMask = -1; + static int warningMask = -1; static int disableMask = -1; - if (warnMask == -1) - initRasterFallbacksMasks(&warnMask, &disableMask); - return warn ? warnMask : disableMask; -#endif + if (warningMask < 0) { + struct { + const char *name; + PaintOperation operation; + } const operations[] = { + { "DRAW_RECTS", DRAW_RECTS }, + { "DRAW_LINES", DRAW_LINES }, + { "DRAW_IMAGE", DRAW_IMAGE }, + { "DRAW_PIXMAP", DRAW_PIXMAP }, + { "DRAW_TILED_PIXMAP", DRAW_TILED_PIXMAP }, + { "STROKE_PATH", STROKE_PATH }, + { "DRAW_PATH", DRAW_PATH }, + { "DRAW_POINTS", DRAW_POINTS }, + { "DRAW_ELLIPSE", DRAW_ELLIPSE }, + { "DRAW_POLYGON", DRAW_POLYGON }, + { "DRAW_TEXT", DRAW_TEXT }, + { "FILL_PATH", FILL_PATH }, + { "FILL_RECT", FILL_RECT }, + { "DRAW_COLORSPANS", DRAW_COLORSPANS }, + { "DRAW_ROUNDED_RECT", DRAW_ROUNDED_RECT }, + { "ALL", ALL }, + { 0, ALL } + }; + + QStringList warning = QString::fromLatin1(qgetenv("QT_DIRECTFB_WARN_ON_RASTERFALLBACKS")).toUpper().split(QLatin1Char('|'), + QString::SkipEmptyParts); + QStringList disable = QString::fromLatin1(qgetenv("QT_DIRECTFB_DISABLE_RASTERFALLBACKS")).toUpper().split(QLatin1Char('|'), + QString::SkipEmptyParts); + warningMask = 0; + disableMask = 0; + if (!warning.isEmpty() || !disable.isEmpty()) { + for (int i=0; operations[i].name; ++i) { + const QString name = QString::fromLatin1(operations[i].name); + int idx = warning.indexOf(name); + if (idx != -1) { + warningMask |= operations[i].operation; + warning.erase(warning.begin() + idx); + } + idx = disable.indexOf(name); + if (idx != -1) { + disableMask |= operations[i].operation; + disable.erase(disable.begin() + idx); + } + } + } + if (!warning.isEmpty()) { + qWarning("QDirectFBPaintEngine QT_DIRECTFB_WARN_ON_RASTERFALLBACKS Unknown operation(s): %s", + qPrintable(warning.join(QLatin1String("|")))); + } + if (!disable.isEmpty()) { + qWarning("QDirectFBPaintEngine QT_DIRECTFB_DISABLE_RASTERFALLBACKS Unknown operation(s): %s", + qPrintable(disable.join(QLatin1String("|")))); + } + } + if (op & warningMask) + ret |= RasterWarn; + if (op & disableMask) + ret |= RasterDisable; + return ret; } -#endif -#if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS || defined QT_DEBUG template <typename device, typename T1, typename T2, typename T3> static void rasterFallbackWarn(const char *msg, const char *func, const device *dev, uint transformationType, bool simplePen, @@ -267,16 +273,24 @@ static void rasterFallbackWarn(const char *msg, const char *func, const device * const char *nameOne, const T1 &one, const char *nameTwo, const T2 &two, const char *nameThree, const T3 &three); -#endif -#if defined QT_DEBUG || (defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS && defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS) #define RASTERFALLBACK(op, one, two, three) \ { \ - const bool disable = op & rasterFallbacksMask(false); \ - if (op & rasterFallbacksMask(true)) \ - rasterFallbackWarn(disable \ - ? "Disabled raster engine operation" \ - : "Falling back to raster engine for", \ + static const uint rasterFallbacks = rasterFallbacksMask(op); \ + switch (rasterFallbacks) { \ + case 0: break; \ + case RasterWarn: \ + rasterFallbackWarn("Falling back to raster engine for", \ + __FUNCTION__, \ + state()->painter->device(), \ + d_func()->transformationType, \ + d_func()->simplePen, \ + d_func()->clipType, \ + d_func()->compositionModeStatus, \ + #one, one, #two, two, #three, three); \ + break; \ + case RasterDisable|RasterWarn: \ + rasterFallbackWarn("Disabled raster engine operation", \ __FUNCTION__, \ state()->painter->device(), \ d_func()->transformationType, \ @@ -284,26 +298,10 @@ static void rasterFallbackWarn(const char *msg, const char *func, const device * d_func()->clipType, \ d_func()->compositionModeStatus, \ #one, one, #two, two, #three, three); \ - if (disable) \ + case RasterDisable: \ return; \ + } \ } -#elif defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS -#define RASTERFALLBACK(op, one, two, three) \ - if (op & rasterFallbacksMask(false)) \ - return; -#elif defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS -#define RASTERFALLBACK(op, one, two, three) \ - if (op & rasterFallbacksMask(true)) \ - rasterFallbackWarn("Falling back to raster engine for", \ - __FUNCTION__, state()->painter->device(), \ - d_func()->transformationType, \ - d_func()->simplePen, \ - d_func()->clipType, \ - d_func()->compositionModeStatus, \ - #one, one, #two, two, #three, three); -#else -#define RASTERFALLBACK(op, one, two, three) -#endif template <class T> static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface); @@ -632,7 +630,12 @@ void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image, #if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE bool release; IDirectFBSurface *imgSurface = d->getSurface(image, &release); - d->prepareForBlit(QDirectFBScreen::hasAlphaChannel(imgSurface)); + uint blitFlags = 0; + if (image.hasAlphaChannel()) + blitFlags |= QDirectFBPaintEnginePrivate::HasAlpha; + if (QDirectFBScreen::isPremultiplied(image.format())) + blitFlags |= QDirectFBPaintEnginePrivate::Premultiplied; + d->prepareForBlit(blitFlags); CLIPPED_PAINT(d->blit(r, imgSurface, sr)); if (release) { #if (Q_DIRECTFB_VERSION >= 0x010000) @@ -671,8 +674,14 @@ void QDirectFBPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, QRasterPaintEngine::drawImage(r, *img, sr); } else { QDirectFBPaintEnginePrivate::unlock(dfbData); - d->prepareForBlit(pixmap.hasAlphaChannel()); IDirectFBSurface *s = dfbData->directFBSurface(); + uint blitFlags = 0; + if (pixmap.hasAlphaChannel()) + blitFlags |= QDirectFBPaintEnginePrivate::HasAlpha; + if (QDirectFBScreen::isPremultiplied(dfbData->pixelFormat())) + blitFlags |= QDirectFBPaintEnginePrivate::Premultiplied; + + d->prepareForBlit(blitFlags); CLIPPED_PAINT(d->blit(r, s, sr)); } } @@ -707,7 +716,8 @@ void QDirectFBPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap pix(data); QRasterPaintEngine::drawTiledPixmap(r, pix, offset); } else { - CLIPPED_PAINT(d->drawTiledPixmap(r, pixmap, offset)); + QTransform transform(state()->matrix); + CLIPPED_PAINT(d->drawTiledPixmap(r, pixmap, offset, transform)); } } @@ -797,6 +807,14 @@ void QDirectFBPaintEngine::drawRoundedRect(const QRectF &rect, qreal xrad, qreal QRasterPaintEngine::drawRoundedRect(rect, xrad, yrad, mode); } +void QDirectFBPaintEngine::drawStaticTextItem(QStaticTextItem *item) +{ + RASTERFALLBACK(DRAW_STATICTEXT, item, VOID_ARG(), VOID_ARG()); + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawStaticTextItem(item); +} + void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) { Q_D(QDirectFBPaintEngine); @@ -819,9 +837,14 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) return; } case Qt::TexturePattern: { + const QPointF &brushOrigin = state()->brushOrigin; + const QTransform stateTransform = state()->matrix; + QTransform transform(stateTransform); + transform.translate(brushOrigin.x(), brushOrigin.y()); + transform = brush.transform() * transform; if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported) - || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) - || (!d->supportsStretchBlit() && state()->matrix.isScaling())) { + || (QDirectFBPaintEnginePrivate::getTransformationType(transform) & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) + || (!d->supportsStretchBlit() && transform.isScaling())) { break; } @@ -829,7 +852,7 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) if (texture.pixmapData()->classId() != QPixmapData::DirectFBClass) break; - CLIPPED_PAINT(d->drawTiledPixmap(rect, texture, rect.topLeft() - state()->brushOrigin)); + CLIPPED_PAINT(d->drawTiledPixmap(stateTransform.mapRect(rect), texture, rect.topLeft() - brushOrigin, transform)); return; } default: break; @@ -940,10 +963,7 @@ void QDirectFBPaintEnginePrivate::unlock(QDirectFBPaintDevice *device) void QDirectFBPaintEnginePrivate::setTransform(const QTransform &transform) { - transformationType = transform.type(); - if (qMin(transform.m11(), transform.m22()) < 0) { - transformationType |= QDirectFBPaintEnginePrivate::Matrix_NegativeScale; - } + transformationType = getTransformationType(transform); setPen(q->state()->pen); } @@ -1039,13 +1059,18 @@ void QDirectFBPaintEnginePrivate::setRenderHints(QPainter::RenderHints hints) } } -void QDirectFBPaintEnginePrivate::prepareForBlit(bool alpha) +void QDirectFBPaintEnginePrivate::prepareForBlit(uint flags) { - DFBSurfaceBlittingFlags blittingFlags = alpha ? DSBLIT_BLEND_ALPHACHANNEL : DSBLIT_NOFX; + DFBSurfaceBlittingFlags blittingFlags = DSBLIT_NOFX; + if (flags & Premultiplied) + blittingFlags |= DSBLIT_SRC_PREMULTIPLY; + if (flags & HasAlpha) + blittingFlags |= DSBLIT_BLEND_ALPHACHANNEL; if (opacity != 255) { blittingFlags |= DSBLIT_BLEND_COLORALPHA; + surface->SetColor(surface, 0xff, 0xff, 0xff, opacity); } - surface->SetColor(surface, 0xff, 0xff, 0xff, opacity); + surface->SetBlittingFlags(surface, blittingFlags); } @@ -1140,10 +1165,12 @@ static inline qreal fixCoord(qreal rect_pos, qreal pixmapSize, qreal offset) return pos; } -void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &off) +void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, + const QPointF &off, const QTransform &pixmapTransform) { - Q_ASSERT(!(transformationType & Matrix_BlitsUnsupported)); const QTransform &transform = q->state()->matrix; + Q_ASSERT(!(getTransformationType(transform) & Matrix_BlitsUnsupported) && + !(getTransformationType(pixmapTransform) & Matrix_BlitsUnsupported)); const QRect destinationRect = transform.mapRect(dest).toRect().normalized(); QRect newClip = destinationRect; if (!currentClip.isEmpty()) @@ -1160,22 +1187,27 @@ void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPix }; surface->SetClip(surface, &clip); - QPointF offset = off; + QPointF offset = pixmapTransform.inverted().map(off); Q_ASSERT(transform.type() <= QTransform::TxScale); - prepareForBlit(pixmap.hasAlphaChannel()); QPixmapData *data = pixmap.pixmapData(); Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); + IDirectFBSurface *sourceSurface = dfbData->directFBSurface(); + uint blitFlags = 0; + if (dfbData->hasAlphaChannel()) + blitFlags |= HasAlpha; + if (QDirectFBScreen::isPremultiplied(dfbData->pixelFormat())) + blitFlags |= Premultiplied; + prepareForBlit(blitFlags); QDirectFBPaintEnginePrivate::unlock(dfbData); const QSize pixmapSize = dfbData->size(); - IDirectFBSurface *sourceSurface = dfbData->directFBSurface(); - if (transform.isScaling()) { + if (transform.isScaling() || pixmapTransform.isScaling()) { Q_ASSERT(supportsStretchBlit()); Q_ASSERT(qMin(transform.m11(), transform.m22()) >= 0); offset.rx() *= transform.m11(); offset.ry() *= transform.m22(); - const QSizeF mappedSize(pixmapSize.width() * transform.m11(), pixmapSize.height() * transform.m22()); + const QSizeF mappedSize(pixmapSize.width() * pixmapTransform.m11(), pixmapSize.height() * pixmapTransform.m22()); qreal y = fixCoord(destinationRect.y(), mappedSize.height(), offset.y()); const qreal startX = fixCoord(destinationRect.x(), mappedSize.width(), offset.x()); while (y <= destinationRect.bottom()) { @@ -1354,7 +1386,6 @@ static inline void drawRects(const T *rects, int n, const QTransform &transform, } } -#if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS || defined QT_DEBUG template <typename T> inline const T *ptr(const T &t) { return &t; } template <> inline const bool* ptr<bool>(const bool &) { return 0; } template <typename device, typename T1, typename T2, typename T3> @@ -1395,8 +1426,6 @@ static void rasterFallbackWarn(const char *msg, const char *func, const device * qWarning("%s", qPrintable(out)); } -#endif // QT_DIRECTFB_WARN_ON_RASTERFALLBACKS - QT_END_NAMESPACE #endif // QT_NO_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h index 64609d7..19e8b84 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h @@ -109,6 +109,8 @@ public: virtual void clip(const QRegion ®ion, Qt::ClipOperation op); virtual void clip(const QRect &rect, Qt::ClipOperation op); + virtual void drawStaticTextItem(QStaticTextItem *item); + static void initImageCache(int size); }; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp index 80366d1..ce3a05a 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp @@ -91,6 +91,7 @@ void QDirectFBPixmapData::resize(int width, int height) setSerialNumber(++global_ser_no); } +#ifdef QT_DIRECTFB_OPAQUE_DETECTION // mostly duplicated from qimage.cpp (QImageData::checkForAlphaPixels) static bool checkForAlphaPixels(const QImage &img) { @@ -160,12 +161,16 @@ static bool checkForAlphaPixels(const QImage &img) return false; } +#endif // QT_DIRECTFB_OPAQUE_DETECTION -bool QDirectFBPixmapData::hasAlphaChannel(const QImage &img) +bool QDirectFBPixmapData::hasAlphaChannel(const QImage &img, Qt::ImageConversionFlags flags) { -#ifndef QT_NO_DIRECTFB_OPAQUE_DETECTION - return checkForAlphaPixels(img); + if (img.depth() == 1) + return true; +#ifdef QT_DIRECTFB_OPAQUE_DETECTION + return ((flags & Qt::NoOpaqueDetection) ? img.hasAlphaChannel() : checkForAlphaPixels(img)); #else + Q_UNUSED(flags); return img.hasAlphaChannel(); #endif } @@ -246,12 +251,6 @@ bool QDirectFBPixmapData::fromDataBufferDescription(const DFBDataBufferDescripti } QDirectFBPointer<IDirectFBImageProvider> provider(providerPtr); - DFBSurfaceDescription surfaceDescription; - if ((result = provider->GetSurfaceDescription(provider.data(), &surfaceDescription)) != DFB_OK) { - DirectFBError("QDirectFBPixmapData::fromDataBufferDescription(): Can't get surface description", result); - return false; - } - DFBImageDescription imageDescription; result = provider->GetImageDescription(provider.data(), &imageDescription); if (result != DFB_OK) { @@ -259,7 +258,17 @@ bool QDirectFBPixmapData::fromDataBufferDescription(const DFBDataBufferDescripti return false; } - alpha = imageDescription.caps & (DICAPS_ALPHACHANNEL|DICAPS_COLORKEY); + if (imageDescription.caps & DICAPS_COLORKEY) { + return false; + } + + DFBSurfaceDescription surfaceDescription; + if ((result = provider->GetSurfaceDescription(provider.data(), &surfaceDescription)) != DFB_OK) { + DirectFBError("QDirectFBPixmapData::fromDataBufferDescription(): Can't get surface description", result); + return false; + } + + alpha = imageDescription.caps & DICAPS_ALPHACHANNEL; imageFormat = alpha ? screen->alphaPixmapFormat() : screen->pixelFormat(); dfbSurface = screen->createDFBSurface(QSize(surfaceDescription.width, surfaceDescription.height), @@ -287,19 +296,9 @@ bool QDirectFBPixmapData::fromDataBufferDescription(const DFBDataBufferDescripti #endif -void QDirectFBPixmapData::fromImage(const QImage &img, - Qt::ImageConversionFlags flags) +void QDirectFBPixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags) { - if (img.depth() == 1) { - alpha = true; -#ifndef QT_NO_DIRECTFB_OPAQUE_DETECTION - } else if (flags & Qt::NoOpaqueDetection || QDirectFBPixmapData::hasAlphaChannel(img)) { - alpha = true; -#else - } else if (img.hasAlphaChannel()) { - alpha = true; -#endif - } + alpha = QDirectFBPixmapData::hasAlphaChannel(img, flags); imageFormat = alpha ? screen->alphaPixmapFormat() : screen->pixelFormat(); QImage image; if ((flags & ~Qt::NoOpaqueDetection) != Qt::AutoColor) { @@ -590,7 +589,6 @@ void QDirectFBPixmapData::invalidate() imageFormat = QImage::Format_Invalid; } -#ifndef QT_DIRECTFB_PLUGIN Q_GUI_EXPORT IDirectFBSurface *qt_directfb_surface_for_pixmap(const QPixmap &pixmap) { const QPixmapData *data = pixmap.pixmapData(); @@ -599,7 +597,6 @@ Q_GUI_EXPORT IDirectFBSurface *qt_directfb_surface_for_pixmap(const QPixmap &pix const QDirectFBPixmapData *dfbData = static_cast<const QDirectFBPixmapData*>(data); return dfbData->directFBSurface(); } -#endif QT_END_NAMESPACE diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h index da6edc6..343b26e 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h @@ -86,8 +86,8 @@ public: virtual int metric(QPaintDevice::PaintDeviceMetric m) const { return QDirectFBPaintDevice::metric(m); } inline QImage::Format pixelFormat() const { return imageFormat; } - static bool hasAlphaChannel(const QImage &img); inline bool hasAlphaChannel() const { return alpha; } + static bool hasAlphaChannel(const QImage &img, Qt::ImageConversionFlags flags = Qt::AutoColor); private: #ifdef QT_DIRECTFB_IMAGEPROVIDER bool fromDataBufferDescription(const DFBDataBufferDescription &dataBuffer); diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp index cffd4e3..f2ee6ae 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp @@ -1554,9 +1554,8 @@ void QDirectFBScreen::exposeRegion(QRegion r, int) : (DSBLIT_BLEND_ALPHACHANNEL|DSBLIT_BLEND_COLORALPHA); } } - if (!region.isEmpty()) { - solidFill(d_ptr->backgroundColor, region); - } + + solidFill(d_ptr->backgroundColor, region); while (idx > 0) { const PaintCommand &cmd = commands[--idx]; @@ -1629,29 +1628,34 @@ void QDirectFBScreen::solidFill(const QColor &color, const QRegion ®ion) Q_UNUSED(color); Q_UNUSED(region); #else + QDirectFBScreen::solidFill(d_ptr->primarySurface, color, region); +#endif +} + +static inline void clearRect(IDirectFBSurface *surface, const QColor &color, const QRect &rect) +{ + Q_ASSERT(surface); + const DFBRegion region = { rect.left(), rect.top(), rect.right(), rect.bottom() }; + // could just reinterpret_cast this to a DFBRegion + surface->SetClip(surface, ®ion); + surface->Clear(surface, color.red(), color.green(), color.blue(), color.alpha()); +} + +void QDirectFBScreen::solidFill(IDirectFBSurface *surface, const QColor &color, const QRegion ®ion) +{ if (region.isEmpty()) return; - d_ptr->primarySurface->SetColor(d_ptr->primarySurface, - color.red(), color.green(), color.blue(), - color.alpha()); const int n = region.rectCount(); if (n == 1) { - const QRect r = region.boundingRect(); - d_ptr->primarySurface->FillRectangle(d_ptr->primarySurface, r.x(), r.y(), r.width(), r.height()); + clearRect(surface, color, region.boundingRect()); } else { const QVector<QRect> rects = region.rects(); - QVarLengthArray<DFBRectangle, 32> rectArray(n); for (int i=0; i<n; ++i) { - const QRect &r = rects.at(i); - rectArray[i].x = r.x(); - rectArray[i].y = r.y(); - rectArray[i].w = r.width(); - rectArray[i].h = r.height(); + clearRect(surface, color, rects.at(i)); } - d_ptr->primarySurface->FillRectangles(d_ptr->primarySurface, rectArray.constData(), n); } -#endif + surface->SetClip(surface, 0); } QImage::Format QDirectFBScreen::alphaPixmapFormat() const @@ -1790,7 +1794,6 @@ IDirectFBSurface *QDirectFBScreen::subSurfaceForWidget(const QWidget *widget, co } #endif -#ifndef QT_DIRECTFB_PLUGIN Q_GUI_EXPORT IDirectFBSurface *qt_directfb_surface_for_widget(const QWidget *widget, QRect *rect) { return QDirectFBScreen::instance() ? QDirectFBScreen::instance()->surfaceForWidget(widget, rect) : 0; @@ -1808,7 +1811,6 @@ Q_GUI_EXPORT IDirectFBWindow *qt_directfb_window_for_widget(const QWidget *widge } #endif -#endif QT_END_NAMESPACE diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h index c483020..1085423 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h @@ -159,6 +159,7 @@ public: void exposeRegion(QRegion r, int changing); void solidFill(const QColor &color, const QRegion ®ion); + static void solidFill(IDirectFBSurface *surface, const QColor &color, const QRegion ®ion); void setMode(int width, int height, int depth); void blank(bool on); diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp index 51969fc..2eeee24 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp @@ -380,11 +380,18 @@ void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion ®ion, flushPending = false; } -void QDirectFBWindowSurface::beginPaint(const QRegion &) +void QDirectFBWindowSurface::beginPaint(const QRegion ®ion) { if (!engine) { engine = new QDirectFBPaintEngine(this); } + + if (dfbSurface) { + const QWidget *win = window(); + if (win && win->testAttribute(Qt::WA_NoSystemBackground)) { + QDirectFBScreen::solidFill(dfbSurface, Qt::transparent, region); + } + } flushPending = true; } diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c index e6ac418..d05dd5d 100644 --- a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c +++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c @@ -95,7 +95,7 @@ static int pvrQwsInitFbScreen(int screen) width = var.xres; height = var.yres; bytesPerPixel = var.bits_per_pixel / 8; - stride = var.xres * bytesPerPixel; + stride = fix.line_length; format = PVR2D_1BPP; if (var.bits_per_pixel == 16) { if (var.red.length == 5 && var.green.length == 6 && diff --git a/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp b/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp index f5ad70c..3bafd97 100644 --- a/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp +++ b/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp @@ -1053,7 +1053,7 @@ void QVNCServer::clientCutText() { QRfbClientCutText ev; - if (ev.read(client)) { + if (cutTextPending == 0 && ev.read(client)) { cutTextPending = ev.length; if (!cutTextPending) handleMsg = false; @@ -1481,7 +1481,7 @@ void QVNCServer::convertPixels(char *dst, const char *src, int count) const } if (count & 0x1) { const quint16 *src16 = reinterpret_cast<const quint16*>(src); - dst32[count - 1] = qt_conv16ToRgb(src16[count - 1]); + *dst32 = qt_conv16ToRgb(src16[count - 1]); } return; #endif @@ -2038,7 +2038,7 @@ void QVNCServer::discardClient() delete qvnc_cursor; qvnc_cursor = 0; #endif - if (!qvnc_screen->screen() && !qvnc_screen->d_ptr->noDisablePainting) + if (!qvnc_screen->screen() && !qvnc_screen->d_ptr->noDisablePainting && QWSServer::instance()) QWSServer::instance()->enablePainting(false); } diff --git a/src/plugins/graphicssystems/graphicssystems.pro b/src/plugins/graphicssystems/graphicssystems.pro index 0788933..29a1f34 100644 --- a/src/plugins/graphicssystems/graphicssystems.pro +++ b/src/plugins/graphicssystems/graphicssystems.pro @@ -7,3 +7,7 @@ contains(QT_CONFIG, shivavg) { # Only works under X11 at present !win32:!embedded:!mac:SUBDIRS += shivavg } + +!win32:!embedded:!mac:!symbian:CONFIG += x11 + +x11:contains(QT_CONFIG, opengles2):contains(QT_CONFIG, egl):SUBDIRS += meego diff --git a/src/plugins/graphicssystems/meego/dithering.cpp b/src/plugins/graphicssystems/meego/dithering.cpp new file mode 100644 index 0000000..1a2e3fa --- /dev/null +++ b/src/plugins/graphicssystems/meego/dithering.cpp @@ -0,0 +1,306 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// This is an implementation of the 32bit => 16bit Floyd-Steinberg dithering. +// The alghorithm used here is not the fastest possible but it's prolly fast enough: +// uses look-up tables, integer-only arthmetics and works in one pass on two lines +// at a time. It's a high-quality dithering using 1/8 diffusion precission. +// Two functions here to look at: +// +// * convertRGBA32_to_RGB565 +// * convertRGBA32_to_RGBA4444 +// +// Each channel (RGBA) is diffused independently and alpha is dithered too. + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <QVarLengthArray> + +// Gets a component (red = 1, green = 2...) from a RGBA data structure. +// data is unsigned char. stride is the number of bytes per line. +#define GET_RGBA_COMPONENT(data, x, y, stride, c) (data[(y * stride) + (x << 2) + c]) + +// Writes a new pixel with r, g, b to data in 565 16bit format. Data is a short. +#define PUT_565(data, x, y, width, r, g, b) (data[(y * width) + x] = (r << 11) | (g << 5) | b) + +// Writes a new pixel with r, g, b, a to data in 4444 RGBA 16bit format. Data is a short. +#define PUT_4444(data, x, y, width, r, g, b, a) (data[(y * width) + x] = (r << 12) | (g << 8) | (b << 4) | a) + +// Writes(ads) a new value to the diffusion accumulator. accumulator is a short. +// x, y is a position in the accumulation buffer. y can be 0 or 1 -- we operate on two lines at time. +#define ACCUMULATE(accumulator, x, y, width, v) if (x < width && x >= 0) accumulator[(y * width) + x] += v + +// Clamps a value to be in 0..255 range. +#define CLAMP_256(v) if (v > 255) v = 255; if (v < 0) v = 0; + +// Converts incoming RGB32 (QImage::Format_RGB32) to RGB565. Returns the newly allocated data. +unsigned short* convertRGB32_to_RGB565(const unsigned char *in, int width, int height, int stride) +{ + // Output line stride. Aligned to 4 bytes. + int alignedWidth = width; + if (alignedWidth % 2 > 0) + alignedWidth++; + + // Will store output + unsigned short *out = (unsigned short *) malloc(alignedWidth * height * 2); + + // Lookup tables for the 8bit => 6bit and 8bit => 5bit conversion + unsigned char lookup_8bit_to_5bit[256]; + short lookup_8bit_to_5bit_diff[256]; + unsigned char lookup_8bit_to_6bit[256]; + short lookup_8bit_to_6bit_diff[256]; + + // Macros for the conversion using the lookup table. + #define CONVERT_8BIT_TO_5BIT(v) (lookup_8bit_to_5bit[v]) + #define DIFF_8BIT_TO_5BIT(v) (lookup_8bit_to_5bit_diff[v]) + + #define CONVERT_8BIT_TO_6BIT(v) (lookup_8bit_to_6bit[v]) + #define DIFF_8BIT_TO_6BIT(v) (lookup_8bit_to_6bit_diff[v]) + + int i; + int x, y, c; // Pixel we're processing. c is component number (0, 1, 2 for r, b, b) + short component[3]; // Stores the new components (r, g, b) for pixel produced during conversion + short diff; // The difference between the converted value and the original one. To be accumulated. + QVarLengthArray <short> accumulatorData(3 * width * 2); // Data for three acumulators for r, g, b. Each accumulator is two lines. + short *accumulator[3]; // Helper for accessing the accumulator on a per-channel basis more easily. + accumulator[0] = accumulatorData.data(); + accumulator[1] = accumulatorData.data() + width; + accumulator[2] = accumulatorData.data() + (width * 2); + + // Produce the conversion lookup tables. + for (i = 0; i < 256; i++) { + lookup_8bit_to_5bit[i] = round(i / 8.0); + + // Before bitshifts: (i * 8) - (... * 8 * 8) + lookup_8bit_to_5bit_diff[i] = (i << 3) - (lookup_8bit_to_5bit[i] << 6); + if (lookup_8bit_to_5bit[i] > 31) + lookup_8bit_to_5bit[i] -= 1; + + lookup_8bit_to_6bit[i] = round(i / 4.0); + + // Before bitshifts: (i * 8) - (... * 4 * 8) + lookup_8bit_to_6bit_diff[i] = (i << 3) - (lookup_8bit_to_6bit[i] << 5); + if (lookup_8bit_to_6bit[i] > 63) + lookup_8bit_to_6bit[i] -= 1; + } + + // Clear the accumulators + memset(accumulator[0], 0, width * 4); + memset(accumulator[1], 0, width * 4); + memset(accumulator[2], 0, width * 4); + + // For each line... + for (y = 0; y < height; y++) { + + // For each accumulator, move the second line (index 1) to replace the first line (index 0). + // Clear the second line (index 1) + memcpy(accumulator[0], accumulator[0] + width, width * 2); + memset(accumulator[0] + width, 0, width * 2); + + memcpy(accumulator[1], accumulator[1] + width, width * 2); + memset(accumulator[1] + width, 0, width * 2); + + memcpy(accumulator[2], accumulator[2] + width, width * 2); + memset(accumulator[2] + width, 0, width * 2); + + // For each column.... + for (x = 0; x < width; x++) { + + // For each component (r, g, b)... + for (c = 0; c < 3; c++) { + + // Get the 8bit value from the original image + component[c] = GET_RGBA_COMPONENT(in, x, y, stride, c); + + // Add the diffusion for this pixel we stored in the accumulator. + // >> 7 because the values in accumulator are stored * 128 + component[c] += accumulator[c][x] >> 7; + + // Make sure we're not over the boundaries. + CLAMP_256(component[c]); + + // For green component we use 6 bits. Otherwise 5 bits. + // Store the difference from converting 8bit => 6 bit and the orig pixel. + // Convert 8bit => 6(5) bit. + if (c == 1) { + diff = DIFF_8BIT_TO_6BIT(component[c]); + component[c] = CONVERT_8BIT_TO_6BIT(component[c]); + } else { + diff = DIFF_8BIT_TO_5BIT(component[c]); + component[c] = CONVERT_8BIT_TO_5BIT(component[c]); + } + + // Distribute the difference according to the matrix in the + // accumulation bufffer. + ACCUMULATE(accumulator[c], x + 1, 0, width, diff * 7); + ACCUMULATE(accumulator[c], x - 1, 1, width, diff * 3); + ACCUMULATE(accumulator[c], x, 1, width, diff * 5); + ACCUMULATE(accumulator[c], x + 1, 1, width, diff * 1); + } + + // Write the newly produced pixel + PUT_565(out, x, y, alignedWidth, component[2], component[1], component[0]); + } + } + + return out; +} + +// Converts incoming RGBA32 (QImage::Format_ARGB32_Premultiplied) to RGB565. Returns the newly allocated data. +// This function is similar (yet different) to the _565 variant but it makes sense to duplicate it here for simplicity. +// The output has each scan line aligned to 4 bytes (as expected by GL by default). +unsigned short* convertARGB32_to_RGBA4444(const unsigned char *in, int width, int height, int stride) +{ + // Output line stride. Aligned to 4 bytes. + int alignedWidth = width; + if (alignedWidth % 2 > 0) + alignedWidth++; + + // Will store output + unsigned short *out = (unsigned short *) malloc(alignedWidth * 2 * height); + + // Lookup tables for the 8bit => 4bit conversion + unsigned char lookup_8bit_to_4bit[256]; + short lookup_8bit_to_4bit_diff[256]; + + // Macros for the conversion using the lookup table. + #define CONVERT_8BIT_TO_4BIT(v) (lookup_8bit_to_4bit[v]) + #define DIFF_8BIT_TO_4BIT(v) (lookup_8bit_to_4bit_diff[v]) + + int i; + int x, y, c; // Pixel we're processing. c is component number (0, 1, 2, 3 for r, b, b, a) + short component[4]; // Stores the new components (r, g, b, a) for pixel produced during conversion + short diff; // The difference between the converted value and the original one. To be accumulated. + QVarLengthArray <short> accumulatorData(4 * width * 2); // Data for three acumulators for r, g, b. Each accumulator is two lines. + short *accumulator[4]; // Helper for accessing the accumulator on a per-channel basis more easily. + accumulator[0] = accumulatorData.data(); + accumulator[1] = accumulatorData.data() + width; + accumulator[2] = accumulatorData.data() + (width * 2); + accumulator[3] = accumulatorData.data() + (width * 3); + + // Produce the conversion lookup tables. + for (i = 0; i < 256; i++) { + lookup_8bit_to_4bit[i] = round(i / 16.0); + // Before bitshifts: (i * 8) - (... * 16 * 8) + lookup_8bit_to_4bit_diff[i] = (i << 3) - (lookup_8bit_to_4bit[i] << 7); + + if (lookup_8bit_to_4bit[i] > 15) + lookup_8bit_to_4bit[i] = 15; + } + + // Clear the accumulators + memset(accumulator[0], 0, width * 4); + memset(accumulator[1], 0, width * 4); + memset(accumulator[2], 0, width * 4); + memset(accumulator[3], 0, width * 4); + + // For each line... + for (y = 0; y < height; y++) { + + // For each component (r, g, b, a)... + memcpy(accumulator[0], accumulator[0] + width, width * 2); + memset(accumulator[0] + width, 0, width * 2); + + memcpy(accumulator[1], accumulator[1] + width, width * 2); + memset(accumulator[1] + width, 0, width * 2); + + memcpy(accumulator[2], accumulator[2] + width, width * 2); + memset(accumulator[2] + width, 0, width * 2); + + memcpy(accumulator[3], accumulator[3] + width, width * 2); + memset(accumulator[3] + width, 0, width * 2); + + // For each column.... + for (x = 0; x < width; x++) { + + // For each component (r, g, b, a)... + for (c = 0; c < 4; c++) { + + // Get the 8bit value from the original image + component[c] = GET_RGBA_COMPONENT(in, x, y, stride, c); + + // Add the diffusion for this pixel we stored in the accumulator. + // >> 7 because the values in accumulator are stored * 128 + component[c] += accumulator[c][x] >> 7; + + // Make sure we're not over the boundaries. + CLAMP_256(component[c]); + + // Store the difference from converting 8bit => 4bit and the orig pixel. + // Convert 8bit => 4bit. + diff = DIFF_8BIT_TO_4BIT(component[c]); + component[c] = CONVERT_8BIT_TO_4BIT(component[c]); + + // Distribute the difference according to the matrix in the + // accumulation bufffer. + ACCUMULATE(accumulator[c], x + 1, 0, width, diff * 7); + ACCUMULATE(accumulator[c], x - 1, 1, width, diff * 3); + ACCUMULATE(accumulator[c], x, 1, width, diff * 5); + ACCUMULATE(accumulator[c], x + 1, 1, width, diff * 1); + } + + // Write the newly produced pixel + PUT_4444(out, x, y, alignedWidth, component[0], component[1], component[2], component[3]); + } + } + + return out; +} + +unsigned char* convertBGRA32_to_RGBA32(const unsigned char *in, int width, int height, int stride) +{ + unsigned char *out = (unsigned char *) malloc(stride * height); + + // For each line... + for (int y = 0; y < height; y++) { + // For each column + for (int x = 0; x < width; x++) { + out[(stride * y) + (x * 4) + 0] = in[(stride * y) + (x * 4) + 2]; + out[(stride * y) + (x * 4) + 1] = in[(stride * y) + (x * 4) + 1]; + out[(stride * y) + (x * 4) + 2] = in[(stride * y) + (x * 4) + 0]; + out[(stride * y) + (x * 4) + 3] = in[(stride * y) + (x * 4) + 3]; + } + } + + return out; +} diff --git a/src/plugins/graphicssystems/meego/meego.pro b/src/plugins/graphicssystems/meego/meego.pro new file mode 100644 index 0000000..0d3cce6 --- /dev/null +++ b/src/plugins/graphicssystems/meego/meego.pro @@ -0,0 +1,13 @@ +TARGET = qmeegographicssystem +include(../../qpluginbase.pri) + +QT += gui opengl + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems + +HEADERS = qmeegographicssystem.h qmeegopixmapdata.h qmeegoextensions.h qmeegorasterpixmapdata.h qmeegolivepixmapdata.h +SOURCES = qmeegographicssystem.cpp qmeegographicssystem.h qmeegographicssystemplugin.h qmeegographicssystemplugin.cpp qmeegopixmapdata.h qmeegopixmapdata.cpp qmeegoextensions.h qmeegoextensions.cpp qmeegorasterpixmapdata.h qmeegorasterpixmapdata.cpp qmeegolivepixmapdata.cpp qmeegolivepixmapdata.h dithering.cpp + +target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems +INSTALLS += target + diff --git a/src/plugins/graphicssystems/meego/qmeegoextensions.cpp b/src/plugins/graphicssystems/meego/qmeegoextensions.cpp new file mode 100644 index 0000000..dff80a4 --- /dev/null +++ b/src/plugins/graphicssystems/meego/qmeegoextensions.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmeegoextensions.h" +#include <private/qeglcontext_p.h> +#include <private/qpixmapdata_gl_p.h> + +bool QMeeGoExtensions::initialized = false; +bool QMeeGoExtensions::hasImageShared = false; +bool QMeeGoExtensions::hasSurfaceScaling = false; +bool QMeeGoExtensions::hasLockSurface = false; +bool QMeeGoExtensions::hasFenceSync = false; + +/* Extension funcs */ + +typedef EGLBoolean (EGLAPIENTRY *eglQueryImageNOKFunc)(EGLDisplay, EGLImageKHR, EGLint, EGLint*); +typedef EGLNativeSharedImageTypeNOK (EGLAPIENTRY *eglCreateSharedImageNOKFunc)(EGLDisplay, EGLImageKHR, EGLint*); +typedef EGLBoolean (EGLAPIENTRY *eglDestroySharedImageNOKFunc)(EGLDisplay, EGLNativeSharedImageTypeNOK); +typedef EGLBoolean (EGLAPIENTRY *eglSetSurfaceScalingNOKFunc)(EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint); +typedef EGLBoolean (EGLAPIENTRY *eglLockSurfaceKHRFunc)(EGLDisplay, EGLSurface, const EGLint*); +typedef EGLBoolean (EGLAPIENTRY *eglUnlockSurfaceKHRFunc)(EGLDisplay, EGLSurface); +typedef EGLSyncKHR (EGLAPIENTRY *eglCreateSyncKHRFunc)(EGLDisplay, EGLenum, const EGLint*); +typedef EGLBoolean (EGLAPIENTRY *eglDestroySyncKHRFunc)(EGLDisplay, EGLSyncKHR); +typedef EGLint (EGLAPIENTRY *eglClientWaitSyncKHRFunc)(EGLDisplay, EGLSyncKHR, EGLint, EGLTimeKHR); +typedef EGLBoolean (EGLAPIENTRY *eglGetSyncAttribKHRFunc)(EGLDisplay, EGLSyncKHR, EGLint, EGLint*); + +static eglQueryImageNOKFunc _eglQueryImageNOK = 0; +static eglCreateSharedImageNOKFunc _eglCreateSharedImageNOK = 0; +static eglDestroySharedImageNOKFunc _eglDestroySharedImageNOK = 0; +static eglSetSurfaceScalingNOKFunc _eglSetSurfaceScalingNOK = 0; +static eglLockSurfaceKHRFunc _eglLockSurfaceKHR = 0; +static eglUnlockSurfaceKHRFunc _eglUnlockSurfaceKHR = 0; +static eglCreateSyncKHRFunc _eglCreateSyncKHR = 0; +static eglDestroySyncKHRFunc _eglDestroySyncKHR = 0; +static eglClientWaitSyncKHRFunc _eglClientWaitSyncKHR = 0; +static eglGetSyncAttribKHRFunc _eglGetSyncAttribKHR = 0; + +/* Public */ + +void QMeeGoExtensions::ensureInitialized() +{ + if (!initialized) + initialize(); + + initialized = true; +} + +EGLNativeSharedImageTypeNOK QMeeGoExtensions::eglCreateSharedImageNOK(EGLDisplay dpy, EGLImageKHR image, EGLint *props) +{ + if (!hasImageShared) + qFatal("EGL_NOK_image_shared not found but trying to use capability!"); + + return _eglCreateSharedImageNOK(dpy, image, props); +} + +bool QMeeGoExtensions::eglQueryImageNOK(EGLDisplay dpy, EGLImageKHR image, EGLint prop, EGLint *v) +{ + if (!hasImageShared) + qFatal("EGL_NOK_image_shared not found but trying to use capability!"); + + return _eglQueryImageNOK(dpy, image, prop, v); +} + +bool QMeeGoExtensions::eglDestroySharedImageNOK(EGLDisplay dpy, EGLNativeSharedImageTypeNOK img) +{ + if (!hasImageShared) + qFatal("EGL_NOK_image_shared not found but trying to use capability!"); + + return _eglDestroySharedImageNOK(dpy, img); +} + +bool QMeeGoExtensions::eglSetSurfaceScalingNOK(EGLDisplay dpy, EGLSurface surface, int x, int y, int width, int height) +{ + if (!hasSurfaceScaling) + qFatal("EGL_NOK_surface_scaling not found but trying to use capability!"); + + return _eglSetSurfaceScalingNOK(dpy, surface, x, y, width, height); +} + +bool QMeeGoExtensions::eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list) +{ + if (!hasLockSurface) + qFatal("EGL_KHR_lock_surface2 not found but trying to use capability!"); + + return _eglLockSurfaceKHR(display, surface, attrib_list); +} + +bool QMeeGoExtensions::eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface) +{ + if (!hasLockSurface) + qFatal("EGL_KHR_lock_surface2 not found but trying to use capability!"); + + return _eglUnlockSurfaceKHR(display, surface); +} + +EGLSyncKHR QMeeGoExtensions::eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) +{ + if (!hasFenceSync) + qFatal("EGL_KHR_fence_sync not found but trying to use capability!"); + + return _eglCreateSyncKHR(dpy, type, attrib_list); +} + +bool QMeeGoExtensions::eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) +{ + if (!hasFenceSync) + qFatal("EGL_KHR_fence_sync not found but trying to use capability!"); + + return _eglDestroySyncKHR(dpy, sync); +} + +EGLint QMeeGoExtensions::eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) +{ + if (!hasFenceSync) + qFatal("EGL_KHR_fence_sync not found but trying to use capability!"); + + return _eglClientWaitSyncKHR(dpy, sync, flags, timeout); +} + +EGLBoolean QMeeGoExtensions::eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) +{ + if (!hasFenceSync) + qFatal("EGL_KHR_fence_sync not found but trying to use capability!"); + + return _eglGetSyncAttribKHR(dpy, sync, attribute, value); +} + +/* Private */ + +void QMeeGoExtensions::initialize() +{ + QGLContext *ctx = (QGLContext *) QGLContext::currentContext(); + qt_resolve_eglimage_gl_extensions(ctx); + + if (QEgl::hasExtension("EGL_NOK_image_shared")) { + qDebug("MeegoGraphics: found EGL_NOK_image_shared"); + _eglQueryImageNOK = (eglQueryImageNOKFunc) eglGetProcAddress("eglQueryImageNOK"); + _eglCreateSharedImageNOK = (eglCreateSharedImageNOKFunc) eglGetProcAddress("eglCreateSharedImageNOK"); + _eglDestroySharedImageNOK = (eglDestroySharedImageNOKFunc) eglGetProcAddress("eglDestroySharedImageNOK"); + _eglLockSurfaceKHR = (eglLockSurfaceKHRFunc) eglGetProcAddress("eglLockSurfaceKHR"); + _eglUnlockSurfaceKHR = (eglUnlockSurfaceKHRFunc) eglGetProcAddress("eglUnlockSurfaceKHR"); + + Q_ASSERT(_eglQueryImageNOK && _eglCreateSharedImageNOK && _eglDestroySharedImageNOK); + hasImageShared = true; + } + + if (QEgl::hasExtension("EGL_NOK_surface_scaling")) { + qDebug("MeegoGraphics: found EGL_NOK_surface_scaling"); + _eglSetSurfaceScalingNOK = (eglSetSurfaceScalingNOKFunc) eglGetProcAddress("eglSetSurfaceScalingNOK"); + + Q_ASSERT(_eglSetSurfaceScalingNOK); + hasSurfaceScaling = true; + } + + if (QEgl::hasExtension("EGL_KHR_lock_surface2")) { + qDebug("MeegoGraphics: found EGL_KHR_lock_surface2"); + _eglLockSurfaceKHR = (eglLockSurfaceKHRFunc) eglGetProcAddress("eglLockSurfaceKHR"); + _eglUnlockSurfaceKHR = (eglUnlockSurfaceKHRFunc) eglGetProcAddress("eglUnlockSurfaceKHR"); + + Q_ASSERT(_eglLockSurfaceKHR && _eglUnlockSurfaceKHR); + hasLockSurface = true; + } + + if (QEgl::hasExtension("EGL_KHR_fence_sync")) { + qDebug("MeegoGraphics: found EGL_KHR_fence_sync"); + _eglCreateSyncKHR = (eglCreateSyncKHRFunc) eglGetProcAddress("eglCreateSyncKHR"); + _eglDestroySyncKHR = (eglDestroySyncKHRFunc) eglGetProcAddress("eglDestroySyncKHR"); + _eglClientWaitSyncKHR = (eglClientWaitSyncKHRFunc) eglGetProcAddress("eglClientWaitSyncKHR"); + _eglGetSyncAttribKHR = (eglGetSyncAttribKHRFunc) eglGetProcAddress("eglGetSyncAttribKHR"); + + Q_ASSERT(_eglCreateSyncKHR && _eglDestroySyncKHR && _eglClientWaitSyncKHR && _eglGetSyncAttribKHR); + hasFenceSync = true; + } +} + diff --git a/src/plugins/graphicssystems/meego/qmeegoextensions.h b/src/plugins/graphicssystems/meego/qmeegoextensions.h new file mode 100644 index 0000000..49a1e30 --- /dev/null +++ b/src/plugins/graphicssystems/meego/qmeegoextensions.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MEXTENSIONS_H +#define MEXTENSIONS_H + +#include <private/qgl_p.h> +#include <private/qeglcontext_p.h> +#include <private/qpixmapdata_gl_p.h> +#include <EGL/egl.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +/* Extensions decls */ + +#ifndef EGL_SHARED_IMAGE_NOK +#define EGL_SHARED_IMAGE_NOK 0x30DA +typedef void* EGLNativeSharedImageTypeNOK; +#endif + +#ifndef EGL_GL_TEXTURE_2D_KHR +#define EGL_GL_TEXTURE_2D_KHR 0x30B1 +#endif + +#ifndef EGL_FIXED_WIDTH_NOK +#define EGL_FIXED_WIDTH_NOK 0x30DB +#define EGL_FIXED_HEIGHT_NOK 0x30DC +#endif + +#ifndef EGL_BITMAP_POINTER_KHR +#define EGL_BITMAP_POINTER_KHR 0x30C6 +#define EGL_BITMAP_PITCH_KHR 0x30C7 +#endif + +#ifndef EGL_MAP_PRESERVE_PIXELS_KHR +#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 +#define EGL_LOCK_USAGE_HINT_KHR 0x30C5 +#define EGL_READ_SURFACE_BIT_KHR 0x0001 +#define EGL_WRITE_SURFACE_BIT_KHR 0x0002 +#endif + +#ifndef EGL_SYNC_FENCE_KHR +#define EGL_SYNC_FENCE_KHR 0x30F9 +#define EGL_SYNC_TYPE_KHR 0x30F7 +#define EGL_SYNC_STATUS_KHR 0x30F1 +#define EGL_SYNC_CONDITION_KHR 0x30F8 +#define EGL_SIGNALED_KHR 0x30F2 +#define EGL_UNSIGNALED_KHR 0x30F3 +#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0 +#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001 +#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull +#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5 +#define EGL_CONDITION_SATISFIED_KHR 0x30F6 +#define EGL_NO_SYNC_KHR ((EGLSyncKHR)0) +typedef void* EGLSyncKHR; +typedef khronos_utime_nanoseconds_t EGLTimeKHR; +#endif + +/* Class */ + +class QMeeGoExtensions +{ +public: + static void ensureInitialized(); + + static EGLNativeSharedImageTypeNOK eglCreateSharedImageNOK(EGLDisplay dpy, EGLImageKHR image, EGLint *props); + static bool eglQueryImageNOK(EGLDisplay dpy, EGLImageKHR image, EGLint prop, EGLint *v); + static bool eglDestroySharedImageNOK(EGLDisplay dpy, EGLNativeSharedImageTypeNOK img); + static bool eglSetSurfaceScalingNOK(EGLDisplay dpy, EGLSurface surface, int x, int y, int width, int height); + static bool eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); + static bool eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface); + static EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); + static bool eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync); + static EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); + static EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value); + +private: + static void initialize(); + + static bool initialized; + static bool hasImageShared; + static bool hasSurfaceScaling; + static bool hasLockSurface; + static bool hasFenceSync; +}; + +#endif diff --git a/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp b/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp new file mode 100644 index 0000000..063af13 --- /dev/null +++ b/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> +#include <private/qpixmap_raster_p.h> +#include <private/qwindowsurface_gl_p.h> +#include <private/qegl_p.h> +#include <private/qglextensions_p.h> +#include <private/qgl_p.h> +#include <private/qimagepixmapcleanuphooks_p.h> +#include <private/qapplication_p.h> +#include <private/qgraphicssystem_runtime_p.h> +#include <private/qimage_p.h> +#include <private/qeglproperties_p.h> +#include <private/qeglcontext_p.h> +#include <private/qpixmap_x11_p.h> + +#include "qmeegopixmapdata.h" +#include "qmeegolivepixmapdata.h" +#include "qmeegographicssystem.h" +#include "qmeegoextensions.h" + +bool QMeeGoGraphicsSystem::surfaceWasCreated = false; + +QHash <Qt::HANDLE, QPixmap*> QMeeGoGraphicsSystem::liveTexturePixmaps; + +QMeeGoGraphicsSystem::QMeeGoGraphicsSystem() +{ + qDebug("Using the meego graphics system"); +} + +QMeeGoGraphicsSystem::~QMeeGoGraphicsSystem() +{ + qDebug("Meego graphics system destroyed"); + qt_destroy_gl_share_widget(); +} + +QWindowSurface* QMeeGoGraphicsSystem::createWindowSurface(QWidget *widget) const +{ + QMeeGoGraphicsSystem::surfaceWasCreated = true; + QWindowSurface *surface = new QGLWindowSurface(widget); + return surface; +} + +QPixmapData *QMeeGoGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +{ + // Long story short: without this it's possible to hit an + // unitialized paintDevice due to a Qt bug too complex to even + // explain here... not to mention fix without going crazy. + // MDK + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + + return new QRasterPixmapData(type); +} + +QPixmapData *QMeeGoGraphicsSystem::createPixmapData(QPixmapData *origin) +{ + // If the pixmap is a raster type... + // and if the pixmap pointer matches our mapping... + // create a shared image instead with the given handle. + + if (origin->classId() == QPixmapData::RasterClass) { + QRasterPixmapData *rasterClass = static_cast <QRasterPixmapData *> (origin); + void *rawResource = static_cast <void *> (rasterClass->buffer()->data_ptr()->data); + + if (QMeeGoPixmapData::sharedImagesMap.contains(rawResource)) + return new QMeeGoPixmapData(); + } + + return new QRasterPixmapData(origin->pixelType()); +} + +QPixmapData* QMeeGoGraphicsSystem::wrapPixmapData(QPixmapData *pmd) +{ + QString name = QApplicationPrivate::instance()->graphics_system_name; + if (name == "runtime") { + QRuntimeGraphicsSystem *rsystem = (QRuntimeGraphicsSystem *) QApplicationPrivate::instance()->graphics_system; + QRuntimePixmapData *rt = new QRuntimePixmapData(rsystem, pmd->pixelType());; + rt->m_data = pmd; + rt->readBackInfo(); + rsystem->m_pixmapDatas << rt; + return rt; + } else + return pmd; +} + +void QMeeGoGraphicsSystem::setSurfaceFixedSize(int /*width*/, int /*height*/) +{ + if (QMeeGoGraphicsSystem::surfaceWasCreated) + qWarning("Trying to set surface fixed size but surface already created!"); + +#ifdef QT_WAS_PATCHED + QEglProperties *properties = new QEglProperties(); + properties->setValue(EGL_FIXED_WIDTH_NOK, width); + properties->setValue(EGL_FIXED_HEIGHT_NOK, height); + QGLContextPrivate::setExtraWindowSurfaceCreationProps(properties); +#endif +} + +void QMeeGoGraphicsSystem::setSurfaceScaling(int x, int y, int width, int height) +{ + QMeeGoExtensions::ensureInitialized(); + QMeeGoExtensions::eglSetSurfaceScalingNOK(QEgl::display(), QEglContext::currentContext(QEgl::OpenGL)->currentSurface, x, y, width, height); +} + +void QMeeGoGraphicsSystem::setTranslucent(bool translucent) +{ + QGLWindowSurface::surfaceFormat.setSampleBuffers(false); + QGLWindowSurface::surfaceFormat.setSamples(0); + QGLWindowSurface::surfaceFormat.setAlpha(translucent); +} + +QPixmapData *QMeeGoGraphicsSystem::pixmapDataFromEGLSharedImage(Qt::HANDLE handle, const QImage &softImage) +{ + if (softImage.format() != QImage::Format_ARGB32_Premultiplied && + softImage.format() != QImage::Format_RGB32) { + qFatal("For egl shared images, the soft image has to be ARGB32_Premultiplied or RGB32"); + return NULL; + } + + if (QMeeGoGraphicsSystem::meeGoRunning()) { + QMeeGoPixmapData *pmd = new QMeeGoPixmapData; + pmd->fromEGLSharedImage(handle, softImage); + return QMeeGoGraphicsSystem::wrapPixmapData(pmd); + } else { + QRasterPixmapData *pmd = new QRasterPixmapData(QPixmapData::PixmapType); + pmd->fromImage(softImage, Qt::NoOpaqueDetection); + + // Make sure that the image was not converted in any way + if (pmd->buffer()->data_ptr()->data != + const_cast<QImage &>(softImage).data_ptr()->data) + qFatal("Iternal misalignment of raster data detected. Prolly a QImage copy fail."); + + QMeeGoPixmapData::registerSharedImage(handle, softImage); + return QMeeGoGraphicsSystem::wrapPixmapData(pmd); + } +} + +void QMeeGoGraphicsSystem::updateEGLSharedImagePixmap(QPixmap *pixmap) +{ + QMeeGoPixmapData *pmd = (QMeeGoPixmapData *) pixmap->pixmapData(); + + // Basic sanity check to make sure this is really a QMeeGoPixmapData... + if (pmd->classId() != QPixmapData::OpenGLClass) + qFatal("Trying to updated EGLSharedImage pixmap but it's not really a shared image pixmap!"); + + pmd->updateFromSoftImage(); +} + +QPixmapData *QMeeGoGraphicsSystem::pixmapDataWithGLTexture(int w, int h) +{ + QGLPixmapData *pmd = new QGLPixmapData(QPixmapData::PixmapType); + pmd->resize(w, h); + return QMeeGoGraphicsSystem::wrapPixmapData(pmd); +} + +bool QMeeGoGraphicsSystem::meeGoRunning() +{ + if (! QApplicationPrivate::instance()) { + qWarning("Application not running just yet... hard to know what system running!"); + return false; + } + + QString name = QApplicationPrivate::instance()->graphics_system_name; + if (name == "runtime") { + QRuntimeGraphicsSystem *rsystem = (QRuntimeGraphicsSystem *) QApplicationPrivate::instance()->graphics_system; + name = rsystem->graphicsSystemName(); + } + + return (name == "meego"); +} + +QPixmapData* QMeeGoGraphicsSystem::pixmapDataWithNewLiveTexture(int w, int h, QImage::Format format) +{ + return new QMeeGoLivePixmapData(w, h, format); +} + +QPixmapData* QMeeGoGraphicsSystem::pixmapDataFromLiveTextureHandle(Qt::HANDLE handle) +{ + return new QMeeGoLivePixmapData(handle); +} + +QImage* QMeeGoGraphicsSystem::lockLiveTexture(QPixmap* pixmap, void* fenceSync) +{ + QMeeGoLivePixmapData *pixmapData = static_cast<QMeeGoLivePixmapData*>(pixmap->data_ptr().data()); + return pixmapData->lock(fenceSync); +} + +bool QMeeGoGraphicsSystem::releaseLiveTexture(QPixmap *pixmap, QImage *image) +{ + QMeeGoLivePixmapData *pixmapData = static_cast<QMeeGoLivePixmapData*>(pixmap->data_ptr().data()); + return pixmapData->release(image); +} + +Qt::HANDLE QMeeGoGraphicsSystem::getLiveTextureHandle(QPixmap *pixmap) +{ + QMeeGoLivePixmapData *pixmapData = static_cast<QMeeGoLivePixmapData*>(pixmap->data_ptr().data()); + return pixmapData->handle(); +} + +void* QMeeGoGraphicsSystem::createFenceSync() +{ + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + QMeeGoExtensions::ensureInitialized(); + return QMeeGoExtensions::eglCreateSyncKHR(QEgl::display(), EGL_SYNC_FENCE_KHR, NULL); +} + +void QMeeGoGraphicsSystem::destroyFenceSync(void *fenceSync) +{ + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + QMeeGoExtensions::ensureInitialized(); + QMeeGoExtensions::eglDestroySyncKHR(QEgl::display(), fenceSync); +} + +/* C API */ + +int qt_meego_image_to_egl_shared_image(const QImage &image) +{ + return QMeeGoPixmapData::imageToEGLSharedImage(image); +} + +QPixmapData* qt_meego_pixmapdata_from_egl_shared_image(Qt::HANDLE handle, const QImage &softImage) +{ + return QMeeGoGraphicsSystem::pixmapDataFromEGLSharedImage(handle, softImage); +} + +QPixmapData* qt_meego_pixmapdata_with_gl_texture(int w, int h) +{ + return QMeeGoGraphicsSystem::pixmapDataWithGLTexture(w, h); +} + +bool qt_meego_destroy_egl_shared_image(Qt::HANDLE handle) +{ + return QMeeGoPixmapData::destroyEGLSharedImage(handle); +} + +void qt_meego_set_surface_fixed_size(int width, int height) +{ + QMeeGoGraphicsSystem::setSurfaceFixedSize(width, height); +} + +void qt_meego_set_surface_scaling(int x, int y, int width, int height) +{ + QMeeGoGraphicsSystem::setSurfaceScaling(x, y, width, height); +} + +void qt_meego_set_translucent(bool translucent) +{ + QMeeGoGraphicsSystem::setTranslucent(translucent); +} + +void qt_meego_update_egl_shared_image_pixmap(QPixmap *pixmap) +{ + QMeeGoGraphicsSystem::updateEGLSharedImagePixmap(pixmap); +} + +QPixmapData* qt_meego_pixmapdata_with_new_live_texture(int w, int h, QImage::Format format) +{ + return QMeeGoGraphicsSystem::pixmapDataWithNewLiveTexture(w, h, format); +} + +QPixmapData* qt_meego_pixmapdata_from_live_texture_handle(Qt::HANDLE handle) +{ + return QMeeGoGraphicsSystem::pixmapDataFromLiveTextureHandle(handle); +} + +QImage* qt_meego_live_texture_lock(QPixmap *pixmap, void *fenceSync) +{ + return QMeeGoGraphicsSystem::lockLiveTexture(pixmap, fenceSync); +} + +bool qt_meego_live_texture_release(QPixmap *pixmap, QImage *image) +{ + return QMeeGoGraphicsSystem::releaseLiveTexture(pixmap, image); +} + +Qt::HANDLE qt_meego_live_texture_get_handle(QPixmap *pixmap) +{ + return QMeeGoGraphicsSystem::getLiveTextureHandle(pixmap); +} + +void* qt_meego_create_fence_sync(void) +{ + return QMeeGoGraphicsSystem::createFenceSync(); +} + +void qt_meego_destroy_fence_sync(void* fs) +{ + return QMeeGoGraphicsSystem::destroyFenceSync(fs); +} diff --git a/src/plugins/graphicssystems/meego/qmeegographicssystem.h b/src/plugins/graphicssystems/meego/qmeegographicssystem.h new file mode 100644 index 0000000..1e50f00 --- /dev/null +++ b/src/plugins/graphicssystems/meego/qmeegographicssystem.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MGRAPHICSSYSTEM_H +#define MGRAPHICSSYSTEM_H + +#include <private/qgraphicssystem_p.h> +#include <EGL/egl.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +class QMeeGoGraphicsSystem : public QGraphicsSystem +{ +public: + QMeeGoGraphicsSystem(); + ~QMeeGoGraphicsSystem(); + + virtual QWindowSurface *createWindowSurface(QWidget *widget) const; + virtual QPixmapData *createPixmapData(QPixmapData::PixelType) const; + virtual QPixmapData *createPixmapData(QPixmapData *origin); + + static QPixmapData *wrapPixmapData(QPixmapData *pmd); + static void setSurfaceFixedSize(int width, int height); + static void setSurfaceScaling(int x, int y, int width, int height); + static void setTranslucent(bool translucent); + + static QPixmapData *pixmapDataFromEGLSharedImage(Qt::HANDLE handle, const QImage &softImage); + static QPixmapData *pixmapDataFromEGLImage(Qt::HANDLE handle); + static QPixmapData *pixmapDataWithGLTexture(int w, int h); + static void updateEGLSharedImagePixmap(QPixmap *pixmap); + + static QPixmapData *pixmapDataWithNewLiveTexture(int w, int h, QImage::Format format); + static QPixmapData *pixmapDataFromLiveTextureHandle(Qt::HANDLE handle); + static QImage *lockLiveTexture(QPixmap* pixmap, void* fenceSync); + static bool releaseLiveTexture(QPixmap *pixmap, QImage *image); + static Qt::HANDLE getLiveTextureHandle(QPixmap *pixmap); + + static void* createFenceSync(); + static void destroyFenceSync(void* fenceSync); + +private: + static bool meeGoRunning(); + static EGLSurface getSurfaceForLiveTexturePixmap(QPixmap *pixmap); + static void destroySurfaceForLiveTexturePixmap(QPixmapData* pmd); + + static bool surfaceWasCreated; + static QHash <Qt::HANDLE, QPixmap*> liveTexturePixmaps; +}; + +/* C api */ + +extern "C" { + Q_DECL_EXPORT int qt_meego_image_to_egl_shared_image(const QImage &image); + Q_DECL_EXPORT QPixmapData* qt_meego_pixmapdata_from_egl_shared_image(Qt::HANDLE handle, const QImage &softImage); + Q_DECL_EXPORT QPixmapData* qt_meego_pixmapdata_with_gl_texture(int w, int h); + Q_DECL_EXPORT void qt_meego_update_egl_shared_image_pixmap(QPixmap *pixmap); + Q_DECL_EXPORT bool qt_meego_destroy_egl_shared_image(Qt::HANDLE handle); + Q_DECL_EXPORT void qt_meego_set_surface_fixed_size(int width, int height); + Q_DECL_EXPORT void qt_meego_set_surface_scaling(int x, int y, int width, int height); + Q_DECL_EXPORT void qt_meego_set_translucent(bool translucent); + Q_DECL_EXPORT QPixmapData* qt_meego_pixmapdata_with_new_live_texture(int w, int h, QImage::Format format); + Q_DECL_EXPORT QPixmapData* qt_meego_pixmapdata_from_live_texture_handle(Qt::HANDLE handle); + Q_DECL_EXPORT QImage* qt_meego_live_texture_lock(QPixmap *pixmap, void *fenceSync); + Q_DECL_EXPORT bool qt_meego_live_texture_release(QPixmap *pixmap, QImage *image); + Q_DECL_EXPORT Qt::HANDLE qt_meego_live_texture_get_handle(QPixmap *pixmap); + Q_DECL_EXPORT void* qt_meego_create_fence_sync(void); + Q_DECL_EXPORT void qt_meego_destroy_fence_sync(void* fs); +} + +#endif diff --git a/src/plugins/graphicssystems/meego/qmeegographicssystemplugin.cpp b/src/plugins/graphicssystems/meego/qmeegographicssystemplugin.cpp new file mode 100644 index 0000000..7c142eb --- /dev/null +++ b/src/plugins/graphicssystems/meego/qmeegographicssystemplugin.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> +#include "qmeegographicssystemplugin.h" +#include "qmeegographicssystem.h" + +QStringList QMeeGoGraphicsSystemPlugin::keys() const +{ + QStringList list; + list << "meego"; + return list; +} + +QGraphicsSystem *QMeeGoGraphicsSystemPlugin::create(const QString&) +{ + return new QMeeGoGraphicsSystem; +} + +Q_EXPORT_PLUGIN2(meego, QMeeGoGraphicsSystemPlugin) diff --git a/src/plugins/graphicssystems/meego/qmeegographicssystemplugin.h b/src/plugins/graphicssystems/meego/qmeegographicssystemplugin.h new file mode 100644 index 0000000..336458f --- /dev/null +++ b/src/plugins/graphicssystems/meego/qmeegographicssystemplugin.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MGRAPHICSSYSTEMPLUGIN_H +#define MGRAPHICSSYSTEMPLUGIN_H + +#include <private/qgraphicssystemplugin_p.h> + +class QMeeGoGraphicsSystemPlugin : public QGraphicsSystemPlugin +{ +public: + virtual QStringList keys() const; + virtual QGraphicsSystem *create(const QString&); +}; + +#endif diff --git a/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp b/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp new file mode 100644 index 0000000..16096c9 --- /dev/null +++ b/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmeegolivepixmapdata.h" +#include "qmeegorasterpixmapdata.h" +#include <private/qimage_p.h> +#include <private/qwindowsurface_gl_p.h> +#include <private/qeglcontext_p.h> +#include <private/qapplication_p.h> +#include <private/qgraphicssystem_runtime_p.h> +#include <private/qpixmap_x11_p.h> +#include <stdio.h> + +static EGLint lock_attribs[] = { + EGL_MAP_PRESERVE_PIXELS_KHR, EGL_TRUE, + EGL_LOCK_USAGE_HINT_KHR, EGL_READ_SURFACE_BIT_KHR | EGL_WRITE_SURFACE_BIT_KHR, + EGL_NONE +}; + +static EGLint preserved_attribs[] = { + EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, + EGL_NONE +}; + +// as copied from qwindowsurface.cpp +void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset) +{ + // make sure we don't detach + uchar *mem = const_cast<uchar*>(const_cast<const QImage &>(img).bits()); + + int lineskip = img.bytesPerLine(); + int depth = img.depth() >> 3; + + const QRect imageRect(0, 0, img.width(), img.height()); + const QRect r = rect & imageRect & imageRect.translated(-offset); + const QPoint p = rect.topLeft() + offset; + + if (r.isEmpty()) + return; + + const uchar *src; + uchar *dest; + + if (r.top() < p.y()) { + src = mem + r.bottom() * lineskip + r.left() * depth; + dest = mem + (p.y() + r.height() - 1) * lineskip + p.x() * depth; + lineskip = -lineskip; + } else { + src = mem + r.top() * lineskip + r.left() * depth; + dest = mem + p.y() * lineskip + p.x() * depth; + } + + const int w = r.width(); + int h = r.height(); + const int bytes = w * depth; + + // overlapping segments? + if (offset.y() == 0 && qAbs(offset.x()) < w) { + do { + ::memmove(dest, src, bytes); + dest += lineskip; + src += lineskip; + } while (--h); + } else { + do { + ::memcpy(dest, src, bytes); + dest += lineskip; + src += lineskip; + } while (--h); + } +} + +/* Public */ + +QMeeGoLivePixmapData::QMeeGoLivePixmapData(int w, int h, QImage::Format format) : QGLPixmapData(QPixmapData::PixmapType) +{ + QImage image(w, h, format); + QX11PixmapData *pmd = new QX11PixmapData(QPixmapData::PixmapType); + pmd->fromImage(image, Qt::NoOpaqueDetection); + backingX11Pixmap = new QPixmap(pmd); + + initializeThroughEGLImage(); +} + +QMeeGoLivePixmapData::QMeeGoLivePixmapData(Qt::HANDLE h) : QGLPixmapData(QPixmapData::PixmapType) +{ + backingX11Pixmap = new QPixmap(QPixmap::fromX11Pixmap(h)); + initializeThroughEGLImage(); +} + +QMeeGoLivePixmapData::~QMeeGoLivePixmapData() +{ + delete backingX11Pixmap; +} + +void QMeeGoLivePixmapData::initializeThroughEGLImage() +{ + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + QMeeGoExtensions::ensureInitialized(); + + EGLImageKHR eglImage = EGL_NO_IMAGE_KHR; + GLuint newTextureId = 0; + + eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, + (EGLClientBuffer) backingX11Pixmap->handle(), preserved_attribs); + + if (eglImage == EGL_NO_IMAGE_KHR) { + qWarning("eglCreateImageKHR failed (live texture)!"); + return; + } + + glGenTextures(1, &newTextureId); + glBindTexture(GL_TEXTURE_2D, newTextureId); + + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (EGLImageKHR) eglImage); + if (glGetError() == GL_NO_ERROR) { + resize(backingX11Pixmap->width(), backingX11Pixmap->height()); + texture()->id = newTextureId; + texture()->options &= ~QGLContext::InvertedYBindOption; + m_hasAlpha = backingX11Pixmap->hasAlphaChannel(); + } else { + qWarning("Failed to create a texture from an egl image (live texture)!"); + glDeleteTextures(1, &newTextureId); + } + + QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); +} + +QPixmapData *QMeeGoLivePixmapData::createCompatiblePixmapData() const +{ + qWarning("Create compatible called on live pixmap! Expect fail soon..."); + return new QMeeGoRasterPixmapData(pixelType()); +} + +QImage* QMeeGoLivePixmapData::lock(EGLSyncKHR fenceSync) +{ + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + QMeeGoExtensions::ensureInitialized(); + + if (fenceSync) { + QMeeGoExtensions::eglClientWaitSyncKHR(QEgl::display(), + fenceSync, + EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, + EGL_FOREVER_KHR); + } + + void *data = 0; + int pitch = 0; + EGLSurface surface = 0; + QImage::Format format; + lockedImage = QImage(); + + surface = getSurfaceForBackingPixmap(); + if (! QMeeGoExtensions::eglLockSurfaceKHR(QEgl::display(), surface, lock_attribs)) { + qWarning("Failed to lock surface (live texture)!"); + return &lockedImage; + } + + eglQuerySurface(QEgl::display(), surface, EGL_BITMAP_POINTER_KHR, (EGLint*) &data); + eglQuerySurface(QEgl::display(), surface, EGL_BITMAP_PITCH_KHR, (EGLint*) &pitch); + + // Ok, here we know we just support those two formats. Real solution would be: + // uqery also the format. + if (backingX11Pixmap->depth() > 16) + format = QImage::Format_ARGB32_Premultiplied; + else + format = QImage::Format_RGB16; + + if (data == NULL || pitch == 0) { + qWarning("Failed to query the live texture!"); + return &lockedImage; + } + + lockedImage = QImage((uchar *) data, width(), height(), format); + return &lockedImage; +} + +bool QMeeGoLivePixmapData::release(QImage* /*img*/) +{ + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + QMeeGoExtensions::ensureInitialized(); + + if (QMeeGoExtensions::eglUnlockSurfaceKHR(QEgl::display(), getSurfaceForBackingPixmap())) { + lockedImage = QImage(); + return true; + } else { + lockedImage = QImage(); + return false; + } +} + +Qt::HANDLE QMeeGoLivePixmapData::handle() +{ + return backingX11Pixmap->handle(); +} + +bool QMeeGoLivePixmapData::scroll(int dx, int dy, const QRect &rect) +{ + lock(NULL); + + if (!lockedImage.isNull()) + qt_scrollRectInImage(lockedImage, rect, QPoint(dx, dy)); + + release(&lockedImage); + return true; +} + +EGLSurface QMeeGoLivePixmapData::getSurfaceForBackingPixmap() +{ + // This code is a crative remix of the stuff that can be found in the + // Qt's TFP implementation in /src/opengl/qgl_x11egl.cpp ::bindiTextureFromNativePixmap + QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(backingX11Pixmap->data_ptr().data()); + Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class); + bool hasAlpha = pixmapData->hasAlphaChannel(); + + if (pixmapData->gl_surface && + hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) + return pixmapData->gl_surface; + + // Check to see if the surface is still valid + if (pixmapData->gl_surface && + hasAlpha != ((pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha) > 0)) { + // Surface is invalid! + destroySurfaceForPixmapData(pixmapData); + } + + if (pixmapData->gl_surface == 0) { + EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap, + QEgl::OpenGL, + hasAlpha ? QEgl::Translucent : QEgl::NoOptions); + + pixmapData->gl_surface = (void*)QEgl::createSurface(backingX11Pixmap, config); + + if (hasAlpha) + pixmapData->flags |= QX11PixmapData::GlSurfaceCreatedWithAlpha; + else + pixmapData->flags &= ~QX11PixmapData::GlSurfaceCreatedWithAlpha; + + if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE) + return NULL; + } + + return pixmapData->gl_surface; +} + +void QMeeGoLivePixmapData::destroySurfaceForPixmapData(QPixmapData* pmd) +{ + Q_ASSERT(pmd->classId() == QPixmapData::X11Class); + QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd); + if (pixmapData->gl_surface) { + eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface); + pixmapData->gl_surface = 0; + } +} diff --git a/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.h b/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.h new file mode 100644 index 0000000..2c6854e --- /dev/null +++ b/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MLIVEPIXMAPDATA_H +#define MLIVEPIXMAPDATA_H + +#include <private/qpixmapdata_gl_p.h> +#include "qmeegoextensions.h" + +class QMeeGoLivePixmapData : public QGLPixmapData +{ +public: + QMeeGoLivePixmapData(int w, int h, QImage::Format format); + QMeeGoLivePixmapData(Qt::HANDLE h); + ~QMeeGoLivePixmapData(); + + QPixmapData *createCompatiblePixmapData() const; + bool scroll(int dx, int dy, const QRect &rect); + + void initializeThroughEGLImage(); + + QImage* lock(EGLSyncKHR fenceSync); + bool release(QImage *img); + Qt::HANDLE handle(); + + EGLSurface getSurfaceForBackingPixmap(); + void destroySurfaceForPixmapData(QPixmapData* pmd); + + QPixmap *backingX11Pixmap; + QImage lockedImage; +}; + +#endif diff --git a/src/plugins/graphicssystems/meego/qmeegopixmapdata.cpp b/src/plugins/graphicssystems/meego/qmeegopixmapdata.cpp new file mode 100644 index 0000000..eb63692 --- /dev/null +++ b/src/plugins/graphicssystems/meego/qmeegopixmapdata.cpp @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmeegopixmapdata.h" +#include "qmeegoextensions.h" +#include "qmeegorasterpixmapdata.h" +#include <private/qimage_p.h> +#include <private/qwindowsurface_gl_p.h> +#include <private/qeglcontext_p.h> +#include <private/qapplication_p.h> +#include <private/qgraphicssystem_runtime_p.h> + +// from dithering.cpp +extern unsigned short* convertRGB32_to_RGB565(const unsigned char *in, int width, int height, int stride); +extern unsigned short* convertARGB32_to_RGBA4444(const unsigned char *in, int width, int height, int stride); +extern unsigned char* convertBGRA32_to_RGBA32(const unsigned char *in, int width, int height, int stride); + +static EGLint preserved_image_attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; + +QHash <void*, QMeeGoImageInfo*> QMeeGoPixmapData::sharedImagesMap; + +/* Public */ + +QMeeGoPixmapData::QMeeGoPixmapData() : QGLPixmapData(QPixmapData::PixmapType) +{ +} + +void QMeeGoPixmapData::fromTexture(GLuint textureId, int w, int h, bool alpha) +{ + resize(w, h); + texture()->id = textureId; + m_hasAlpha = alpha; + softImage = QImage(); +} + +QImage QMeeGoPixmapData::toImage() const +{ + return softImage; +} + +void QMeeGoPixmapData::fromImage(const QImage &image, + Qt::ImageConversionFlags flags) +{ + void *rawResource = static_cast <void *> (((QImage &) image).data_ptr()->data); + + if (sharedImagesMap.contains(rawResource)) { + QMeeGoImageInfo *info = sharedImagesMap.value(rawResource); + fromEGLSharedImage(info->handle, image); + } else { + // This should *never* happen since the graphics system should never + // create a QMeeGoPixmapData for an origin that doesn't contain a raster + // image we know about. But... + qWarning("QMeeGoPixmapData::fromImage called on non-know resource. Falling back..."); + QGLPixmapData::fromImage(image, flags); + } +} + +void QMeeGoPixmapData::fromEGLSharedImage(Qt::HANDLE handle, const QImage &si) +{ + if (si.isNull()) + qFatal("Trying to build pixmap with an empty/null softimage!"); + + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + + QMeeGoExtensions::ensureInitialized(); + + bool textureIsBound = false; + GLuint newTextureId; + GLint newWidth, newHeight; + + glGenTextures(1, &newTextureId); + glBindTexture(GL_TEXTURE_2D, newTextureId); + + EGLImageKHR image = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_SHARED_IMAGE_NOK, + (EGLClientBuffer)handle, preserved_image_attribs); + + if (image != EGL_NO_IMAGE_KHR) { + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); + GLint err = glGetError(); + if (err == GL_NO_ERROR) + textureIsBound = true; + + QMeeGoExtensions::eglQueryImageNOK(QEgl::display(), image, EGL_WIDTH, &newWidth); + QMeeGoExtensions::eglQueryImageNOK(QEgl::display(), image, EGL_HEIGHT, &newHeight); + + QEgl::eglDestroyImageKHR(QEgl::display(), image); + } + + if (textureIsBound) { + fromTexture(newTextureId, newWidth, newHeight, + (si.hasAlphaChannel() && const_cast<QImage &>(si).data_ptr()->checkForAlphaPixels())); + texture()->options &= ~QGLContext::InvertedYBindOption; + softImage = si; + QMeeGoPixmapData::registerSharedImage(handle, softImage); + } else { + qWarning("Failed to create a texture from a shared image!"); + glDeleteTextures(1, &newTextureId); + } +} + +Qt::HANDLE QMeeGoPixmapData::imageToEGLSharedImage(const QImage &image) +{ + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + + QMeeGoExtensions::ensureInitialized(); + + GLuint textureId; + + glGenTextures(1, &textureId); + glBindTexture(GL_TEXTURE_2D, textureId); + if (image.hasAlphaChannel() && const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels()) { + void *converted = convertBGRA32_to_RGBA32(image.bits(), image.width(), image.height(), image.bytesPerLine()); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, converted); + free(converted); + } else { + void *converted = convertRGB32_to_RGB565(image.bits(), image.width(), image.height(), image.bytesPerLine()); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, converted); + free(converted); + } + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glBindTexture(GL_TEXTURE_2D, textureId); + EGLImageKHR eglimage = QEgl::eglCreateImageKHR(QEgl::display(), QEglContext::currentContext(QEgl::OpenGL)->context(), + EGL_GL_TEXTURE_2D_KHR, + (EGLClientBuffer) textureId, + preserved_image_attribs); + glDeleteTextures(1, &textureId); + if (eglimage) { + EGLNativeSharedImageTypeNOK handle = QMeeGoExtensions::eglCreateSharedImageNOK(QEgl::display(), eglimage, NULL); + QEgl::eglDestroyImageKHR(QEgl::display(), eglimage); + return (Qt::HANDLE) handle; + } else { + qWarning("Failed to create shared image from pixmap/texture!"); + return 0; + } +} + +void QMeeGoPixmapData::updateFromSoftImage() +{ + // FIXME That's broken with recent 16bit textures changes. + m_dirty = true; + m_source = softImage; + ensureCreated(); + + if (softImage.width() != w || softImage.height() != h) + qWarning("Ooops, looks like softImage changed dimensions since last updated! Corruption ahead?!"); +} + +bool QMeeGoPixmapData::destroyEGLSharedImage(Qt::HANDLE h) +{ + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + QMeeGoExtensions::ensureInitialized(); + + QMutableHashIterator <void*, QMeeGoImageInfo*> i(sharedImagesMap); + while (i.hasNext()) { + i.next(); + if (i.value()->handle == h) + i.remove(); + } + + return QMeeGoExtensions::eglDestroySharedImageNOK(QEgl::display(), (EGLNativeSharedImageTypeNOK) h); +} + +void QMeeGoPixmapData::registerSharedImage(Qt::HANDLE handle, const QImage &si) +{ + void *raw = static_cast <void *> (((QImage) si).data_ptr()->data); + QMeeGoImageInfo *info; + + if (! sharedImagesMap.contains(raw)) { + info = new QMeeGoImageInfo; + info->handle = handle; + info->rawFormat = si.format(); + sharedImagesMap.insert(raw, info); + } else { + info = sharedImagesMap.value(raw); + if (info->handle != handle || info->rawFormat != si.format()) + qWarning("Inconsistency detected: overwriting entry in sharedImagesMap but handle/format different"); + } +} + +QPixmapData *QMeeGoPixmapData::createCompatiblePixmapData() const +{ + return new QMeeGoRasterPixmapData(pixelType()); +} diff --git a/src/plugins/graphicssystems/meego/qmeegopixmapdata.h b/src/plugins/graphicssystems/meego/qmeegopixmapdata.h new file mode 100644 index 0000000..c66e719 --- /dev/null +++ b/src/plugins/graphicssystems/meego/qmeegopixmapdata.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MPIXMAPDATA_H +#define MPIXMAPDATA_H + +#include <private/qpixmapdata_gl_p.h> + +struct QMeeGoImageInfo +{ + Qt::HANDLE handle; + QImage::Format rawFormat; +}; + +class QMeeGoPixmapData : public QGLPixmapData +{ +public: + QMeeGoPixmapData(); + void fromTexture(GLuint textureId, int w, int h, bool alpha); + QPixmapData *createCompatiblePixmapData() const; + + virtual void fromEGLSharedImage(Qt::HANDLE handle, const QImage &softImage); + virtual void fromImage (const QImage &image, Qt::ImageConversionFlags flags); + virtual QImage toImage() const; + virtual void updateFromSoftImage(); + + QImage softImage; + + static QHash <void*, QMeeGoImageInfo*> sharedImagesMap; + + static Qt::HANDLE imageToEGLSharedImage(const QImage &image); + static bool destroyEGLSharedImage(Qt::HANDLE h); + static void registerSharedImage(Qt::HANDLE handle, const QImage &si); +}; + +#endif diff --git a/src/plugins/graphicssystems/meego/qmeegorasterpixmapdata.cpp b/src/plugins/graphicssystems/meego/qmeegorasterpixmapdata.cpp new file mode 100644 index 0000000..b6a3727 --- /dev/null +++ b/src/plugins/graphicssystems/meego/qmeegorasterpixmapdata.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmeegorasterpixmapdata.h" + +/* Public */ + +QMeeGoRasterPixmapData::QMeeGoRasterPixmapData() : QRasterPixmapData(QPixmapData::PixmapType) +{ +} + +QMeeGoRasterPixmapData::QMeeGoRasterPixmapData(QPixmapData::PixelType t) : QRasterPixmapData(t) +{ +} + +void QMeeGoRasterPixmapData::copy(const QPixmapData *data, const QRect &rect) +{ + if (data->classId() == QPixmapData::OpenGLClass) + fromImage(data->toImage(rect).copy(), Qt::NoOpaqueDetection); + else + QRasterPixmapData::copy(data, rect); +} diff --git a/src/plugins/graphicssystems/meego/qmeegorasterpixmapdata.h b/src/plugins/graphicssystems/meego/qmeegorasterpixmapdata.h new file mode 100644 index 0000000..636b0e6 --- /dev/null +++ b/src/plugins/graphicssystems/meego/qmeegorasterpixmapdata.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MRASTERPIXMAPDATA_H +#define MRASTERPIXMAPDATA_H + +#include <private/qpixmap_raster_p.h> + +class QMeeGoRasterPixmapData : public QRasterPixmapData +{ +public: + QMeeGoRasterPixmapData(); + QMeeGoRasterPixmapData(QPixmapData::PixelType t); + void copy(const QPixmapData *data, const QRect &rect); +}; + +#endif diff --git a/src/plugins/graphicssystems/opengl/main.cpp b/src/plugins/graphicssystems/opengl/main.cpp index 19631b6..4c740ca 100644 --- a/src/plugins/graphicssystems/opengl/main.cpp +++ b/src/plugins/graphicssystems/opengl/main.cpp @@ -56,9 +56,12 @@ QStringList QGLGraphicsSystemPlugin::keys() const { QStringList list; list << QLatin1String("OpenGL") << QLatin1String("OpenGL1"); -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +#if !defined(QT_OPENGL_ES_1) list << QLatin1String("OpenGL2"); #endif +#if defined(Q_WS_X11) && !defined(QT_NO_EGL) + list << QLatin1String("X11GL"); +#endif return list; } @@ -66,18 +69,23 @@ QGraphicsSystem* QGLGraphicsSystemPlugin::create(const QString& system) { if (system.toLower() == QLatin1String("opengl1")) { QGL::setPreferredPaintEngine(QPaintEngine::OpenGL); - return new QGLGraphicsSystem; + return new QGLGraphicsSystem(false); } -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +#if !defined(QT_OPENGL_ES_1) if (system.toLower() == QLatin1String("opengl2")) { QGL::setPreferredPaintEngine(QPaintEngine::OpenGL2); - return new QGLGraphicsSystem; + return new QGLGraphicsSystem(false); } #endif +#if defined(Q_WS_X11) && !defined(QT_NO_EGL) + if (system.toLower() == QLatin1String("x11gl")) + return new QGLGraphicsSystem(true); +#endif + if (system.toLower() == QLatin1String("opengl")) - return new QGLGraphicsSystem; + return new QGLGraphicsSystem(false); return 0; } diff --git a/src/plugins/graphicssystems/opengl/opengl.pro b/src/plugins/graphicssystems/opengl/opengl.pro index 7d6fe3f..47e15c5 100644 --- a/src/plugins/graphicssystems/opengl/opengl.pro +++ b/src/plugins/graphicssystems/opengl/opengl.pro @@ -9,3 +9,5 @@ SOURCES = main.cpp target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems INSTALLS += target + +symbian: TARGET.UID3 = 0x2002131B diff --git a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp index 2c7c0b7..9674233 100644 --- a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp +++ b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp @@ -42,6 +42,9 @@ #include "qgraphicssystem_vg_p.h" #include <QtOpenVG/private/qpixmapdata_vg_p.h> #include <QtOpenVG/private/qwindowsurface_vg_p.h> +#if defined(Q_OS_SYMBIAN) && !defined(Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE) +#include <QtGui/private/qwidget_p.h> +#endif QT_BEGIN_NAMESPACE @@ -64,6 +67,11 @@ QPixmapData *QVGGraphicsSystem::createPixmapData(QPixmapData::PixelType type) co QWindowSurface *QVGGraphicsSystem::createWindowSurface(QWidget *widget) const { +#if defined(Q_OS_SYMBIAN) && !defined(Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE) + QWidgetPrivate *d = qt_widget_private(widget); + if (!d->isOpaque && widget->testAttribute(Qt::WA_TranslucentBackground)) + return d->createDefaultWindowSurface_sys(); +#endif return new QVGWindowSurface(widget); } diff --git a/src/plugins/graphicssystems/trace/qgraphicssystem_trace.cpp b/src/plugins/graphicssystems/trace/qgraphicssystem_trace.cpp index 13044f4..6bf9d6b 100644 --- a/src/plugins/graphicssystems/trace/qgraphicssystem_trace.cpp +++ b/src/plugins/graphicssystems/trace/qgraphicssystem_trace.cpp @@ -82,8 +82,13 @@ QTraceWindowSurface::~QTraceWindowSurface() QFile outputFile(QString(QLatin1String("qtgraphics-%0.trace")).arg(winId)); if (outputFile.open(QIODevice::WriteOnly)) { QDataStream out(&outputFile); - out.writeBytes("qttrace", 7); - out << *buffer << updates; + out.setFloatingPointPrecision(QDataStream::SinglePrecision); + + out.writeBytes("qttraceV2", 9); + + uint version = 1; + + out << version << *buffer << updates; } delete buffer; } diff --git a/src/plugins/graphicssystems/trace/trace.pro b/src/plugins/graphicssystems/trace/trace.pro index d548a6c..07472e2 100644 --- a/src/plugins/graphicssystems/trace/trace.pro +++ b/src/plugins/graphicssystems/trace/trace.pro @@ -4,6 +4,7 @@ include(../../qpluginbase.pri) QT += network QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems +symbian:TARGET.UID3 = 0x2002130E SOURCES = main.cpp qgraphicssystem_trace.cpp diff --git a/src/plugins/imageformats/gif/gif.pro b/src/plugins/imageformats/gif/gif.pro index 8a5c51a..439b431 100644 --- a/src/plugins/imageformats/gif/gif.pro +++ b/src/plugins/imageformats/gif/gif.pro @@ -1,9 +1,8 @@ TARGET = qgif include(../../qpluginbase.pri) -HEADERS += qgifhandler.h -SOURCES += main.cpp \ - qgifhandler.cpp +include(../../../gui/image/qgifhandler.pri) +SOURCES += $$PWD/main.cpp QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats diff --git a/src/plugins/imageformats/gif/main.cpp b/src/plugins/imageformats/gif/main.cpp index 3bb0bf4..99a9528 100644 --- a/src/plugins/imageformats/gif/main.cpp +++ b/src/plugins/imageformats/gif/main.cpp @@ -47,7 +47,7 @@ #ifdef QT_NO_IMAGEFORMAT_GIF #undef QT_NO_IMAGEFORMAT_GIF #endif -#include "qgifhandler.h" +#include <qgifhandler_p.h> QT_BEGIN_NAMESPACE diff --git a/src/plugins/imageformats/gif/qgifhandler.cpp b/src/plugins/imageformats/gif/qgifhandler.cpp deleted file mode 100644 index cba3ff6..0000000 --- a/src/plugins/imageformats/gif/qgifhandler.cpp +++ /dev/null @@ -1,1186 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 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$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, 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. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -** WARNING: -** A separate license from Unisys may be required to use the gif -** reader. See http://www.unisys.com/about__unisys/lzw/ -** for information from Unisys -** -****************************************************************************/ - -#include "qgifhandler.h" - -#include <qimage.h> -#include <qiodevice.h> -#include <qvariant.h> - -QT_BEGIN_NAMESPACE - -#define Q_TRANSPARENT 0x00ffffff - -// avoid going through QImage::scanLine() which calls detach -#define FAST_SCAN_LINE(bits, bpl, y) (bits + (y) * bpl) - - -/* - Incremental image decoder for GIF image format. - - This subclass of QImageFormat decodes GIF format images, - including animated GIFs. Internally in -*/ - -class QGIFFormat { -public: - QGIFFormat(); - ~QGIFFormat(); - - int decode(QImage *image, const uchar* buffer, int length, - int *nextFrameDelay, int *loopCount); - static void scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount); - - bool newFrame; - bool partialNewFrame; - -private: - void fillRect(QImage *image, int x, int y, int w, int h, QRgb col); - inline QRgb color(uchar index) const; - - // GIF specific stuff - QRgb* globalcmap; - QRgb* localcmap; - QImage backingstore; - unsigned char hold[16]; - bool gif89; - int count; - int ccount; - int expectcount; - enum State { - Header, - LogicalScreenDescriptor, - GlobalColorMap, - LocalColorMap, - Introducer, - ImageDescriptor, - TableImageLZWSize, - ImageDataBlockSize, - ImageDataBlock, - ExtensionLabel, - GraphicControlExtension, - ApplicationExtension, - NetscapeExtensionBlockSize, - NetscapeExtensionBlock, - SkipBlockSize, - SkipBlock, - Done, - Error - } state; - int gncols; - int lncols; - int ncols; - int lzwsize; - bool lcmap; - int swidth, sheight; - int width, height; - int left, top, right, bottom; - enum Disposal { NoDisposal, DoNotChange, RestoreBackground, RestoreImage }; - Disposal disposal; - bool disposed; - int trans_index; - bool gcmap; - int bgcol; - int interlace; - int accum; - int bitcount; - - enum { max_lzw_bits=12 }; // (poor-compiler's static const int) - - int code_size, clear_code, end_code, max_code_size, max_code; - int firstcode, oldcode, incode; - short table[2][1<< max_lzw_bits]; - short stack[(1<<(max_lzw_bits))*2]; - short *sp; - bool needfirst; - int x, y; - int frame; - bool out_of_bounds; - bool digress; - void nextY(unsigned char *bits, int bpl); - void disposePrevious(QImage *image); -}; - -/*! - Constructs a QGIFFormat. -*/ -QGIFFormat::QGIFFormat() -{ - globalcmap = 0; - localcmap = 0; - lncols = 0; - gncols = 0; - disposal = NoDisposal; - out_of_bounds = false; - disposed = true; - frame = -1; - state = Header; - count = 0; - lcmap = false; - newFrame = false; - partialNewFrame = false; -} - -/*! - Destroys a QGIFFormat. -*/ -QGIFFormat::~QGIFFormat() -{ - if (globalcmap) delete[] globalcmap; - if (localcmap) delete[] localcmap; -} - -void QGIFFormat::disposePrevious(QImage *image) -{ - if (out_of_bounds) { - // flush anything that survived - // ### Changed: QRect(0, 0, swidth, sheight) - } - - // Handle disposal of previous image before processing next one - - if (disposed) return; - - int l = qMin(swidth-1,left); - int r = qMin(swidth-1,right); - int t = qMin(sheight-1,top); - int b = qMin(sheight-1,bottom); - - switch (disposal) { - case NoDisposal: - break; - case DoNotChange: - break; - case RestoreBackground: - if (trans_index>=0) { - // Easy: we use the transparent color - fillRect(image, l, t, r-l+1, b-t+1, Q_TRANSPARENT); - } else if (bgcol>=0) { - // Easy: we use the bgcol given - fillRect(image, l, t, r-l+1, b-t+1, color(bgcol)); - } else { - // Impossible: We don't know of a bgcol - use pixel 0 - QRgb *bits = (QRgb*)image->bits(); - fillRect(image, l, t, r-l+1, b-t+1, bits[0]); - } - // ### Changed: QRect(l, t, r-l+1, b-t+1) - break; - case RestoreImage: { - if (frame >= 0) { - for (int ln=t; ln<=b; ln++) { - memcpy(image->scanLine(ln)+l, - backingstore.scanLine(ln-t), - (r-l+1)*sizeof(QRgb)); - } - // ### Changed: QRect(l, t, r-l+1, b-t+1) - } - } - } - disposal = NoDisposal; // Until an extension says otherwise. - - disposed = true; -} - -/*! - This function decodes some data into image changes. - - Returns the number of bytes consumed. -*/ -int QGIFFormat::decode(QImage *image, const uchar *buffer, int length, - int *nextFrameDelay, int *loopCount) -{ - // We are required to state that - // "The Graphics Interchange Format(c) is the Copyright property of - // CompuServe Incorporated. GIF(sm) is a Service Mark property of - // CompuServe Incorporated." - - image->detach(); - int bpl = image->bytesPerLine(); - unsigned char *bits = image->bits(); - -#define LM(l, m) (((m)<<8)|l) - digress = false; - const int initial = length; - while (!digress && length) { - length--; - unsigned char ch=*buffer++; - switch (state) { - case Header: - hold[count++]=ch; - if (count==6) { - // Header - gif89=(hold[3]!='8' || hold[4]!='7'); - state=LogicalScreenDescriptor; - count=0; - } - break; - case LogicalScreenDescriptor: - hold[count++]=ch; - if (count==7) { - // Logical Screen Descriptor - swidth=LM(hold[0], hold[1]); - sheight=LM(hold[2], hold[3]); - gcmap=!!(hold[4]&0x80); - //UNUSED: bpchan=(((hold[4]&0x70)>>3)+1); - //UNUSED: gcmsortflag=!!(hold[4]&0x08); - gncols=2<<(hold[4]&0x7); - bgcol=(gcmap) ? hold[5] : -1; - //aspect=hold[6] ? double(hold[6]+15)/64.0 : 1.0; - - trans_index = -1; - count=0; - ncols=gncols; - if (gcmap) { - ccount=0; - state=GlobalColorMap; - globalcmap = new QRgb[gncols+1]; // +1 for trans_index - globalcmap[gncols] = Q_TRANSPARENT; - } else { - state=Introducer; - } - } - break; - case GlobalColorMap: case LocalColorMap: - hold[count++]=ch; - if (count==3) { - QRgb rgb = qRgb(hold[0], hold[1], hold[2]); - if (state == LocalColorMap) { - if (ccount < lncols) - localcmap[ccount] = rgb; - } else { - globalcmap[ccount] = rgb; - } - if (++ccount >= ncols) { - if (state == LocalColorMap) - state=TableImageLZWSize; - else - state=Introducer; - } - count=0; - } - break; - case Introducer: - hold[count++]=ch; - switch (ch) { - case ',': - state=ImageDescriptor; - break; - case '!': - state=ExtensionLabel; - break; - case ';': - // ### Changed: QRect(0, 0, swidth, sheight) - state=Done; - break; - default: - digress=true; - // Unexpected Introducer - ignore block - state=Error; - } - break; - case ImageDescriptor: - hold[count++]=ch; - if (count==10) { - int newleft=LM(hold[1], hold[2]); - int newtop=LM(hold[3], hold[4]); - int newwidth=LM(hold[5], hold[6]); - int newheight=LM(hold[7], hold[8]); - - // disbelieve ridiculous logical screen sizes, - // unless the image frames are also large. - if (swidth/10 > qMax(newwidth,200)) - swidth = -1; - if (sheight/10 > qMax(newheight,200)) - sheight = -1; - - if (swidth <= 0) - swidth = newleft + newwidth; - if (sheight <= 0) - sheight = newtop + newheight; - - QImage::Format format = trans_index >= 0 ? QImage::Format_ARGB32 : QImage::Format_RGB32; - if (image->isNull()) { - (*image) = QImage(swidth, sheight, format); - bpl = image->bytesPerLine(); - bits = image->bits(); - memset(bits, 0, image->byteCount()); - } - - disposePrevious(image); - disposed = false; - - left = newleft; - top = newtop; - width = newwidth; - height = newheight; - - right=qMax(0, qMin(left+width, swidth)-1); - bottom=qMax(0, qMin(top+height, sheight)-1); - lcmap=!!(hold[9]&0x80); - interlace=!!(hold[9]&0x40); - //bool lcmsortflag=!!(hold[9]&0x20); - lncols=lcmap ? (2<<(hold[9]&0x7)) : 0; - if (lncols) { - if (localcmap) - delete [] localcmap; - localcmap = new QRgb[lncols+1]; - localcmap[lncols] = Q_TRANSPARENT; - ncols = lncols; - } else { - ncols = gncols; - } - frame++; - if (frame == 0) { - if (left || top || width<swidth || height<sheight) { - // Not full-size image - erase with bg or transparent - if (trans_index >= 0) { - fillRect(image, 0, 0, swidth, sheight, color(trans_index)); - // ### Changed: QRect(0, 0, swidth, sheight) - } else if (bgcol>=0) { - fillRect(image, 0, 0, swidth, sheight, color(bgcol)); - // ### Changed: QRect(0, 0, swidth, sheight) - } - } - } - - if (disposal == RestoreImage) { - int l = qMin(swidth-1,left); - int r = qMin(swidth-1,right); - int t = qMin(sheight-1,top); - int b = qMin(sheight-1,bottom); - int w = r-l+1; - int h = b-t+1; - - if (backingstore.width() < w - || backingstore.height() < h) { - // We just use the backing store as a byte array - backingstore = QImage(qMax(backingstore.width(), w), - qMax(backingstore.height(), h), - QImage::Format_RGB32); - memset(bits, 0, image->byteCount()); - } - const int dest_bpl = backingstore.bytesPerLine(); - unsigned char *dest_data = backingstore.bits(); - for (int ln=0; ln<h; ln++) { - memcpy(FAST_SCAN_LINE(dest_data, dest_bpl, ln), - FAST_SCAN_LINE(bits, bpl, t+ln) + l, w*sizeof(QRgb)); - } - } - - count=0; - if (lcmap) { - ccount=0; - state=LocalColorMap; - } else { - state=TableImageLZWSize; - } - x = left; - y = top; - accum = 0; - bitcount = 0; - sp = stack; - firstcode = oldcode = 0; - needfirst = true; - out_of_bounds = left>=swidth || y>=sheight; - } - break; - case TableImageLZWSize: { - lzwsize=ch; - if (lzwsize > max_lzw_bits) { - state=Error; - } else { - code_size=lzwsize+1; - clear_code=1<<lzwsize; - end_code=clear_code+1; - max_code_size=2*clear_code; - max_code=clear_code+2; - int i; - for (i=0; i<clear_code; i++) { - table[0][i]=0; - table[1][i]=i; - } - state=ImageDataBlockSize; - } - count=0; - break; - } case ImageDataBlockSize: - expectcount=ch; - if (expectcount) { - state=ImageDataBlock; - } else { - state=Introducer; - digress = true; - newFrame = true; - } - break; - case ImageDataBlock: - count++; - accum|=(ch<<bitcount); - bitcount+=8; - while (bitcount>=code_size && state==ImageDataBlock) { - int code=accum&((1<<code_size)-1); - bitcount-=code_size; - accum>>=code_size; - - if (code==clear_code) { - if (!needfirst) { - code_size=lzwsize+1; - max_code_size=2*clear_code; - max_code=clear_code+2; - } - needfirst=true; - } else if (code==end_code) { - bitcount = -32768; - // Left the block end arrive - } else { - if (needfirst) { - firstcode=oldcode=code; - if (!out_of_bounds && image->height() > y && firstcode!=trans_index) - ((QRgb*)FAST_SCAN_LINE(bits, bpl, y))[x] = color(firstcode); - x++; - if (x>=swidth) out_of_bounds = true; - needfirst=false; - if (x>=left+width) { - x=left; - out_of_bounds = left>=swidth || y>=sheight; - nextY(bits, bpl); - } - } else { - incode=code; - if (code>=max_code) { - *sp++=firstcode; - code=oldcode; - } - while (code>=clear_code+2) { - *sp++=table[1][code]; - if (code==table[0][code]) { - state=Error; - break; - } - if (sp-stack>=(1<<(max_lzw_bits))*2) { - state=Error; - break; - } - code=table[0][code]; - } - *sp++=firstcode=table[1][code]; - code=max_code; - if (code<(1<<max_lzw_bits)) { - table[0][code]=oldcode; - table[1][code]=firstcode; - max_code++; - if ((max_code>=max_code_size) - && (max_code_size<(1<<max_lzw_bits))) - { - max_code_size*=2; - code_size++; - } - } - oldcode=incode; - const int h = image->height(); - const QRgb *map = lcmap ? localcmap : globalcmap; - QRgb *line = 0; - if (!out_of_bounds && h > y) - line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y); - while (sp>stack) { - const uchar index = *(--sp); - if (!out_of_bounds && h > y && index!=trans_index) { - if (index > ncols) - line[x] = Q_TRANSPARENT; - else - line[x] = map ? map[index] : 0; - } - x++; - if (x>=swidth) out_of_bounds = true; - if (x>=left+width) { - x=left; - out_of_bounds = left>=swidth || y>=sheight; - nextY(bits, bpl); - if (!out_of_bounds && h > y) - line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y); - } - } - } - } - } - partialNewFrame = true; - if (count==expectcount) { - count=0; - state=ImageDataBlockSize; - } - break; - case ExtensionLabel: - switch (ch) { - case 0xf9: - state=GraphicControlExtension; - break; - case 0xff: - state=ApplicationExtension; - break; -#if 0 - case 0xfe: - state=CommentExtension; - break; - case 0x01: - break; -#endif - default: - state=SkipBlockSize; - } - count=0; - break; - case ApplicationExtension: - if (count<11) hold[count]=ch; - count++; - if (count==hold[0]+1) { - if (qstrncmp((char*)(hold+1), "NETSCAPE", 8)==0) { - // Looping extension - state=NetscapeExtensionBlockSize; - } else { - state=SkipBlockSize; - } - count=0; - } - break; - case NetscapeExtensionBlockSize: - expectcount=ch; - count=0; - if (expectcount) state=NetscapeExtensionBlock; - else state=Introducer; - break; - case NetscapeExtensionBlock: - if (count<3) hold[count]=ch; - count++; - if (count==expectcount) { - *loopCount = hold[1]+hold[2]*256; - state=SkipBlockSize; // Ignore further blocks - } - break; - case GraphicControlExtension: - if (count<5) hold[count]=ch; - count++; - if (count==hold[0]+1) { - disposePrevious(image); - disposal=Disposal((hold[1]>>2)&0x7); - //UNUSED: waitforuser=!!((hold[1]>>1)&0x1); - int delay=count>3 ? LM(hold[2], hold[3]) : 1; - // IE and mozilla use a minimum delay of 10. With the minimum delay of 10 - // we are compatible to them and avoid huge loads on the app and xserver. - *nextFrameDelay = (delay < 2 ? 10 : delay) * 10; - - bool havetrans=hold[1]&0x1; - trans_index = havetrans ? hold[4] : -1; - - count=0; - state=SkipBlockSize; - } - break; - case SkipBlockSize: - expectcount=ch; - count=0; - if (expectcount) state=SkipBlock; - else state=Introducer; - break; - case SkipBlock: - count++; - if (count==expectcount) state=SkipBlockSize; - break; - case Done: - digress=true; - /* Netscape ignores the junk, so we do too. - length++; // Unget - state=Error; // More calls to this is an error - */ - break; - case Error: - return -1; // Called again after done. - } - } - return initial-length; -} - -/*! - Scans through the data stream defined by \a device and returns the image - sizes found in the stream in the \a imageSizes vector. -*/ -void QGIFFormat::scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount) -{ - if (!device) - return; - - qint64 oldPos = device->pos(); - if (!device->seek(0)) - return; - - int colorCount = 0; - int localColorCount = 0; - int globalColorCount = 0; - int colorReadCount = 0; - bool localColormap = false; - bool globalColormap = false; - int count = 0; - int blockSize = 0; - int imageWidth = 0; - int imageHeight = 0; - bool done = false; - uchar hold[16]; - State state = Header; - - const int readBufferSize = 40960; // 40k read buffer - QByteArray readBuffer(device->read(readBufferSize)); - - if (readBuffer.isEmpty()) { - device->seek(oldPos); - return; - } - - // This is a specialized version of the state machine from decode(), - // which doesn't do any image decoding or mallocing, and has an - // optimized way of skipping SkipBlocks, ImageDataBlocks and - // Global/LocalColorMaps. - - while (!readBuffer.isEmpty()) { - int length = readBuffer.size(); - const uchar *buffer = (const uchar *) readBuffer.constData(); - while (!done && length) { - length--; - uchar ch = *buffer++; - switch (state) { - case Header: - hold[count++] = ch; - if (count == 6) { - state = LogicalScreenDescriptor; - count = 0; - } - break; - case LogicalScreenDescriptor: - hold[count++] = ch; - if (count == 7) { - imageWidth = LM(hold[0], hold[1]); - imageHeight = LM(hold[2], hold[3]); - globalColormap = !!(hold[4] & 0x80); - globalColorCount = 2 << (hold[4] & 0x7); - count = 0; - colorCount = globalColorCount; - if (globalColormap) { - int colorTableSize = 3 * globalColorCount; - if (length >= colorTableSize) { - // skip the global color table in one go - length -= colorTableSize; - buffer += colorTableSize; - state = Introducer; - } else { - colorReadCount = 0; - state = GlobalColorMap; - } - } else { - state=Introducer; - } - } - break; - case GlobalColorMap: - case LocalColorMap: - hold[count++] = ch; - if (count == 3) { - if (++colorReadCount >= colorCount) { - if (state == LocalColorMap) - state = TableImageLZWSize; - else - state = Introducer; - } - count = 0; - } - break; - case Introducer: - hold[count++] = ch; - switch (ch) { - case 0x2c: - state = ImageDescriptor; - break; - case 0x21: - state = ExtensionLabel; - break; - case 0x3b: - state = Done; - break; - default: - done = true; - state = Error; - } - break; - case ImageDescriptor: - hold[count++] = ch; - if (count == 10) { - int newLeft = LM(hold[1], hold[2]); - int newTop = LM(hold[3], hold[4]); - int newWidth = LM(hold[5], hold[6]); - int newHeight = LM(hold[7], hold[8]); - - if (imageWidth/10 > qMax(newWidth,200)) - imageWidth = -1; - if (imageHeight/10 > qMax(newHeight,200)) - imageHeight = -1; - - if (imageWidth <= 0) - imageWidth = newLeft + newWidth; - if (imageHeight <= 0) - imageHeight = newTop + newHeight; - - *imageSizes << QSize(imageWidth, imageHeight); - - localColormap = !!(hold[9] & 0x80); - localColorCount = localColormap ? (2 << (hold[9] & 0x7)) : 0; - if (localColorCount) - colorCount = localColorCount; - else - colorCount = globalColorCount; - - count = 0; - if (localColormap) { - int colorTableSize = 3 * localColorCount; - if (length >= colorTableSize) { - // skip the local color table in one go - length -= colorTableSize; - buffer += colorTableSize; - state = TableImageLZWSize; - } else { - colorReadCount = 0; - state = LocalColorMap; - } - } else { - state = TableImageLZWSize; - } - } - break; - case TableImageLZWSize: - if (ch > max_lzw_bits) - state = Error; - else - state = ImageDataBlockSize; - count = 0; - break; - case ImageDataBlockSize: - blockSize = ch; - if (blockSize) { - if (length >= blockSize) { - // we can skip the block in one go - length -= blockSize; - buffer += blockSize; - count = 0; - } else { - state = ImageDataBlock; - } - } else { - state = Introducer; - } - break; - case ImageDataBlock: - ++count; - if (count == blockSize) { - count = 0; - state = ImageDataBlockSize; - } - break; - case ExtensionLabel: - switch (ch) { - case 0xf9: - state = GraphicControlExtension; - break; - case 0xff: - state = ApplicationExtension; - break; - default: - state = SkipBlockSize; - } - count = 0; - break; - case ApplicationExtension: - if (count < 11) - hold[count] = ch; - ++count; - if (count == hold[0] + 1) { - if (qstrncmp((char*)(hold+1), "NETSCAPE", 8) == 0) - state=NetscapeExtensionBlockSize; - else - state=SkipBlockSize; - count = 0; - } - break; - case GraphicControlExtension: - if (count < 5) - hold[count] = ch; - ++count; - if (count == hold[0] + 1) { - count = 0; - state = SkipBlockSize; - } - break; - case NetscapeExtensionBlockSize: - blockSize = ch; - count = 0; - if (blockSize) - state = NetscapeExtensionBlock; - else - state = Introducer; - break; - case NetscapeExtensionBlock: - if (count < 3) - hold[count] = ch; - count++; - if (count == blockSize) { - *loopCount = LM(hold[1], hold[2]); - state = SkipBlockSize; - } - break; - case SkipBlockSize: - blockSize = ch; - count = 0; - if (blockSize) { - if (length >= blockSize) { - // we can skip the block in one go - length -= blockSize; - buffer += blockSize; - } else { - state = SkipBlock; - } - } else { - state = Introducer; - } - break; - case SkipBlock: - ++count; - if (count == blockSize) - state = SkipBlockSize; - break; - case Done: - done = true; - break; - case Error: - device->seek(oldPos); - return; - } - } - readBuffer = device->read(readBufferSize); - } - device->seek(oldPos); - return; -} - -void QGIFFormat::fillRect(QImage *image, int col, int row, int w, int h, QRgb color) -{ - if (w>0) { - for (int j=0; j<h; j++) { - QRgb *line = (QRgb*)image->scanLine(j+row); - for (int i=0; i<w; i++) - *(line+col+i) = color; - } - } -} - -void QGIFFormat::nextY(unsigned char *bits, int bpl) -{ - int my; - switch (interlace) { - case 0: // Non-interlaced - // if (!out_of_bounds) { - // ### Changed: QRect(left, y, right - left + 1, 1); - // } - y++; - break; - case 1: { - int i; - my = qMin(7, bottom-y); - // Don't dup with transparency - if (trans_index < 0) { - for (i=1; i<=my; i++) { - memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb), - (right-left+1)*sizeof(QRgb)); - } - } - - // if (!out_of_bounds) { - // ### Changed: QRect(left, y, right - left + 1, my + 1); - // } -// if (!out_of_bounds) -// qDebug("consumer->changed(QRect(%d, %d, %d, %d))", left, y, right-left+1, my+1); - y+=8; - if (y>bottom) { - interlace++; y=top+4; - if (y > bottom) { // for really broken GIFs with bottom < 5 - interlace=2; - y = top + 2; - if (y > bottom) { // for really broken GIF with bottom < 3 - interlace = 0; - y = top + 1; - } - } - } - } break; - case 2: { - int i; - my = qMin(3, bottom-y); - // Don't dup with transparency - if (trans_index < 0) { - for (i=1; i<=my; i++) { - memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb), - (right-left+1)*sizeof(QRgb)); - } - } - - // if (!out_of_bounds) { - // ### Changed: QRect(left, y, right - left + 1, my + 1); - // } - y+=8; - if (y>bottom) { - interlace++; y=top+2; - // handle broken GIF with bottom < 3 - if (y > bottom) { - interlace = 3; - y = top + 1; - } - } - } break; - case 3: { - int i; - my = qMin(1, bottom-y); - // Don't dup with transparency - if (trans_index < 0) { - for (i=1; i<=my; i++) { - memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb), - (right-left+1)*sizeof(QRgb)); - } - } - // if (!out_of_bounds) { - // ### Changed: QRect(left, y, right - left + 1, my + 1); - // } - y+=4; - if (y>bottom) { interlace++; y=top+1; } - } break; - case 4: - // if (!out_of_bounds) { - // ### Changed: QRect(left, y, right - left + 1, 1); - // } - y+=2; - } - - // Consume bogus extra lines - if (y >= sheight) out_of_bounds=true; //y=bottom; -} - -inline QRgb QGIFFormat::color(uchar index) const -{ - if (index == trans_index || index > ncols) - return Q_TRANSPARENT; - - QRgb *map = lcmap ? localcmap : globalcmap; - return map ? map[index] : 0; -} - -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- - -QGifHandler::QGifHandler() -{ - gifFormat = new QGIFFormat; - nextDelay = 100; - loopCnt = 1; - frameNumber = -1; - scanIsCached = false; -} - -QGifHandler::~QGifHandler() -{ - delete gifFormat; -} - -// Does partial decode if necessary, just to see if an image is coming - -bool QGifHandler::imageIsComing() const -{ - const int GifChunkSize = 4096; - - while (!gifFormat->partialNewFrame) { - if (buffer.isEmpty()) { - buffer += device()->read(GifChunkSize); - if (buffer.isEmpty()) - break; - } - - int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(), - &nextDelay, &loopCnt); - if (decoded == -1) - break; - buffer.remove(0, decoded); - } - return gifFormat->partialNewFrame; -} - -bool QGifHandler::canRead() const -{ - if (canRead(device())) { - setFormat("gif"); - return true; - } - - return imageIsComing(); -} - -bool QGifHandler::canRead(QIODevice *device) -{ - if (!device) { - qWarning("QGifHandler::canRead() called with no device"); - return false; - } - - char head[6]; - if (device->peek(head, sizeof(head)) == sizeof(head)) - return qstrncmp(head, "GIF87a", 6) == 0 - || qstrncmp(head, "GIF89a", 6) == 0; - return false; -} - -bool QGifHandler::read(QImage *image) -{ - const int GifChunkSize = 4096; - - while (!gifFormat->newFrame) { - if (buffer.isEmpty()) { - buffer += device()->read(GifChunkSize); - if (buffer.isEmpty()) - break; - } - - int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(), - &nextDelay, &loopCnt); - if (decoded == -1) - break; - buffer.remove(0, decoded); - } - if (gifFormat->newFrame || (gifFormat->partialNewFrame && device()->atEnd())) { - *image = lastImage; - ++frameNumber; - gifFormat->newFrame = false; - gifFormat->partialNewFrame = false; - return true; - } - - return false; -} - -bool QGifHandler::write(const QImage &image) -{ - Q_UNUSED(image); - return false; -} - -bool QGifHandler::supportsOption(ImageOption option) const -{ - return option == Size - || option == Animation; -} - -QVariant QGifHandler::option(ImageOption option) const -{ - if (option == Size) { - if (!scanIsCached) { - QGIFFormat::scan(device(), &imageSizes, &loopCnt); - scanIsCached = true; - } - // before the first frame is read, or we have an empty data stream - if (frameNumber == -1) - return (imageSizes.count() > 0) ? QVariant(imageSizes.at(0)) : QVariant(); - // after the last frame has been read, the next size is undefined - if (frameNumber >= imageSizes.count() - 1) - return QVariant(); - // and the last case: the size of the next frame - return imageSizes.at(frameNumber + 1); - } else if (option == Animation) { - return true; - } - return QVariant(); -} - -void QGifHandler::setOption(ImageOption option, const QVariant &value) -{ - Q_UNUSED(option); - Q_UNUSED(value); -} - -int QGifHandler::nextImageDelay() const -{ - return nextDelay; -} - -int QGifHandler::imageCount() const -{ - if (!scanIsCached) { - QGIFFormat::scan(device(), &imageSizes, &loopCnt); - scanIsCached = true; - } - return imageSizes.count(); -} - -int QGifHandler::loopCount() const -{ - if (!scanIsCached) { - QGIFFormat::scan(device(), &imageSizes, &loopCnt); - scanIsCached = true; - } - return loopCnt-1; // In GIF, loop count is iteration count, so subtract one -} - -int QGifHandler::currentImageNumber() const -{ - return frameNumber; -} - -QByteArray QGifHandler::name() const -{ - return "gif"; -} - -QT_END_NAMESPACE diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp index 4edb87a..032ff85 100644 --- a/src/plugins/imageformats/ico/qicohandler.cpp +++ b/src/plugins/imageformats/ico/qicohandler.cpp @@ -54,6 +54,9 @@ #include <QtCore/QFile> #include <QtCore/QBuffer> #include <qvariant.h> + +QT_BEGIN_NAMESPACE + // These next two structs represent how the icon information is stored // in an ICO file. typedef struct @@ -891,3 +894,4 @@ bool QtIcoHandler::jumpToNextImage() return jumpToImage(m_currentIconIndex + 1); } +QT_END_NAMESPACE diff --git a/src/plugins/imageformats/ico/qicohandler.h b/src/plugins/imageformats/ico/qicohandler.h index 394a5eb..4334ad9 100644 --- a/src/plugins/imageformats/ico/qicohandler.h +++ b/src/plugins/imageformats/ico/qicohandler.h @@ -43,6 +43,8 @@ #include <QtGui/QImageIOHandler> +QT_BEGIN_NAMESPACE + class ICOReader; class QtIcoHandler: public QImageIOHandler { @@ -71,5 +73,7 @@ private: }; +QT_END_NAMESPACE + #endif /* QTICOHANDLER_H */ diff --git a/src/plugins/imageformats/imageformats.pro b/src/plugins/imageformats/imageformats.pro index 2e4036b..5fff2de 100644 --- a/src/plugins/imageformats/imageformats.pro +++ b/src/plugins/imageformats/imageformats.pro @@ -1,8 +1,8 @@ TEMPLATE = subdirs -!contains(QT_CONFIG, no-jpeg):SUBDIRS += jpeg -!contains(QT_CONFIG, no-gif):SUBDIRS += gif -!contains(QT_CONFIG, no-mng):SUBDIRS += mng +!contains(QT_CONFIG, no-jpeg):!contains(QT_CONFIG, jpeg):SUBDIRS += jpeg +!contains(QT_CONFIG, no-gif):!contains(QT_CONFIG, gif):SUBDIRS += gif +!contains(QT_CONFIG, no-mng):!contains(QT_CONFIG, mng):SUBDIRS += mng contains(QT_CONFIG, svg):SUBDIRS += svg -!contains(QT_CONFIG, no-tiff):SUBDIRS += tiff +!contains(QT_CONFIG, no-tiff):!contains(QT_CONFIG, tiff):SUBDIRS += tiff !contains(QT_CONFIG, no-ico):SUBDIRS += ico diff --git a/src/plugins/imageformats/jpeg/jpeg.pro b/src/plugins/imageformats/jpeg/jpeg.pro index ebc79cc..fb254b8 100644 --- a/src/plugins/imageformats/jpeg/jpeg.pro +++ b/src/plugins/imageformats/jpeg/jpeg.pro @@ -3,78 +3,9 @@ include(../../qpluginbase.pri) QTDIR_build:REQUIRES = "!contains(QT_CONFIG, no-jpeg)" -HEADERS += qjpeghandler.h -SOURCES += main.cpp \ - qjpeghandler.cpp - -wince*: { - DEFINES += NO_GETENV - contains(CE_ARCH,x86):CONFIG -= stl exceptions - contains(CE_ARCH,x86):CONFIG += exceptions_off -} - -symbian: { - #Disable warnings in 3rdparty code due to unused arguments - QMAKE_CXXFLAGS.CW += -W nounusedarg - TARGET.UID3=0x2001E61B -} - -contains(QT_CONFIG, system-jpeg) { - unix:LIBS += -ljpeg - win32:LIBS += libjpeg.lib -} -!contains(QT_CONFIG, system-jpeg) { - INCLUDEPATH += ../../../3rdparty/libjpeg - SOURCES += \ - ../../../3rdparty/libjpeg/jcapimin.c \ - ../../../3rdparty/libjpeg/jcapistd.c \ - ../../../3rdparty/libjpeg/jccoefct.c \ - ../../../3rdparty/libjpeg/jccolor.c \ - ../../../3rdparty/libjpeg/jcdctmgr.c \ - ../../../3rdparty/libjpeg/jchuff.c \ - ../../../3rdparty/libjpeg/jcinit.c \ - ../../../3rdparty/libjpeg/jcmainct.c \ - ../../../3rdparty/libjpeg/jcmarker.c \ - ../../../3rdparty/libjpeg/jcmaster.c \ - ../../../3rdparty/libjpeg/jcomapi.c \ - ../../../3rdparty/libjpeg/jcparam.c \ - ../../../3rdparty/libjpeg/jcphuff.c \ - ../../../3rdparty/libjpeg/jcprepct.c \ - ../../../3rdparty/libjpeg/jcsample.c \ - ../../../3rdparty/libjpeg/jctrans.c \ - ../../../3rdparty/libjpeg/jdapimin.c \ - ../../../3rdparty/libjpeg/jdapistd.c \ - ../../../3rdparty/libjpeg/jdatadst.c \ - ../../../3rdparty/libjpeg/jdatasrc.c \ - ../../../3rdparty/libjpeg/jdcoefct.c \ - ../../../3rdparty/libjpeg/jdcolor.c \ - ../../../3rdparty/libjpeg/jddctmgr.c \ - ../../../3rdparty/libjpeg/jdhuff.c \ - ../../../3rdparty/libjpeg/jdinput.c \ - ../../../3rdparty/libjpeg/jdmainct.c \ - ../../../3rdparty/libjpeg/jdmarker.c \ - ../../../3rdparty/libjpeg/jdmaster.c \ - ../../../3rdparty/libjpeg/jdmerge.c \ - ../../../3rdparty/libjpeg/jdphuff.c \ - ../../../3rdparty/libjpeg/jdpostct.c \ - ../../../3rdparty/libjpeg/jdsample.c \ - ../../../3rdparty/libjpeg/jdtrans.c \ - ../../../3rdparty/libjpeg/jerror.c \ - ../../../3rdparty/libjpeg/jfdctflt.c \ - ../../../3rdparty/libjpeg/jfdctfst.c \ - ../../../3rdparty/libjpeg/jfdctint.c \ - ../../../3rdparty/libjpeg/jidctflt.c \ - ../../../3rdparty/libjpeg/jidctfst.c \ - ../../../3rdparty/libjpeg/jidctint.c \ - ../../../3rdparty/libjpeg/jidctred.c \ - ../../../3rdparty/libjpeg/jmemmgr.c \ - ../../../3rdparty/libjpeg/jquant1.c \ - ../../../3rdparty/libjpeg/jquant2.c \ - ../../../3rdparty/libjpeg/jutils.c \ - ../../../3rdparty/libjpeg/jmemnobs.c -} +include(../../../gui/image/qjpeghandler.pri) +SOURCES += main.cpp QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats INSTALLS += target - diff --git a/src/plugins/imageformats/jpeg/main.cpp b/src/plugins/imageformats/jpeg/main.cpp index 2a45cb0..8eb3f03 100644 --- a/src/plugins/imageformats/jpeg/main.cpp +++ b/src/plugins/imageformats/jpeg/main.cpp @@ -47,7 +47,7 @@ #ifdef QT_NO_IMAGEFORMAT_JPEG #undef QT_NO_IMAGEFORMAT_JPEG #endif -#include "qjpeghandler.h" +#include <qjpeghandler_p.h> QT_BEGIN_NAMESPACE diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp deleted file mode 100644 index 98bd88f..0000000 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ /dev/null @@ -1,1269 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 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$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, 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. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qjpeghandler.h" - -#include <qimage.h> -#include <qvariant.h> -#include <qvector.h> - -#include <stdio.h> // jpeglib needs this to be pre-included -#include <setjmp.h> - -#ifdef FAR -#undef FAR -#endif - -// hw: optimize smoothscaler for returning 24-bit images - -// including jpeglib.h seems to be a little messy -extern "C" { -// mingw includes rpcndr.h but does not define boolean -#if defined(Q_OS_WIN) && defined(Q_CC_GNU) -# if defined(__RPCNDR_H__) && !defined(boolean) - typedef unsigned char boolean; -# define HAVE_BOOLEAN -# endif -#endif - -#define XMD_H // shut JPEGlib up -#if defined(Q_OS_UNIXWARE) -# define HAVE_BOOLEAN // libjpeg under Unixware seems to need this -#endif -#include <jpeglib.h> -#ifdef const -# undef const // remove crazy C hackery in jconfig.h -#endif -} - -QT_BEGIN_NAMESPACE - -//#define QT_NO_IMAGE_SMOOTHSCALE -#ifndef QT_NO_IMAGE_SMOOTHSCALE -class QImageSmoothScalerPrivate; -class QImageSmoothScaler -{ -public: - QImageSmoothScaler(const int w, const int h, const QImage &src); - QImageSmoothScaler(const int srcWidth, const int srcHeight, - const int dstWidth, const int dstHeight); - - virtual ~QImageSmoothScaler(void); - - QImage scale(); - -private: - QImageSmoothScalerPrivate *d; - virtual QRgb *scanLine(const int line = 0, const QImage *src = 0); -}; - -class QImageSmoothScalerPrivate -{ -public: - int cols; - int newcols; - int rows; - int newrows; - bool hasAlpha; - - const QImage *src; - - void setup(const int srcWidth, const int srcHeight, const int dstWidth, - const int dstHeight, bool hasAlphaChannel); -}; - -QImageSmoothScaler::QImageSmoothScaler(const int w, const int h, - const QImage &src) -{ - d = new QImageSmoothScalerPrivate; - - d->setup(src.width(), src.height(), w, h, src.hasAlphaChannel() ); - this->d->src = &src; -} - -QImageSmoothScaler::QImageSmoothScaler(const int srcWidth, const int srcHeight, - const int dstWidth, const int dstHeight) -{ - d = new QImageSmoothScalerPrivate; - d->setup(srcWidth, srcHeight, dstWidth, dstHeight, 0); -} - -void QImageSmoothScalerPrivate::setup(const int srcWidth, const int srcHeight, - const int dstWidth, const int dstHeight, - bool hasAlphaChannel) -{ - cols = srcWidth; - rows = srcHeight; - newcols = dstWidth; - newrows = dstHeight; - hasAlpha = hasAlphaChannel; -} - -QImageSmoothScaler::~QImageSmoothScaler() -{ - delete d; -} - -inline QRgb *QImageSmoothScaler::scanLine(const int line, const QImage *src) -{ - return (QRgb*)src->scanLine(line); -} - -/* - This function uses code based on pnmscale.c by Jef Poskanzer. - - pnmscale.c - read a portable anymap and scale it - - Copyright (C) 1989, 1991 by Jef Poskanzer. - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose and without fee is hereby granted, provided - that the above copyright notice appear in all copies and that both that - copyright notice and this permission notice appear in supporting - documentation. This software is provided "as is" without express or - implied warranty. -*/ - -QImage QImageSmoothScaler::scale() -{ - long SCALE; - long HALFSCALE; - QRgb *xelrow = 0; - QRgb *tempxelrow = 0; - QRgb *xP; - QRgb *nxP; - int row, rowsread; - int col, needtoreadrow; - uchar maxval = 255; - qreal xscale, yscale; - long sxscale, syscale; - long fracrowtofill, fracrowleft; - long *as; - long *rs; - long *gs; - long *bs; - int rowswritten = 0; - QImage dst; - - if (d->cols > 4096) { - SCALE = 4096; - HALFSCALE = 2048; - } else { - int fac = 4096; - while (d->cols * fac > 4096) - fac /= 2; - - SCALE = fac * d->cols; - HALFSCALE = fac * d->cols / 2; - } - - xscale = (qreal)d->newcols / (qreal)d->cols; - yscale = (qreal)d->newrows / (qreal)d->rows; - sxscale = (long)(xscale * SCALE); - syscale = (long)(yscale * SCALE); - - // shortcut Y scaling if possible - if (d->newrows != d->rows) - tempxelrow = new QRgb[d->cols]; - - if (d->hasAlpha) { - as = new long[d->cols]; - for (col = 0; col < d->cols; ++col) - as[col] = HALFSCALE; - } else { - as = 0; - } - rs = new long[d->cols]; - gs = new long[d->cols]; - bs = new long[d->cols]; - rowsread = 0; - fracrowleft = syscale; - needtoreadrow = 1; - for (col = 0; col < d->cols; ++col) - rs[col] = gs[col] = bs[col] = HALFSCALE; - fracrowtofill = SCALE; - - dst = QImage(d->newcols, d->newrows, d->hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32); - - for (row = 0; row < d->newrows; ++row) { - // First scale Y from xelrow into tempxelrow. - if (d->newrows == d->rows) { - // shortcut Y scaling if possible - tempxelrow = xelrow = scanLine(rowsread++, d->src); - } else { - while (fracrowleft < fracrowtofill) { - if (needtoreadrow && rowsread < d->rows) - xelrow = scanLine(rowsread++, d->src); - for (col = 0, xP = xelrow; col < d->cols; ++col, ++xP) { - if (as) { - as[col] += fracrowleft * qAlpha(*xP); - rs[col] += fracrowleft * qRed(*xP) * qAlpha(*xP) / 255; - gs[col] += fracrowleft * qGreen(*xP) * qAlpha(*xP) / 255; - bs[col] += fracrowleft * qBlue(*xP) * qAlpha(*xP) / 255; - } else { - rs[col] += fracrowleft * qRed(*xP); - gs[col] += fracrowleft * qGreen(*xP); - bs[col] += fracrowleft * qBlue(*xP); - } - } - fracrowtofill -= fracrowleft; - fracrowleft = syscale; - needtoreadrow = 1; - } - // Now fracrowleft is >= fracrowtofill, so we can produce a row. - if (needtoreadrow && rowsread < d->rows) { - xelrow = scanLine(rowsread++, d->src); - needtoreadrow = 0; - } - for (col = 0, xP = xelrow, nxP = tempxelrow; col < d->cols; ++col, ++xP, ++nxP) { - register long a, r, g, b; - - if (as) { - r = rs[col] + fracrowtofill * qRed(*xP) * qAlpha(*xP) / 255; - g = gs[col] + fracrowtofill * qGreen(*xP) * qAlpha(*xP) / 255; - b = bs[col] + fracrowtofill * qBlue(*xP) * qAlpha(*xP) / 255; - a = as[col] + fracrowtofill * qAlpha(*xP); - if (a) { - r = r * 255 / a * SCALE; - g = g * 255 / a * SCALE; - b = b * 255 / a * SCALE; - } - } else { - r = rs[col] + fracrowtofill * qRed(*xP); - g = gs[col] + fracrowtofill * qGreen(*xP); - b = bs[col] + fracrowtofill * qBlue(*xP); - a = 0; // unwarn - } - r /= SCALE; - if (r > maxval) - r = maxval; - g /= SCALE; - if (g > maxval) - g = maxval; - b /= SCALE; - if (b > maxval) - b = maxval; - if (as) { - a /= SCALE; - if (a > maxval) - a = maxval; - *nxP = qRgba((int)r, (int)g, (int)b, (int)a); - as[col] = HALFSCALE; - } else { - *nxP = qRgb((int)r, (int)g, (int)b); - } - rs[col] = gs[col] = bs[col] = HALFSCALE; - } - fracrowleft -= fracrowtofill; - if (fracrowleft == 0) { - fracrowleft = syscale; - needtoreadrow = 1; - } - fracrowtofill = SCALE; - } - - // Now scale X from tempxelrow into dst and write it out. - if (d->newcols == d->cols) { - // shortcut X scaling if possible - memcpy(dst.scanLine(rowswritten++), tempxelrow, d->newcols * 4); - } else { - register long a, r, g, b; - register long fraccoltofill, fraccolleft = 0; - register int needcol; - - nxP = (QRgb *)dst.scanLine(rowswritten++); - QRgb *nxPEnd = nxP + d->newcols; - fraccoltofill = SCALE; - a = r = g = b = HALFSCALE; - needcol = 0; - for (col = 0, xP = tempxelrow; col < d->cols; ++col, ++xP) { - fraccolleft = sxscale; - while (fraccolleft >= fraccoltofill) { - if (needcol) { - ++nxP; - a = r = g = b = HALFSCALE; - } - if (as) { - r += fraccoltofill * qRed(*xP) * qAlpha(*xP) / 255; - g += fraccoltofill * qGreen(*xP) * qAlpha(*xP) / 255; - b += fraccoltofill * qBlue(*xP) * qAlpha(*xP) / 255; - a += fraccoltofill * qAlpha(*xP); - if (a) { - r = r * 255 / a * SCALE; - g = g * 255 / a * SCALE; - b = b * 255 / a * SCALE; - } - } else { - r += fraccoltofill * qRed(*xP); - g += fraccoltofill * qGreen(*xP); - b += fraccoltofill * qBlue(*xP); - } - r /= SCALE; - if (r > maxval) - r = maxval; - g /= SCALE; - if (g > maxval) - g = maxval; - b /= SCALE; - if (b > maxval) - b = maxval; - if (as) { - a /= SCALE; - if (a > maxval) - a = maxval; - *nxP = qRgba((int)r, (int)g, (int)b, (int)a); - } else { - *nxP = qRgb((int)r, (int)g, (int)b); - } - fraccolleft -= fraccoltofill; - fraccoltofill = SCALE; - needcol = 1; - } - if (fraccolleft > 0) { - if (needcol) { - ++nxP; - a = r = g = b = HALFSCALE; - needcol = 0; - } - if (as) { - a += fraccolleft * qAlpha(*xP); - r += fraccolleft * qRed(*xP) * qAlpha(*xP) / 255; - g += fraccolleft * qGreen(*xP) * qAlpha(*xP) / 255; - b += fraccolleft * qBlue(*xP) * qAlpha(*xP) / 255; - } else { - r += fraccolleft * qRed(*xP); - g += fraccolleft * qGreen(*xP); - b += fraccolleft * qBlue(*xP); - } - fraccoltofill -= fraccolleft; - } - } - if (fraccoltofill > 0) { - --xP; - if (as) { - a += fraccolleft * qAlpha(*xP); - r += fraccoltofill * qRed(*xP) * qAlpha(*xP) / 255; - g += fraccoltofill * qGreen(*xP) * qAlpha(*xP) / 255; - b += fraccoltofill * qBlue(*xP) * qAlpha(*xP) / 255; - if (a) { - r = r * 255 / a * SCALE; - g = g * 255 / a * SCALE; - b = b * 255 / a * SCALE; - } - } else { - r += fraccoltofill * qRed(*xP); - g += fraccoltofill * qGreen(*xP); - b += fraccoltofill * qBlue(*xP); - } - } - if (nxP < nxPEnd) { - r /= SCALE; - if (r > maxval) - r = maxval; - g /= SCALE; - if (g > maxval) - g = maxval; - b /= SCALE; - if (b > maxval) - b = maxval; - if (as) { - a /= SCALE; - if (a > maxval) - a = maxval; - *nxP = qRgba((int)r, (int)g, (int)b, (int)a); - } else { - *nxP = qRgb((int)r, (int)g, (int)b); - } - while (++nxP != nxPEnd) - nxP[0] = nxP[-1]; - } - } - } - - if (d->newrows != d->rows && tempxelrow)// Robust, tempxelrow might be 0 1 day - delete [] tempxelrow; - if (as) // Avoid purify complaint - delete [] as; - if (rs) // Robust, rs might be 0 one day - delete [] rs; - if (gs) // Robust, gs might be 0 one day - delete [] gs; - if (bs) // Robust, bs might be 0 one day - delete [] bs; - - return dst; -} - -class jpegSmoothScaler : public QImageSmoothScaler -{ -public: - jpegSmoothScaler(struct jpeg_decompress_struct *info, const QSize& dstSize, const QRect& clipRect) - : QImageSmoothScaler(clipRect.width(), clipRect.height(), - dstSize.width(), dstSize.height()) - { - cinfo = info; - clip = clipRect; - imageCache = QImage(info->output_width, 1, QImage::Format_RGB32); - } - -private: - QRect clip; - QImage imageCache; - struct jpeg_decompress_struct *cinfo; - - QRgb *scanLine(const int line = 0, const QImage *src = 0) - { - QRgb *out; - uchar *in; - - Q_UNUSED(line); - Q_UNUSED(src); - - uchar* data = imageCache.bits(); - - // Read ahead if we haven't reached the first clipped scanline yet. - while (int(cinfo->output_scanline) < clip.y() && - cinfo->output_scanline < cinfo->output_height) - jpeg_read_scanlines(cinfo, &data, 1); - - // Read the next scanline. We assume that "line" - // will never be >= clip.height(). - jpeg_read_scanlines(cinfo, &data, 1); - if (cinfo->output_scanline == cinfo->output_height) - jpeg_finish_decompress(cinfo); - - out = ((QRgb*)data) + clip.x(); - - // - // The smooth scale algorithm only works on 32-bit images; - // convert from (8|24) bits to 32. - // - if (cinfo->output_components == 1) { - in = data + clip.right(); - for (int i = clip.width(); i--; ) { - out[i] = qRgb(*in, *in, *in); - in--; - } - } else if (cinfo->out_color_space == JCS_CMYK) { - in = data + clip.right() * 4; - for (int i = clip.width(); i--; ) { - int k = in[3]; - out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255); - in -= 4; - } - } else { - in = data + clip.right() * 3; - for (int i = clip.width(); i--; ) { - out[i] = qRgb(in[0], in[1], in[2]); - in -= 3; - } - } - - return out; - } - -}; -#endif - -struct my_error_mgr : public jpeg_error_mgr { - jmp_buf setjmp_buffer; -}; - -#if defined(Q_C_CALLBACKS) -extern "C" { -#endif - -static void my_error_exit (j_common_ptr cinfo) -{ - my_error_mgr* myerr = (my_error_mgr*) cinfo->err; - char buffer[JMSG_LENGTH_MAX]; - (*cinfo->err->format_message)(cinfo, buffer); - qWarning("%s", buffer); - longjmp(myerr->setjmp_buffer, 1); -} - -#if defined(Q_C_CALLBACKS) -} -#endif - - -static const int max_buf = 4096; - -struct my_jpeg_source_mgr : public jpeg_source_mgr { - // Nothing dynamic - cannot rely on destruction over longjump - QIODevice *device; - JOCTET buffer[max_buf]; - -public: - my_jpeg_source_mgr(QIODevice *device); -}; - -#if defined(Q_C_CALLBACKS) -extern "C" { -#endif - -static void qt_init_source(j_decompress_ptr) -{ -} - -static boolean qt_fill_input_buffer(j_decompress_ptr cinfo) -{ - int num_read; - my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src; - src->next_input_byte = src->buffer; - num_read = src->device->read((char*)src->buffer, max_buf); - if (num_read <= 0) { - // Insert a fake EOI marker - as per jpeglib recommendation - src->buffer[0] = (JOCTET) 0xFF; - src->buffer[1] = (JOCTET) JPEG_EOI; - src->bytes_in_buffer = 2; - } else { - src->bytes_in_buffer = num_read; - } -#if defined(Q_OS_UNIXWARE) - return B_TRUE; -#else - return true; -#endif -} - -static void qt_skip_input_data(j_decompress_ptr cinfo, long num_bytes) -{ - my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src; - - // `dumb' implementation from jpeglib - - /* Just a dumb implementation for now. Could use fseek() except - * it doesn't work on pipes. Not clear that being smart is worth - * any trouble anyway --- large skips are infrequent. - */ - if (num_bytes > 0) { - while (num_bytes > (long) src->bytes_in_buffer) { - num_bytes -= (long) src->bytes_in_buffer; - (void) qt_fill_input_buffer(cinfo); - /* note we assume that qt_fill_input_buffer will never return false, - * so suspension need not be handled. - */ - } - src->next_input_byte += (size_t) num_bytes; - src->bytes_in_buffer -= (size_t) num_bytes; - } -} - -static void qt_term_source(j_decompress_ptr cinfo) -{ - my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src; - if (!src->device->isSequential()) - src->device->seek(src->device->pos() - src->bytes_in_buffer); -} - -#if defined(Q_C_CALLBACKS) -} -#endif - -inline my_jpeg_source_mgr::my_jpeg_source_mgr(QIODevice *device) -{ - jpeg_source_mgr::init_source = qt_init_source; - jpeg_source_mgr::fill_input_buffer = qt_fill_input_buffer; - jpeg_source_mgr::skip_input_data = qt_skip_input_data; - jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart; - jpeg_source_mgr::term_source = qt_term_source; - this->device = device; - bytes_in_buffer = 0; - next_input_byte = buffer; -} - - -static bool read_jpeg_size(QIODevice *device, int &w, int &h) -{ - bool rt = false; - struct jpeg_decompress_struct cinfo; - - struct my_jpeg_source_mgr *iod_src = new my_jpeg_source_mgr(device); - struct my_error_mgr jerr; - - jpeg_create_decompress(&cinfo); - - cinfo.src = iod_src; - - cinfo.err = jpeg_std_error(&jerr); - jerr.error_exit = my_error_exit; - - if (!setjmp(jerr.setjmp_buffer)) { -#if defined(Q_OS_UNIXWARE) - (void) jpeg_read_header(&cinfo, B_TRUE); -#else - (void) jpeg_read_header(&cinfo, true); -#endif - (void) jpeg_calc_output_dimensions(&cinfo); - - w = cinfo.output_width; - h = cinfo.output_height; - rt = true; - } - jpeg_destroy_decompress(&cinfo); - delete iod_src; - return rt; -} - -#define HIGH_QUALITY_THRESHOLD 50 - -static bool read_jpeg_format(QIODevice *device, QImage::Format &format) -{ - bool result = false; - struct jpeg_decompress_struct cinfo; - - struct my_jpeg_source_mgr *iod_src = new my_jpeg_source_mgr(device); - struct my_error_mgr jerr; - - jpeg_create_decompress(&cinfo); - - cinfo.src = iod_src; - - cinfo.err = jpeg_std_error(&jerr); - jerr.error_exit = my_error_exit; - - if (!setjmp(jerr.setjmp_buffer)) { -#if defined(Q_OS_UNIXWARE) - (void) jpeg_read_header(&cinfo, B_TRUE); -#else - (void) jpeg_read_header(&cinfo, true); -#endif - // This does not allocate memory for the whole image - // or such, so we are safe. - (void) jpeg_start_decompress(&cinfo); - result = true; - switch (cinfo.output_components) { - case 1: - format = QImage::Format_Indexed8; - break; - case 3: - case 4: - format = QImage::Format_RGB32; - break; - default: - result = false; - break; - } - cinfo.output_scanline = cinfo.output_height; - (void) jpeg_finish_decompress(&cinfo); - } - jpeg_destroy_decompress(&cinfo); - delete iod_src; - return result; -} - -static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info, - const QSize& size) -{ - QImage::Format format; - switch (info->output_components) { - case 1: - format = QImage::Format_Indexed8; - break; - case 3: - case 4: - format = QImage::Format_RGB32; - break; - default: - return false; // unsupported format - } - - if (dest->size() != size || dest->format() != format) { - *dest = QImage(size, format); - - if (format == QImage::Format_Indexed8) { - dest->setColorCount(256); - for (int i = 0; i < 256; i++) - dest->setColor(i, qRgb(i,i,i)); - } - } - - return !dest->isNull(); -} - -static bool read_jpeg_image(QIODevice *device, QImage *outImage, - QSize scaledSize, QRect scaledClipRect, - QRect clipRect, int inQuality ) -{ - struct jpeg_decompress_struct cinfo; - - struct my_jpeg_source_mgr *iod_src = new my_jpeg_source_mgr(device); - struct my_error_mgr jerr; - - jpeg_create_decompress(&cinfo); - - cinfo.src = iod_src; - - cinfo.err = jpeg_std_error(&jerr); - jerr.error_exit = my_error_exit; - - if (!setjmp(jerr.setjmp_buffer)) { -#if defined(Q_OS_UNIXWARE) - (void) jpeg_read_header(&cinfo, B_TRUE); -#else - (void) jpeg_read_header(&cinfo, true); -#endif - - // -1 means default quality. - int quality = inQuality; - if (quality < 0) - quality = 75; - - // If possible, merge the scaledClipRect into either scaledSize - // or clipRect to avoid doing a separate scaled clipping pass. - // Best results are achieved by clipping before scaling, not after. - if (!scaledClipRect.isEmpty()) { - if (scaledSize.isEmpty() && clipRect.isEmpty()) { - // No clipping or scaling before final clip. - clipRect = scaledClipRect; - scaledClipRect = QRect(); - } else if (scaledSize.isEmpty()) { - // Clipping, but no scaling: combine the clip regions. - scaledClipRect.translate(clipRect.topLeft()); - clipRect = scaledClipRect.intersected(clipRect); - scaledClipRect = QRect(); - } else if (clipRect.isEmpty()) { - // No clipping, but scaling: if we can map back to an - // integer pixel boundary, then clip before scaling. - if ((cinfo.image_width % scaledSize.width()) == 0 && - (cinfo.image_height % scaledSize.height()) == 0) { - int x = scaledClipRect.x() * cinfo.image_width / - scaledSize.width(); - int y = scaledClipRect.y() * cinfo.image_height / - scaledSize.height(); - int width = (scaledClipRect.right() + 1) * - cinfo.image_width / scaledSize.width() - x; - int height = (scaledClipRect.bottom() + 1) * - cinfo.image_height / scaledSize.height() - y; - clipRect = QRect(x, y, width, height); - scaledSize = scaledClipRect.size(); - scaledClipRect = QRect(); - } - } else { - // Clipping and scaling: too difficult to figure out, - // and not a likely use case, so do it the long way. - } - } - - // Determine the scale factor to pass to libjpeg for quick downscaling. - if (!scaledSize.isEmpty()) { - if (clipRect.isEmpty()) { - cinfo.scale_denom = - qMin(cinfo.image_width / scaledSize.width(), - cinfo.image_height / scaledSize.height()); - } else { - cinfo.scale_denom = - qMin(clipRect.width() / scaledSize.width(), - clipRect.height() / scaledSize.height()); - } - if (cinfo.scale_denom < 2) { - cinfo.scale_denom = 1; - } else if (cinfo.scale_denom < 4) { - cinfo.scale_denom = 2; - } else if (cinfo.scale_denom < 8) { - cinfo.scale_denom = 4; - } else { - cinfo.scale_denom = 8; - } - cinfo.scale_num = 1; - if (!clipRect.isEmpty()) { - // Correct the scale factor so that we clip accurately. - // It is recommended that the clip rectangle be aligned - // on an 8-pixel boundary for best performance. - while (cinfo.scale_denom > 1 && - ((clipRect.x() % cinfo.scale_denom) != 0 || - (clipRect.y() % cinfo.scale_denom) != 0 || - (clipRect.width() % cinfo.scale_denom) != 0 || - (clipRect.height() % cinfo.scale_denom) != 0)) { - cinfo.scale_denom /= 2; - } - } - } - - // If high quality not required, use fast decompression - if( quality < HIGH_QUALITY_THRESHOLD ) { - cinfo.dct_method = JDCT_IFAST; - cinfo.do_fancy_upsampling = FALSE; - } - - (void) jpeg_calc_output_dimensions(&cinfo); - - // Determine the clip region to extract. - QRect imageRect(0, 0, cinfo.output_width, cinfo.output_height); - QRect clip; - if (clipRect.isEmpty()) { - clip = imageRect; - } else if (cinfo.scale_denom == 1) { - clip = clipRect.intersected(imageRect); - } else { - // The scale factor was corrected above to ensure that - // we don't miss pixels when we scale the clip rectangle. - clip = QRect(clipRect.x() / int(cinfo.scale_denom), - clipRect.y() / int(cinfo.scale_denom), - clipRect.width() / int(cinfo.scale_denom), - clipRect.height() / int(cinfo.scale_denom)); - clip = clip.intersected(imageRect); - } - -#ifndef QT_NO_IMAGE_SMOOTHSCALE - if (scaledSize.isValid() && scaledSize != clip.size() - && quality >= HIGH_QUALITY_THRESHOLD) { - - (void) jpeg_start_decompress(&cinfo); - - jpegSmoothScaler scaler(&cinfo, scaledSize, clip); - *outImage = scaler.scale(); - } else -#endif - { - // Allocate memory for the clipped QImage. - if (!ensureValidImage(outImage, &cinfo, clip.size())) - longjmp(jerr.setjmp_buffer, 1); - - // Avoid memcpy() overhead if grayscale with no clipping. - bool quickGray = (cinfo.output_components == 1 && - clip == imageRect); - if (!quickGray) { - // Ask the jpeg library to allocate a temporary row. - // The library will automatically delete it for us later. - // The libjpeg docs say we should do this before calling - // jpeg_start_decompress(). We can't use "new" here - // because we are inside the setjmp() block and an error - // in the jpeg input stream would cause a memory leak. - JSAMPARRAY rows = (cinfo.mem->alloc_sarray) - ((j_common_ptr)&cinfo, JPOOL_IMAGE, - cinfo.output_width * cinfo.output_components, 1); - - (void) jpeg_start_decompress(&cinfo); - - while (cinfo.output_scanline < cinfo.output_height) { - int y = int(cinfo.output_scanline) - clip.y(); - if (y >= clip.height()) - break; // We've read the entire clip region, so abort. - - (void) jpeg_read_scanlines(&cinfo, rows, 1); - - if (y < 0) - continue; // Haven't reached the starting line yet. - - if (cinfo.output_components == 3) { - // Expand 24->32 bpp. - uchar *in = rows[0] + clip.x() * 3; - QRgb *out = (QRgb*)outImage->scanLine(y); - for (int i = 0; i < clip.width(); ++i) { - *out++ = qRgb(in[0], in[1], in[2]); - in += 3; - } - } else if (cinfo.out_color_space == JCS_CMYK) { - // Convert CMYK->RGB. - uchar *in = rows[0] + clip.x() * 4; - QRgb *out = (QRgb*)outImage->scanLine(y); - for (int i = 0; i < clip.width(); ++i) { - int k = in[3]; - *out++ = qRgb(k * in[0] / 255, k * in[1] / 255, - k * in[2] / 255); - in += 4; - } - } else if (cinfo.output_components == 1) { - // Grayscale. - memcpy(outImage->scanLine(y), - rows[0] + clip.x(), clip.width()); - } - } - } else { - // Load unclipped grayscale data directly into the QImage. - (void) jpeg_start_decompress(&cinfo); - while (cinfo.output_scanline < cinfo.output_height) { - uchar *row = outImage->scanLine(cinfo.output_scanline); - (void) jpeg_read_scanlines(&cinfo, &row, 1); - } - } - - if (cinfo.output_scanline == cinfo.output_height) - (void) jpeg_finish_decompress(&cinfo); - - if (cinfo.density_unit == 1) { - outImage->setDotsPerMeterX(int(100. * cinfo.X_density / 2.54)); - outImage->setDotsPerMeterY(int(100. * cinfo.Y_density / 2.54)); - } else if (cinfo.density_unit == 2) { - outImage->setDotsPerMeterX(int(100. * cinfo.X_density)); - outImage->setDotsPerMeterY(int(100. * cinfo.Y_density)); - } - - if (scaledSize.isValid() && scaledSize != clip.size()) - *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::FastTransformation); - } - } - - jpeg_destroy_decompress(&cinfo); - delete iod_src; - if (!scaledClipRect.isEmpty()) - *outImage = outImage->copy(scaledClipRect); - return !outImage->isNull(); -} - - -struct my_jpeg_destination_mgr : public jpeg_destination_mgr { - // Nothing dynamic - cannot rely on destruction over longjump - QIODevice *device; - JOCTET buffer[max_buf]; - -public: - my_jpeg_destination_mgr(QIODevice *); -}; - - -#if defined(Q_C_CALLBACKS) -extern "C" { -#endif - -static void qt_init_destination(j_compress_ptr) -{ -} - -static boolean qt_empty_output_buffer(j_compress_ptr cinfo) -{ - my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest; - - int written = dest->device->write((char*)dest->buffer, max_buf); - if (written == -1) - (*cinfo->err->error_exit)((j_common_ptr)cinfo); - - dest->next_output_byte = dest->buffer; - dest->free_in_buffer = max_buf; - -#if defined(Q_OS_UNIXWARE) - return B_TRUE; -#else - return true; -#endif -} - -static void qt_term_destination(j_compress_ptr cinfo) -{ - my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest; - qint64 n = max_buf - dest->free_in_buffer; - - qint64 written = dest->device->write((char*)dest->buffer, n); - if (written == -1) - (*cinfo->err->error_exit)((j_common_ptr)cinfo); -} - -#if defined(Q_C_CALLBACKS) -} -#endif - -inline my_jpeg_destination_mgr::my_jpeg_destination_mgr(QIODevice *device) -{ - jpeg_destination_mgr::init_destination = qt_init_destination; - jpeg_destination_mgr::empty_output_buffer = qt_empty_output_buffer; - jpeg_destination_mgr::term_destination = qt_term_destination; - this->device = device; - next_output_byte = buffer; - free_in_buffer = max_buf; -} - - -static bool write_jpeg_image(const QImage &sourceImage, QIODevice *device, int sourceQuality) -{ - bool success = false; - const QImage image = sourceImage; - const QVector<QRgb> cmap = image.colorTable(); - - struct jpeg_compress_struct cinfo; - JSAMPROW row_pointer[1]; - row_pointer[0] = 0; - - struct my_jpeg_destination_mgr *iod_dest = new my_jpeg_destination_mgr(device); - struct my_error_mgr jerr; - - cinfo.err = jpeg_std_error(&jerr); - jerr.error_exit = my_error_exit; - - if (!setjmp(jerr.setjmp_buffer)) { - // WARNING: - // this if loop is inside a setjmp/longjmp branch - // do not create C++ temporaries here because the destructor may never be called - // if you allocate memory, make sure that you can free it (row_pointer[0]) - jpeg_create_compress(&cinfo); - - cinfo.dest = iod_dest; - - cinfo.image_width = image.width(); - cinfo.image_height = image.height(); - - bool gray=false; - switch (image.format()) { - case QImage::Format_Mono: - case QImage::Format_MonoLSB: - case QImage::Format_Indexed8: - gray = true; - for (int i = image.colorCount(); gray && i--;) { - gray = gray & (qRed(cmap[i]) == qGreen(cmap[i]) && - qRed(cmap[i]) == qBlue(cmap[i])); - } - cinfo.input_components = gray ? 1 : 3; - cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB; - break; - default: - cinfo.input_components = 3; - cinfo.in_color_space = JCS_RGB; - } - - jpeg_set_defaults(&cinfo); - - qreal diffInch = qAbs(image.dotsPerMeterX()*2.54/100. - qRound(image.dotsPerMeterX()*2.54/100.)) - + qAbs(image.dotsPerMeterY()*2.54/100. - qRound(image.dotsPerMeterY()*2.54/100.)); - qreal diffCm = (qAbs(image.dotsPerMeterX()/100. - qRound(image.dotsPerMeterX()/100.)) - + qAbs(image.dotsPerMeterY()/100. - qRound(image.dotsPerMeterY()/100.)))*2.54; - if (diffInch < diffCm) { - cinfo.density_unit = 1; // dots/inch - cinfo.X_density = qRound(image.dotsPerMeterX()*2.54/100.); - cinfo.Y_density = qRound(image.dotsPerMeterY()*2.54/100.); - } else { - cinfo.density_unit = 2; // dots/cm - cinfo.X_density = (image.dotsPerMeterX()+50) / 100; - cinfo.Y_density = (image.dotsPerMeterY()+50) / 100; - } - - - int quality = sourceQuality >= 0 ? qMin(sourceQuality,100) : 75; -#if defined(Q_OS_UNIXWARE) - jpeg_set_quality(&cinfo, quality, B_TRUE /* limit to baseline-JPEG values */); - jpeg_start_compress(&cinfo, B_TRUE); -#else - jpeg_set_quality(&cinfo, quality, true /* limit to baseline-JPEG values */); - jpeg_start_compress(&cinfo, true); -#endif - - row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components]; - int w = cinfo.image_width; - while (cinfo.next_scanline < cinfo.image_height) { - uchar *row = row_pointer[0]; - switch (image.format()) { - case QImage::Format_Mono: - case QImage::Format_MonoLSB: - if (gray) { - const uchar* data = image.scanLine(cinfo.next_scanline); - if (image.format() == QImage::Format_MonoLSB) { - for (int i=0; i<w; i++) { - bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7))); - row[i] = qRed(cmap[bit]); - } - } else { - for (int i=0; i<w; i++) { - bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7)))); - row[i] = qRed(cmap[bit]); - } - } - } else { - const uchar* data = image.scanLine(cinfo.next_scanline); - if (image.format() == QImage::Format_MonoLSB) { - for (int i=0; i<w; i++) { - bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7))); - *row++ = qRed(cmap[bit]); - *row++ = qGreen(cmap[bit]); - *row++ = qBlue(cmap[bit]); - } - } else { - for (int i=0; i<w; i++) { - bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7)))); - *row++ = qRed(cmap[bit]); - *row++ = qGreen(cmap[bit]); - *row++ = qBlue(cmap[bit]); - } - } - } - break; - case QImage::Format_Indexed8: - if (gray) { - const uchar* pix = image.scanLine(cinfo.next_scanline); - for (int i=0; i<w; i++) { - *row = qRed(cmap[*pix]); - ++row; ++pix; - } - } else { - const uchar* pix = image.scanLine(cinfo.next_scanline); - for (int i=0; i<w; i++) { - *row++ = qRed(cmap[*pix]); - *row++ = qGreen(cmap[*pix]); - *row++ = qBlue(cmap[*pix]); - ++pix; - } - } - break; - case QImage::Format_RGB888: - memcpy(row, image.scanLine(cinfo.next_scanline), w * 3); - break; - case QImage::Format_RGB32: - case QImage::Format_ARGB32: - case QImage::Format_ARGB32_Premultiplied: { - QRgb* rgb = (QRgb*)image.scanLine(cinfo.next_scanline); - for (int i=0; i<w; i++) { - *row++ = qRed(*rgb); - *row++ = qGreen(*rgb); - *row++ = qBlue(*rgb); - ++rgb; - } - break; - } - default: - qWarning("QJpegHandler: unable to write image of format %i", - image.format()); - break; - } - jpeg_write_scanlines(&cinfo, row_pointer, 1); - } - - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); - success = true; - } else { - jpeg_destroy_compress(&cinfo); - success = false; - } - - delete iod_dest; - delete [] row_pointer[0]; - return success; -} - -QJpegHandler::QJpegHandler() -{ - quality = 75; -} - -bool QJpegHandler::canRead() const -{ - if (canRead(device())) { - setFormat("jpeg"); - return true; - } - return false; -} - -bool QJpegHandler::canRead(QIODevice *device) -{ - if (!device) { - qWarning("QJpegHandler::canRead() called with no device"); - return false; - } - - char buffer[2]; - if (device->peek(buffer, 2) != 2) - return false; - - return uchar(buffer[0]) == 0xff && uchar(buffer[1]) == 0xd8; -} - -bool QJpegHandler::read(QImage *image) -{ - if (!canRead()) - return false; - return read_jpeg_image(device(), image, scaledSize, scaledClipRect, clipRect, quality); -} - -bool QJpegHandler::write(const QImage &image) -{ - return write_jpeg_image(image, device(), quality); -} - -bool QJpegHandler::supportsOption(ImageOption option) const -{ - return option == Quality - || option == ScaledSize - || option == ScaledClipRect - || option == ClipRect - || option == Size - || option == ImageFormat; -} - -QVariant QJpegHandler::option(ImageOption option) const -{ - if (option == Quality) { - return quality; - } else if (option == ScaledSize) { - return scaledSize; - } else if (option == ScaledClipRect) { - return scaledClipRect; - } else if (option == ClipRect) { - return clipRect; - } else if (option == Size) { - if (canRead() && !device()->isSequential()) { - qint64 pos = device()->pos(); - int width = 0; - int height = 0; - read_jpeg_size(device(), width, height); - device()->seek(pos); - return QSize(width, height); - } - } else if (option == ImageFormat) { - if (canRead() && !device()->isSequential()) { - qint64 pos = device()->pos(); - QImage::Format format = QImage::Format_Invalid; - read_jpeg_format(device(), format); - device()->seek(pos); - return format; - } - return QImage::Format_Invalid; - } - return QVariant(); -} - -void QJpegHandler::setOption(ImageOption option, const QVariant &value) -{ - if (option == Quality) - quality = value.toInt(); - else if ( option == ScaledSize ) - scaledSize = value.toSize(); - else if ( option == ScaledClipRect ) - scaledClipRect = value.toRect(); - else if ( option == ClipRect ) - clipRect = value.toRect(); -} - -QByteArray QJpegHandler::name() const -{ - return "jpeg"; -} - -QT_END_NAMESPACE diff --git a/src/plugins/imageformats/mng/main.cpp b/src/plugins/imageformats/mng/main.cpp index 84f085c..dd62ba5 100644 --- a/src/plugins/imageformats/mng/main.cpp +++ b/src/plugins/imageformats/mng/main.cpp @@ -47,7 +47,7 @@ #ifdef QT_NO_IMAGEFORMAT_MNG #undef QT_NO_IMAGEFORMAT_MNG #endif -#include "qmnghandler.h" +#include <qmnghandler_p.h> #include <qiodevice.h> #include <qbytearray.h> diff --git a/src/plugins/imageformats/mng/mng.pro b/src/plugins/imageformats/mng/mng.pro index de7dfa7..88085f3 100644 --- a/src/plugins/imageformats/mng/mng.pro +++ b/src/plugins/imageformats/mng/mng.pro @@ -3,54 +3,15 @@ include(../../qpluginbase.pri) QTDIR_build:REQUIRES = "!contains(QT_CONFIG, no-mng)" -HEADERS += qmnghandler.h -SOURCES += main.cpp \ - qmnghandler.cpp - symbian: { #Disable warnings in 3rdparty code due to unused variables and arguments QMAKE_CXXFLAGS.CW += -W nounused TARGET.UID3=0x2001E619 } -contains(QT_CONFIG, system-mng) { - unix:LIBS += -lmng - win32:LIBS += libmng.lib -} -!contains(QT_CONFIG, system-mng) { - DEFINES += MNG_BUILD_SO - DEFINES += MNG_NO_INCLUDE_JNG - INCLUDEPATH += ../../../3rdparty/libmng - SOURCES += \ - ../../../3rdparty/libmng/libmng_callback_xs.c \ - ../../../3rdparty/libmng/libmng_chunk_io.c \ - ../../../3rdparty/libmng/libmng_chunk_descr.c \ - ../../../3rdparty/libmng/libmng_chunk_prc.c \ - ../../../3rdparty/libmng/libmng_chunk_xs.c \ - ../../../3rdparty/libmng/libmng_cms.c \ - ../../../3rdparty/libmng/libmng_display.c \ - ../../../3rdparty/libmng/libmng_dither.c \ - ../../../3rdparty/libmng/libmng_error.c \ - ../../../3rdparty/libmng/libmng_filter.c \ - ../../../3rdparty/libmng/libmng_hlapi.c \ - ../../../3rdparty/libmng/libmng_jpeg.c \ - ../../../3rdparty/libmng/libmng_object_prc.c \ - ../../../3rdparty/libmng/libmng_pixels.c \ - ../../../3rdparty/libmng/libmng_prop_xs.c \ - ../../../3rdparty/libmng/libmng_read.c \ - ../../../3rdparty/libmng/libmng_trace.c \ - ../../../3rdparty/libmng/libmng_write.c \ - ../../../3rdparty/libmng/libmng_zlib.c -} - -contains(QT_CONFIG, system-zlib) { - LIBS += -lz -} -!contains(QT_CONFIG, system-zlib) { - INCLUDEPATH += ../../../3rdparty/zlib -} +include(../../../gui/image/qmnghandler.pri) +SOURCES += main.cpp QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats INSTALLS += target - diff --git a/src/plugins/imageformats/mng/qmnghandler.cpp b/src/plugins/imageformats/mng/qmnghandler.cpp deleted file mode 100644 index 9dbb885..0000000 --- a/src/plugins/imageformats/mng/qmnghandler.cpp +++ /dev/null @@ -1,497 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 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$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, 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. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qmnghandler.h" - -#include "qimage.h" -#include "qvariant.h" -#include "qcolor.h" - -#define MNG_USE_SO -#include <libmng.h> - -QT_BEGIN_NAMESPACE - -class QMngHandlerPrivate -{ - Q_DECLARE_PUBLIC(QMngHandler) - public: - bool haveReadNone; - bool haveReadAll; - mng_handle hMNG; - QImage image; - int elapsed; - int nextDelay; - int iterCount; - int frameIndex; - int nextIndex; - int frameCount; - mng_uint32 iStyle; - mng_bool readData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pRead); - mng_bool writeData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pWritten); - mng_bool processHeader(mng_uint32 iWidth, mng_uint32 iHeight); - QMngHandlerPrivate(QMngHandler *q_ptr); - ~QMngHandlerPrivate(); - bool getNextImage(QImage *result); - bool writeImage(const QImage &image); - int currentImageNumber() const; - int imageCount() const; - bool jumpToImage(int imageNumber); - bool jumpToNextImage(); - int nextImageDelay() const; - bool setBackgroundColor(const QColor &color); - QColor backgroundColor() const; - QMngHandler *q_ptr; -}; - -static mng_bool myerror(mng_handle /*hMNG*/, - mng_int32 iErrorcode, - mng_int8 /*iSeverity*/, - mng_chunkid iChunkname, - mng_uint32 /*iChunkseq*/, - mng_int32 iExtra1, - mng_int32 iExtra2, - mng_pchar zErrortext) -{ - qWarning("MNG error %d: %s; chunk %c%c%c%c; subcode %d:%d", - iErrorcode,zErrortext, - (iChunkname>>24)&0xff, - (iChunkname>>16)&0xff, - (iChunkname>>8)&0xff, - (iChunkname>>0)&0xff, - iExtra1,iExtra2); - return TRUE; -} - -static mng_ptr myalloc(mng_size_t iSize) -{ -#if defined(Q_OS_WINCE) - mng_ptr ptr = malloc(iSize); - memset(ptr, 0, iSize); - return ptr; -#else - return (mng_ptr)calloc(1, iSize); -#endif -} - -static void myfree(mng_ptr pPtr, mng_size_t /*iSize*/) -{ - free(pPtr); -} - -static mng_bool myopenstream(mng_handle) -{ - return MNG_TRUE; -} - -static mng_bool myclosestream(mng_handle hMNG) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - pMydata->haveReadAll = true; - return MNG_TRUE; -} - -static mng_bool myreaddata(mng_handle hMNG, - mng_ptr pBuf, - mng_uint32 iSize, - mng_uint32p pRead) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - return pMydata->readData(pBuf, iSize, pRead); -} - -static mng_bool mywritedata(mng_handle hMNG, - mng_ptr pBuf, - mng_uint32 iSize, - mng_uint32p pWritten) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - return pMydata->writeData(pBuf, iSize, pWritten); -} - -static mng_bool myprocessheader(mng_handle hMNG, - mng_uint32 iWidth, - mng_uint32 iHeight) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - return pMydata->processHeader(iWidth, iHeight); -} - -static mng_ptr mygetcanvasline(mng_handle hMNG, - mng_uint32 iLinenr) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - return (mng_ptr)pMydata->image.scanLine(iLinenr); -} - -static mng_bool myrefresh(mng_handle /*hMNG*/, - mng_uint32 /*iX*/, - mng_uint32 /*iY*/, - mng_uint32 /*iWidth*/, - mng_uint32 /*iHeight*/) -{ - return MNG_TRUE; -} - -static mng_uint32 mygettickcount(mng_handle hMNG) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - return pMydata->elapsed++; -} - -static mng_bool mysettimer(mng_handle hMNG, - mng_uint32 iMsecs) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - pMydata->elapsed += iMsecs; - pMydata->nextDelay = iMsecs; - return MNG_TRUE; -} - -static mng_bool myprocessterm(mng_handle hMNG, - mng_uint8 iTermaction, - mng_uint8 /*iIteraction*/, - mng_uint32 /*iDelay*/, - mng_uint32 iItermax) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - if (iTermaction == 3) - pMydata->iterCount = iItermax; - return MNG_TRUE; -} - -static mng_bool mytrace(mng_handle, - mng_int32 iFuncnr, - mng_int32 iFuncseq, - mng_pchar zFuncname) -{ - qDebug("mng trace: iFuncnr: %d iFuncseq: %d zFuncname: %s", iFuncnr, iFuncseq, zFuncname); - return MNG_TRUE; -} - -QMngHandlerPrivate::QMngHandlerPrivate(QMngHandler *q_ptr) - : haveReadNone(true), haveReadAll(false), elapsed(0), nextDelay(0), iterCount(1), - frameIndex(-1), nextIndex(0), frameCount(0), q_ptr(q_ptr) -{ - iStyle = (QSysInfo::ByteOrder == QSysInfo::LittleEndian) ? MNG_CANVAS_BGRA8 : MNG_CANVAS_ARGB8; - // Initialize libmng - hMNG = mng_initialize((mng_ptr)this, myalloc, myfree, mytrace); - if (hMNG) { - // Set callback functions - mng_setcb_errorproc(hMNG, myerror); - mng_setcb_openstream(hMNG, myopenstream); - mng_setcb_closestream(hMNG, myclosestream); - mng_setcb_readdata(hMNG, myreaddata); - mng_setcb_writedata(hMNG, mywritedata); - mng_setcb_processheader(hMNG, myprocessheader); - mng_setcb_getcanvasline(hMNG, mygetcanvasline); - mng_setcb_refresh(hMNG, myrefresh); - mng_setcb_gettickcount(hMNG, mygettickcount); - mng_setcb_settimer(hMNG, mysettimer); - mng_setcb_processterm(hMNG, myprocessterm); - mng_set_doprogressive(hMNG, MNG_FALSE); - mng_set_suspensionmode(hMNG, MNG_TRUE); - } -} - -QMngHandlerPrivate::~QMngHandlerPrivate() -{ - mng_cleanup(&hMNG); -} - -mng_bool QMngHandlerPrivate::readData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pRead) -{ - Q_Q(QMngHandler); - *pRead = q->device()->read((char *)pBuf, iSize); - return (*pRead > 0) ? MNG_TRUE : MNG_FALSE; -} - -mng_bool QMngHandlerPrivate::writeData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pWritten) -{ - Q_Q(QMngHandler); - *pWritten = q->device()->write((char *)pBuf, iSize); - return MNG_TRUE; -} - -mng_bool QMngHandlerPrivate::processHeader(mng_uint32 iWidth, mng_uint32 iHeight) -{ - if (mng_set_canvasstyle(hMNG, iStyle) != MNG_NOERROR) - return MNG_FALSE; - image = QImage(iWidth, iHeight, QImage::Format_ARGB32); - image.fill(0); - return MNG_TRUE; -} - -bool QMngHandlerPrivate::getNextImage(QImage *result) -{ - mng_retcode ret; - if (haveReadNone) { - haveReadNone = false; - ret = mng_readdisplay(hMNG); - } else { - ret = mng_display_resume(hMNG); - } - if ((MNG_NOERROR == ret) || (MNG_NEEDTIMERWAIT == ret)) { - *result = image; - frameIndex = nextIndex++; - if (haveReadAll && (frameCount == 0)) - frameCount = nextIndex; - return true; - } - return false; -} - -bool QMngHandlerPrivate::writeImage(const QImage &image) -{ - mng_reset(hMNG); - if (mng_create(hMNG) != MNG_NOERROR) - return false; - - this->image = image.convertToFormat(QImage::Format_ARGB32); - int w = image.width(); - int h = image.height(); - - if ( - // width, height, ticks, layercount, framecount, playtime, simplicity - (mng_putchunk_mhdr(hMNG, w, h, 1000, 0, 0, 0, 7) == MNG_NOERROR) && - // termination_action, action_after_iterations, delay, iteration_max - (mng_putchunk_term(hMNG, 3, 0, 1, 0x7FFFFFFF) == MNG_NOERROR) && - // width, height, bitdepth, colortype, compression, filter, interlace - (mng_putchunk_ihdr(hMNG, w, h, 8, 6, 0, 0, 0) == MNG_NOERROR) && - // width, height, colortype, bitdepth, compression, filter, interlace, canvasstyle, getcanvasline - (mng_putimgdata_ihdr(hMNG, w, h, 6, 8, 0, 0, 0, iStyle, mygetcanvasline) == MNG_NOERROR) && - (mng_putchunk_iend(hMNG) == MNG_NOERROR) && - (mng_putchunk_mend(hMNG) == MNG_NOERROR) && - (mng_write(hMNG) == MNG_NOERROR) - ) - return true; - return false; -} - -int QMngHandlerPrivate::currentImageNumber() const -{ -// return mng_get_currentframe(hMNG) % imageCount(); not implemented, apparently - return frameIndex; -} - -int QMngHandlerPrivate::imageCount() const -{ -// return mng_get_totalframes(hMNG); not implemented, apparently - if (haveReadAll) - return frameCount; - return 0; // Don't know -} - -bool QMngHandlerPrivate::jumpToImage(int imageNumber) -{ - if (imageNumber == nextIndex) - return true; - - if ((imageNumber == 0) && haveReadAll && (nextIndex == frameCount)) { - // Loop! - nextIndex = 0; - return true; - } - if (mng_display_freeze(hMNG) == MNG_NOERROR) { - if (mng_display_goframe(hMNG, imageNumber) == MNG_NOERROR) { - nextIndex = imageNumber; - return true; - } - } - return false; -} - -bool QMngHandlerPrivate::jumpToNextImage() -{ - return jumpToImage((currentImageNumber()+1) % imageCount()); -} - -int QMngHandlerPrivate::nextImageDelay() const -{ - return nextDelay; -} - -bool QMngHandlerPrivate::setBackgroundColor(const QColor &color) -{ - mng_uint16 iRed = (mng_uint16)(color.red() << 8); - mng_uint16 iBlue = (mng_uint16)(color.blue() << 8); - mng_uint16 iGreen = (mng_uint16)(color.green() << 8); - return (mng_set_bgcolor(hMNG, iRed, iBlue, iGreen) == MNG_NOERROR); -} - -QColor QMngHandlerPrivate::backgroundColor() const -{ - mng_uint16 iRed; - mng_uint16 iBlue; - mng_uint16 iGreen; - if (mng_get_bgcolor(hMNG, &iRed, &iBlue, &iGreen) == MNG_NOERROR) - return QColor((iRed >> 8) & 0xFF, (iGreen >> 8) & 0xFF, (iBlue >> 8) & 0xFF); - return QColor(); -} - -QMngHandler::QMngHandler() - : d_ptr(new QMngHandlerPrivate(this)) -{ -} - -QMngHandler::~QMngHandler() -{ -} - -/*! \reimp */ -bool QMngHandler::canRead() const -{ - Q_D(const QMngHandler); - if (!d->haveReadNone) - return (!d->haveReadAll || (d->haveReadAll && (d->nextIndex < d->frameCount))); - - if (canRead(device())) { - setFormat("mng"); - return true; - } - return false; -} - -/*! \internal */ -bool QMngHandler::canRead(QIODevice *device) -{ - if (!device) { - qWarning("QMngHandler::canRead() called with no device"); - return false; - } - - return device->peek(8) == "\x8A\x4D\x4E\x47\x0D\x0A\x1A\x0A"; -} - -/*! \reimp */ -QByteArray QMngHandler::name() const -{ - return "mng"; -} - -/*! \reimp */ -bool QMngHandler::read(QImage *image) -{ - Q_D(QMngHandler); - return canRead() ? d->getNextImage(image) : false; -} - -/*! \reimp */ -bool QMngHandler::write(const QImage &image) -{ - Q_D(QMngHandler); - return d->writeImage(image); -} - -/*! \reimp */ -int QMngHandler::currentImageNumber() const -{ - Q_D(const QMngHandler); - return d->currentImageNumber(); -} - -/*! \reimp */ -int QMngHandler::imageCount() const -{ - Q_D(const QMngHandler); - return d->imageCount(); -} - -/*! \reimp */ -bool QMngHandler::jumpToImage(int imageNumber) -{ - Q_D(QMngHandler); - return d->jumpToImage(imageNumber); -} - -/*! \reimp */ -bool QMngHandler::jumpToNextImage() -{ - Q_D(QMngHandler); - return d->jumpToNextImage(); -} - -/*! \reimp */ -int QMngHandler::loopCount() const -{ - Q_D(const QMngHandler); - if (d->iterCount == 0x7FFFFFFF) - return -1; // infinite loop - return d->iterCount-1; -} - -/*! \reimp */ -int QMngHandler::nextImageDelay() const -{ - Q_D(const QMngHandler); - return d->nextImageDelay(); -} - -/*! \reimp */ -QVariant QMngHandler::option(ImageOption option) const -{ - Q_D(const QMngHandler); - if (option == QImageIOHandler::Animation) - return true; - else if (option == QImageIOHandler::BackgroundColor) - return d->backgroundColor(); - return QVariant(); -} - -/*! \reimp */ -void QMngHandler::setOption(ImageOption option, const QVariant & value) -{ - Q_D(QMngHandler); - if (option == QImageIOHandler::BackgroundColor) - d->setBackgroundColor(qVariantValue<QColor>(value)); -} - -/*! \reimp */ -bool QMngHandler::supportsOption(ImageOption option) const -{ - if (option == QImageIOHandler::Animation) - return true; - else if (option == QImageIOHandler::BackgroundColor) - return true; - return false; -} - -QT_END_NAMESPACE diff --git a/src/plugins/imageformats/svg/main.cpp b/src/plugins/imageformats/svg/main.cpp index dbbd3b7..329e9d4 100644 --- a/src/plugins/imageformats/svg/main.cpp +++ b/src/plugins/imageformats/svg/main.cpp @@ -62,26 +62,18 @@ public: QStringList QSvgPlugin::keys() const { - return QStringList() << QLatin1String("svg"); + return QStringList() << QLatin1String("svg") << QLatin1String("svgz"); } QImageIOPlugin::Capabilities QSvgPlugin::capabilities(QIODevice *device, const QByteArray &format) const { - //### canRead disabled for now because it's hard to detect - // whether the file is actually svg without parsing it - //if (device->isReadable() && QSvgIOHandler::canRead(device)) - - if (format == "svg") + if (format == "svg" || format == "svgz") return Capabilities(CanRead); - else - return 0; - - - if (!device->isOpen()) + if (!format.isEmpty()) return 0; Capabilities cap; - if (device->isReadable()) + if (device->isReadable() && QSvgIOHandler::canRead(device)) cap |= CanRead; return cap; } diff --git a/src/plugins/imageformats/svg/qsvgiohandler.cpp b/src/plugins/imageformats/svg/qsvgiohandler.cpp index f3670c6..7b8463d 100644 --- a/src/plugins/imageformats/svg/qsvgiohandler.cpp +++ b/src/plugins/imageformats/svg/qsvgiohandler.cpp @@ -48,6 +48,7 @@ #include "qpixmap.h" #include "qpainter.h" #include "qvariant.h" +#include "qbuffer.h" #include "qdebug.h" QT_BEGIN_NAMESPACE @@ -55,67 +56,58 @@ QT_BEGIN_NAMESPACE class QSvgIOHandlerPrivate { public: - QSvgIOHandlerPrivate() - : r(new QSvgRenderer()), loaded(false) + QSvgIOHandlerPrivate(QSvgIOHandler *qq) + : q(qq), loaded(false), readDone(false), backColor(Qt::transparent) {} - ~QSvgIOHandlerPrivate() - { - delete r; - } bool load(QIODevice *device); - static bool findSvgTag(QIODevice *device); - QSvgRenderer *r; - QSize defaultSize; - QSize currentSize; - bool loaded; + QSvgIOHandler *q; + QSvgRenderer r; + QXmlStreamReader xmlReader; + QSize defaultSize; + QRect clipRect; + QSize scaledSize; + QRect scaledClipRect; + bool loaded; + bool readDone; + QColor backColor; }; + bool QSvgIOHandlerPrivate::load(QIODevice *device) { if (loaded) return true; + if (q->format().isEmpty()) + q->canRead(); + + // # The SVG renderer doesn't handle trailing, unrelated data, so we must + // assume that all available data in the device is to be read. + bool res = false; + QBuffer *buf = qobject_cast<QBuffer *>(device); + if (buf) { + const QByteArray &ba = buf->data(); + res = r.load(QByteArray::fromRawData(ba.constData() + buf->pos(), ba.size() - buf->pos())); + buf->seek(ba.size()); + } else if (q->format() == "svgz") { + res = r.load(device->readAll()); + } else { + xmlReader.setDevice(device); + res = r.load(&xmlReader); + } - if (r->load(device->readAll())) { - defaultSize = QSize(r->viewBox().width(), r->viewBox().height()); - if (currentSize.isEmpty()) - currentSize = defaultSize; + if (res) { + defaultSize = QSize(r.viewBox().width(), r.viewBox().height()); + loaded = true; } - loaded = r->isValid(); return loaded; } -bool QSvgIOHandlerPrivate::findSvgTag(QIODevice *device) -{ - qint64 pos = device->pos(); - device->seek(0); - char buffer[256]; - const char svg_tag[] = "<svg"; - - while (1) { - int size = device->read(buffer, 256); - for (int i=0; i<size - 5; ++i) { - if (!memcmp(buffer + i, svg_tag, 4)) { - if (buffer[i+4] == ' ' || buffer[i+4] == '\t' - || buffer[i+4] == '\n' || buffer[i+4] == '\r') - { - device->seek(pos); - return true; - } - } - } - if (device->atEnd()) - break; - device->seek(device->pos()-4); - } - device->seek(pos); - return false; -} QSvgIOHandler::QSvgIOHandler() - : d(new QSvgIOHandlerPrivate()) + : d(new QSvgIOHandlerPrivate(this)) { } @@ -129,7 +121,20 @@ QSvgIOHandler::~QSvgIOHandler() bool QSvgIOHandler::canRead() const { - return QSvgIOHandlerPrivate::findSvgTag(device()); + if (!device()) + return false; + if (d->loaded && !d->readDone) + return true; // Will happen if we have been asked for the size + + QByteArray buf = device()->peek(8); + if (buf.startsWith("\x1f\x8b")) { + setFormat("svgz"); + return true; + } else if (buf.contains("<?xml") || buf.contains("<svg")) { + setFormat("svg"); + return true; + } + return false; } @@ -141,14 +146,41 @@ QByteArray QSvgIOHandler::name() const bool QSvgIOHandler::read(QImage *image) { - if (d->load(device())) { - *image = QImage(d->currentSize, QImage::Format_ARGB32_Premultiplied); - if (!d->currentSize.isEmpty()) { - image->fill(0x00000000); + if (!d->readDone && d->load(device())) { + bool xform = (d->clipRect.isValid() || d->scaledSize.isValid() || d->scaledClipRect.isValid()); + QSize finalSize = d->defaultSize; + QRectF bounds; + if (xform && !d->defaultSize.isEmpty()) { + bounds = QRectF(QPointF(0,0), QSizeF(d->defaultSize)); + QPoint tr1, tr2; + QSizeF sc(1, 1); + if (d->clipRect.isValid()) { + tr1 = -d->clipRect.topLeft(); + finalSize = d->clipRect.size(); + } + if (d->scaledSize.isValid()) { + sc = QSizeF(qreal(d->scaledSize.width()) / finalSize.width(), + qreal(d->scaledSize.height()) / finalSize.height()); + finalSize = d->scaledSize; + } + if (d->scaledClipRect.isValid()) { + tr2 = -d->scaledClipRect.topLeft(); + finalSize = d->scaledClipRect.size(); + } + QTransform t; + t.translate(tr2.x(), tr2.y()); + t.scale(sc.width(), sc.height()); + t.translate(tr1.x(), tr1.y()); + bounds = t.mapRect(bounds); + } + *image = QImage(finalSize, QImage::Format_ARGB32_Premultiplied); + if (!finalSize.isEmpty()) { + image->fill(d->backColor.rgba()); QPainter p(image); - d->r->render(&p); + d->r.render(&p, bounds); p.end(); } + d->readDone = true; return true; } @@ -166,8 +198,17 @@ QVariant QSvgIOHandler::option(ImageOption option) const d->load(device()); return d->defaultSize; break; + case ClipRect: + return d->clipRect; + break; case ScaledSize: - return d->currentSize; + return d->scaledSize; + break; + case ScaledClipRect: + return d->scaledClipRect; + break; + case BackgroundColor: + return d->backColor; break; default: break; @@ -179,12 +220,17 @@ QVariant QSvgIOHandler::option(ImageOption option) const void QSvgIOHandler::setOption(ImageOption option, const QVariant & value) { switch(option) { - case Size: - d->defaultSize = value.toSize(); - d->currentSize = value.toSize(); + case ClipRect: + d->clipRect = value.toRect(); break; case ScaledSize: - d->currentSize = value.toSize(); + d->scaledSize = value.toSize(); + break; + case ScaledClipRect: + d->scaledClipRect = value.toRect(); + break; + case BackgroundColor: + d->backColor = value.value<QColor>(); break; default: break; @@ -198,7 +244,10 @@ bool QSvgIOHandler::supportsOption(ImageOption option) const { case ImageFormat: case Size: + case ClipRect: case ScaledSize: + case ScaledClipRect: + case BackgroundColor: return true; default: break; @@ -206,9 +255,11 @@ bool QSvgIOHandler::supportsOption(ImageOption option) const return false; } + bool QSvgIOHandler::canRead(QIODevice *device) { - return QSvgIOHandlerPrivate::findSvgTag(device); + QByteArray buf = device->peek(8); + return buf.startsWith("\x1f\x8b") || buf.contains("<?xml") || buf.contains("<svg"); } QT_END_NAMESPACE diff --git a/src/plugins/imageformats/tiff/main.cpp b/src/plugins/imageformats/tiff/main.cpp index fbcbd72..c022abe 100644 --- a/src/plugins/imageformats/tiff/main.cpp +++ b/src/plugins/imageformats/tiff/main.cpp @@ -47,7 +47,7 @@ #ifdef QT_NO_IMAGEFORMAT_TIFF #undef QT_NO_IMAGEFORMAT_TIFF #endif -#include "qtiffhandler.h" +#include <qtiffhandler_p.h> QT_BEGIN_NAMESPACE diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp deleted file mode 100644 index 31e0c92..0000000 --- a/src/plugins/imageformats/tiff/qtiffhandler.cpp +++ /dev/null @@ -1,661 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 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$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, 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. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtiffhandler.h" -#include <qvariant.h> -#include <qdebug.h> -#include <qimage.h> -#include <qglobal.h> -extern "C" { -#include "tiffio.h" -} - -QT_BEGIN_NAMESPACE - -tsize_t qtiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) -{ - QIODevice* device = static_cast<QTiffHandler*>(fd)->device(); - return device->isReadable() ? device->read(static_cast<char *>(buf), size) : -1; -} - -tsize_t qtiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) -{ - return static_cast<QTiffHandler*>(fd)->device()->write(static_cast<char *>(buf), size); -} - -toff_t qtiffSeekProc(thandle_t fd, toff_t off, int whence) -{ - QIODevice *device = static_cast<QTiffHandler*>(fd)->device(); - switch (whence) { - case SEEK_SET: - device->seek(off); - break; - case SEEK_CUR: - device->seek(device->pos() + off); - break; - case SEEK_END: - device->seek(device->size() + off); - break; - } - - return device->pos(); -} - -int qtiffCloseProc(thandle_t /*fd*/) -{ - return 0; -} - -toff_t qtiffSizeProc(thandle_t fd) -{ - return static_cast<QTiffHandler*>(fd)->device()->size(); -} - -int qtiffMapProc(thandle_t /*fd*/, tdata_t* /*pbase*/, toff_t* /*psize*/) -{ - return 0; -} - -void qtiffUnmapProc(thandle_t /*fd*/, tdata_t /*base*/, toff_t /*size*/) -{ -} - -// for 32 bits images -inline void rotate_right_mirror_horizontal(QImage *const image)// rotate right->mirrored horizontal -{ - const int height = image->height(); - const int width = image->width(); - QImage generated(/* width = */ height, /* height = */ width, image->format()); - const uint32 *originalPixel = reinterpret_cast<const uint32*>(image->bits()); - uint32 *const generatedPixels = reinterpret_cast<uint32*>(generated.bits()); - for (int row=0; row < height; ++row) { - for (int col=0; col < width; ++col) { - int idx = col * height + row; - generatedPixels[idx] = *originalPixel; - ++originalPixel; - } - } - *image = generated; -} - -inline void rotate_right_mirror_vertical(QImage *const image) // rotate right->mirrored vertical -{ - const int height = image->height(); - const int width = image->width(); - QImage generated(/* width = */ height, /* height = */ width, image->format()); - const int lastCol = width - 1; - const int lastRow = height - 1; - const uint32 *pixel = reinterpret_cast<const uint32*>(image->bits()); - uint32 *const generatedBits = reinterpret_cast<uint32*>(generated.bits()); - for (int row=0; row < height; ++row) { - for (int col=0; col < width; ++col) { - int idx = (lastCol - col) * height + (lastRow - row); - generatedBits[idx] = *pixel; - ++pixel; - } - } - *image = generated; -} - -QTiffHandler::QTiffHandler() : QImageIOHandler() -{ - compression = NoCompression; -} - -bool QTiffHandler::canRead() const -{ - if (canRead(device())) { - setFormat("tiff"); - return true; - } - return false; -} - -bool QTiffHandler::canRead(QIODevice *device) -{ - if (!device) { - qWarning("QTiffHandler::canRead() called with no device"); - return false; - } - - // current implementation uses TIFFClientOpen which needs to be - // able to seek, so sequential devices are not supported - QByteArray header = device->peek(4); - return header == QByteArray::fromRawData("\x49\x49\x2A\x00", 4) - || header == QByteArray::fromRawData("\x4D\x4D\x00\x2A", 4); -} - -bool QTiffHandler::read(QImage *image) -{ - if (!canRead()) - return false; - - TIFF *const tiff = TIFFClientOpen("foo", - "r", - this, - qtiffReadProc, - qtiffWriteProc, - qtiffSeekProc, - qtiffCloseProc, - qtiffSizeProc, - qtiffMapProc, - qtiffUnmapProc); - - if (!tiff) { - return false; - } - uint32 width; - uint32 height; - uint16 photometric; - if (!TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width) - || !TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height) - || !TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric)) { - TIFFClose(tiff); - return false; - } - - // BitsPerSample defaults to 1 according to the TIFF spec. - uint16 bitPerSample; - if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample)) - bitPerSample = 1; - - bool grayscale = photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE; - if (grayscale && bitPerSample == 1) { - if (image->size() != QSize(width, height) || image->format() != QImage::Format_Mono) - *image = QImage(width, height, QImage::Format_Mono); - QVector<QRgb> colortable(2); - if (photometric == PHOTOMETRIC_MINISBLACK) { - colortable[0] = 0xff000000; - colortable[1] = 0xffffffff; - } else { - colortable[0] = 0xffffffff; - colortable[1] = 0xff000000; - } - image->setColorTable(colortable); - - if (!image->isNull()) { - for (uint32 y=0; y<height; ++y) { - if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) { - TIFFClose(tiff); - return false; - } - } - } - } else { - if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8) { - if (image->size() != QSize(width, height) || image->format() != QImage::Format_Indexed8) - *image = QImage(width, height, QImage::Format_Indexed8); - if (!image->isNull()) { - const uint16 tableSize = 256; - QVector<QRgb> qtColorTable(tableSize); - if (grayscale) { - for (int i = 0; i<tableSize; ++i) { - const int c = (photometric == PHOTOMETRIC_MINISBLACK) ? i : (255 - i); - qtColorTable[i] = qRgb(c, c, c); - } - } else { - // create the color table - uint16 *redTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); - uint16 *greenTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); - uint16 *blueTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); - if (!redTable || !greenTable || !blueTable) { - TIFFClose(tiff); - return false; - } - if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { - TIFFClose(tiff); - return false; - } - - for (int i = 0; i<tableSize ;++i) { - const int red = redTable[i] / 257; - const int green = greenTable[i] / 257; - const int blue = blueTable[i] / 257; - qtColorTable[i] = qRgb(red, green, blue); - } - } - - image->setColorTable(qtColorTable); - for (uint32 y=0; y<height; ++y) { - if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) { - TIFFClose(tiff); - return false; - } - } - - // free redTable, greenTable and greenTable done by libtiff - } - } else { - if (image->size() != QSize(width, height) || image->format() != QImage::Format_ARGB32) - *image = QImage(width, height, QImage::Format_ARGB32); - if (!image->isNull()) { - const int stopOnError = 1; - if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), ORIENTATION_TOPLEFT, stopOnError)) { - for (uint32 y=0; y<height; ++y) - convert32BitOrder(image->scanLine(y), width); - } else { - TIFFClose(tiff); - return false; - } - } - } - } - - if (image->isNull()) { - TIFFClose(tiff); - return false; - } - - float resX = 0; - float resY = 0; - uint16 resUnit = RESUNIT_NONE; - if (TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resUnit) - && TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &resX) - && TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &resY)) { - - switch(resUnit) { - case RESUNIT_CENTIMETER: - image->setDotsPerMeterX(qRound(resX * 100)); - image->setDotsPerMeterY(qRound(resY * 100)); - break; - case RESUNIT_INCH: - image->setDotsPerMeterX(qRound(resX * (100 / 2.54))); - image->setDotsPerMeterY(qRound(resY * (100 / 2.54))); - break; - default: - // do nothing as defaults have already - // been set within the QImage class - break; - } - } - - // rotate the image if the orientation is defined in the file - uint16 orientationTag; - if (TIFFGetField(tiff, TIFFTAG_ORIENTATION, &orientationTag)) { - if (image->format() == QImage::Format_ARGB32) { - // TIFFReadRGBAImageOriented() flip the image but does not rotate them - switch (orientationTag) { - case 5: - rotate_right_mirror_horizontal(image); - break; - case 6: - rotate_right_mirror_vertical(image); - break; - case 7: - rotate_right_mirror_horizontal(image); - break; - case 8: - rotate_right_mirror_vertical(image); - break; - } - } else { - switch (orientationTag) { - case 1: // default orientation - break; - case 2: // mirror horizontal - *image = image->mirrored(true, false); - break; - case 3: // mirror both - *image = image->mirrored(true, true); - break; - case 4: // mirror vertical - *image = image->mirrored(false, true); - break; - case 5: // rotate right mirror horizontal - { - QMatrix transformation; - transformation.rotate(90); - *image = image->transformed(transformation); - *image = image->mirrored(true, false); - break; - } - case 6: // rotate right - { - QMatrix transformation; - transformation.rotate(90); - *image = image->transformed(transformation); - break; - } - case 7: // rotate right, mirror vertical - { - QMatrix transformation; - transformation.rotate(90); - *image = image->transformed(transformation); - *image = image->mirrored(false, true); - break; - } - case 8: // rotate left - { - QMatrix transformation; - transformation.rotate(270); - *image = image->transformed(transformation); - break; - } - } - } - } - - - TIFFClose(tiff); - return true; -} - -static bool checkGrayscale(const QVector<QRgb> &colorTable) -{ - if (colorTable.size() != 256) - return false; - - const bool increasing = (colorTable.at(0) == 0xff000000); - for (int i = 0; i < 256; ++i) { - if (increasing && colorTable.at(i) != qRgb(i, i, i) - || !increasing && colorTable.at(i) != qRgb(255 - i, 255 - i, 255 - i)) - return false; - } - return true; -} - -bool QTiffHandler::write(const QImage &image) -{ - if (!device()->isWritable()) - return false; - - TIFF *const tiff = TIFFClientOpen("foo", - "w", - this, - qtiffReadProc, - qtiffWriteProc, - qtiffSeekProc, - qtiffCloseProc, - qtiffSizeProc, - qtiffMapProc, - qtiffUnmapProc); - if (!tiff) - return false; - - const int width = image.width(); - const int height = image.height(); - - if (!TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width) - || !TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height) - || !TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) { - TIFFClose(tiff); - return false; - } - - // set the resolution - bool resolutionSet = false; - const int dotPerMeterX = image.dotsPerMeterX(); - const int dotPerMeterY = image.dotsPerMeterY(); - if ((dotPerMeterX % 100) == 0 - && (dotPerMeterY % 100) == 0) { - resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_CENTIMETER) - && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, dotPerMeterX/100.0) - && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, dotPerMeterY/100.0); - } else { - resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH) - && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, static_cast<float>(image.logicalDpiX())) - && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, static_cast<float>(image.logicalDpiY())); - } - if (!resolutionSet) { - TIFFClose(tiff); - return false; - } - - // configure image depth - const QImage::Format format = image.format(); - if (format == QImage::Format_Mono || format == QImage::Format_MonoLSB) { - uint16 photometric = PHOTOMETRIC_MINISBLACK; - if (image.colorTable().at(0) == 0xffffffff) - photometric = PHOTOMETRIC_MINISWHITE; - if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric) - || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_CCITTRLE) - || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 1)) { - TIFFClose(tiff); - return false; - } - - // try to do the conversion in chunks no greater than 16 MB - int chunks = (width * height / (1024 * 1024 * 16)) + 1; - int chunkHeight = qMax(height / chunks, 1); - - int y = 0; - while (y < height) { - QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)).convertToFormat(QImage::Format_Mono); - - int chunkStart = y; - int chunkEnd = y + chunk.height(); - while (y < chunkEnd) { - if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) { - TIFFClose(tiff); - return false; - } - ++y; - } - } - TIFFClose(tiff); - } else if (format == QImage::Format_Indexed8) { - const QVector<QRgb> colorTable = image.colorTable(); - bool isGrayscale = checkGrayscale(colorTable); - if (isGrayscale) { - uint16 photometric = PHOTOMETRIC_MINISBLACK; - if (image.colorTable().at(0) == 0xffffffff) - photometric = PHOTOMETRIC_MINISWHITE; - if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric) - || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS) - || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { - TIFFClose(tiff); - return false; - } - } else { - if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE) - || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS) - || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { - TIFFClose(tiff); - return false; - } - //// write the color table - // allocate the color tables - uint16 *redTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); - uint16 *greenTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); - uint16 *blueTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); - if (!redTable || !greenTable || !blueTable) { - TIFFClose(tiff); - return false; - } - - // set the color table - const int tableSize = colorTable.size(); - Q_ASSERT(tableSize <= 256); - for (int i = 0; i<tableSize; ++i) { - const QRgb color = colorTable.at(i); - redTable[i] = qRed(color) * 257; - greenTable[i] = qGreen(color) * 257; - blueTable[i] = qBlue(color) * 257; - } - - const bool setColorTableSuccess = TIFFSetField(tiff, TIFFTAG_COLORMAP, redTable, greenTable, blueTable); - - qFree(redTable); - qFree(greenTable); - qFree(blueTable); - - if (!setColorTableSuccess) { - TIFFClose(tiff); - return false; - } - } - - //// write the data - // try to do the conversion in chunks no greater than 16 MB - int chunks = (width * height/ (1024 * 1024 * 16)) + 1; - int chunkHeight = qMax(height / chunks, 1); - - int y = 0; - while (y < height) { - QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)); - - int chunkStart = y; - int chunkEnd = y + chunk.height(); - while (y < chunkEnd) { - if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) { - TIFFClose(tiff); - return false; - } - ++y; - } - } - TIFFClose(tiff); - - } else { - if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB) - || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW) - || !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 4) - || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { - TIFFClose(tiff); - return false; - } - // try to do the ARGB32 conversion in chunks no greater than 16 MB - int chunks = (width * height * 4 / (1024 * 1024 * 16)) + 1; - int chunkHeight = qMax(height / chunks, 1); - - int y = 0; - while (y < height) { - QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)).convertToFormat(QImage::Format_ARGB32); - - int chunkStart = y; - int chunkEnd = y + chunk.height(); - while (y < chunkEnd) { - if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) - convert32BitOrder(chunk.scanLine(y - chunkStart), width); - else - convert32BitOrderBigEndian(chunk.scanLine(y - chunkStart), width); - - if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) { - TIFFClose(tiff); - return false; - } - ++y; - } - } - TIFFClose(tiff); - } - - return true; -} - -QByteArray QTiffHandler::name() const -{ - return "tiff"; -} - -QVariant QTiffHandler::option(ImageOption option) const -{ - if (option == Size && canRead()) { - QSize imageSize; - qint64 pos = device()->pos(); - TIFF *tiff = TIFFClientOpen("foo", - "r", - const_cast<QTiffHandler*>(this), - qtiffReadProc, - qtiffWriteProc, - qtiffSeekProc, - qtiffCloseProc, - qtiffSizeProc, - qtiffMapProc, - qtiffUnmapProc); - - if (tiff) { - uint32 width = 0; - uint32 height = 0; - TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width); - TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height); - imageSize = QSize(width, height); - } - device()->seek(pos); - if (imageSize.isValid()) - return imageSize; - } else if (option == CompressionRatio) { - return compression; - } else if (option == ImageFormat) { - return QImage::Format_ARGB32; - } - return QVariant(); -} - -void QTiffHandler::setOption(ImageOption option, const QVariant &value) -{ - if (option == CompressionRatio && value.type() == QVariant::Int) - compression = value.toInt(); -} - -bool QTiffHandler::supportsOption(ImageOption option) const -{ - return option == CompressionRatio - || option == Size - || option == ImageFormat; -} - -void QTiffHandler::convert32BitOrder(void *buffer, int width) -{ - uint32 *target = reinterpret_cast<uint32 *>(buffer); - for (int32 x=0; x<width; ++x) { - uint32 p = target[x]; - // convert between ARGB and ABGR - target[x] = (p & 0xff000000) - | ((p & 0x00ff0000) >> 16) - | (p & 0x0000ff00) - | ((p & 0x000000ff) << 16); - } -} - -void QTiffHandler::convert32BitOrderBigEndian(void *buffer, int width) -{ - uint32 *target = reinterpret_cast<uint32 *>(buffer); - for (int32 x=0; x<width; ++x) { - uint32 p = target[x]; - target[x] = (p & 0xff000000) >> 24 - | (p & 0x00ff0000) << 8 - | (p & 0x0000ff00) << 8 - | (p & 0x000000ff) << 8; - } -} - -QT_END_NAMESPACE diff --git a/src/plugins/imageformats/tiff/tiff.pro b/src/plugins/imageformats/tiff/tiff.pro index 312f99c..e781526 100644 --- a/src/plugins/imageformats/tiff/tiff.pro +++ b/src/plugins/imageformats/tiff/tiff.pro @@ -3,70 +3,8 @@ include(../../qpluginbase.pri) QTDIR_build:REQUIRES = "!contains(QT_CONFIG, no-tiff)" -HEADERS += qtiffhandler.h -SOURCES += main.cpp \ - qtiffhandler.cpp - -contains(QT_CONFIG, system-tiff) { - unix:LIBS += -ltiff - win32:LIBS += libtiff.lib -} -!contains(QT_CONFIG, system-tiff) { - INCLUDEPATH += ../../../3rdparty/libtiff/libtiff - SOURCES += \ - ../../../3rdparty/libtiff/libtiff/tif_aux.c \ - ../../../3rdparty/libtiff/libtiff/tif_close.c \ - ../../../3rdparty/libtiff/libtiff/tif_codec.c \ - ../../../3rdparty/libtiff/libtiff/tif_color.c \ - ../../../3rdparty/libtiff/libtiff/tif_compress.c \ - ../../../3rdparty/libtiff/libtiff/tif_dir.c \ - ../../../3rdparty/libtiff/libtiff/tif_dirinfo.c \ - ../../../3rdparty/libtiff/libtiff/tif_dirread.c \ - ../../../3rdparty/libtiff/libtiff/tif_dirwrite.c \ - ../../../3rdparty/libtiff/libtiff/tif_dumpmode.c \ - ../../../3rdparty/libtiff/libtiff/tif_error.c \ - ../../../3rdparty/libtiff/libtiff/tif_extension.c \ - ../../../3rdparty/libtiff/libtiff/tif_fax3.c \ - ../../../3rdparty/libtiff/libtiff/tif_fax3sm.c \ - ../../../3rdparty/libtiff/libtiff/tif_flush.c \ - ../../../3rdparty/libtiff/libtiff/tif_getimage.c \ - ../../../3rdparty/libtiff/libtiff/tif_luv.c \ - ../../../3rdparty/libtiff/libtiff/tif_lzw.c \ - ../../../3rdparty/libtiff/libtiff/tif_next.c \ - ../../../3rdparty/libtiff/libtiff/tif_open.c \ - ../../../3rdparty/libtiff/libtiff/tif_packbits.c \ - ../../../3rdparty/libtiff/libtiff/tif_pixarlog.c \ - ../../../3rdparty/libtiff/libtiff/tif_predict.c \ - ../../../3rdparty/libtiff/libtiff/tif_print.c \ - ../../../3rdparty/libtiff/libtiff/tif_read.c \ - ../../../3rdparty/libtiff/libtiff/tif_strip.c \ - ../../../3rdparty/libtiff/libtiff/tif_swab.c \ - ../../../3rdparty/libtiff/libtiff/tif_thunder.c \ - ../../../3rdparty/libtiff/libtiff/tif_tile.c \ - ../../../3rdparty/libtiff/libtiff/tif_version.c \ - ../../../3rdparty/libtiff/libtiff/tif_warning.c \ - ../../../3rdparty/libtiff/libtiff/tif_write.c \ - ../../../3rdparty/libtiff/libtiff/tif_zip.c - win32 { - SOURCES += ../../../3rdparty/libtiff/libtiff/tif_win32.c - } - unix: { - SOURCES += ../../../3rdparty/libtiff/libtiff/tif_unix.c - } - wince*: { - SOURCES += ../../../corelib/kernel/qfunctions_wince.cpp - } - symbian*: { - SOURCES += ../../../3rdparty/libtiff/port/lfind.c - } -} - -contains(QT_CONFIG, system-zlib) { - LIBS += -lz -} -!contains(QT_CONFIG, system-zlib) { - INCLUDEPATH += ../../../3rdparty/zlib -} +include(../../../gui/image/qtiffhandler.pri) +SOURCES += main.cpp QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats diff --git a/src/plugins/phonon/ds9/ds9.pro b/src/plugins/phonon/ds9/ds9.pro index 786338a..301808e 100644 --- a/src/plugins/phonon/ds9/ds9.pro +++ b/src/plugins/phonon/ds9/ds9.pro @@ -22,7 +22,6 @@ HEADERS += \ $$PHONON_DS9_DIR/mediaobject.h \ $$PHONON_DS9_DIR/videowidget.h \ $$PHONON_DS9_DIR/videorenderer_soft.h \ - $$PHONON_DS9_DIR/videorenderer_vmr9.h \ $$PHONON_DS9_DIR/volumeeffect.h \ $$PHONON_DS9_DIR/qbasefilter.h \ $$PHONON_DS9_DIR/qpin.h \ @@ -45,7 +44,6 @@ SOURCES += \ $$PHONON_DS9_DIR/mediaobject.cpp \ $$PHONON_DS9_DIR/videowidget.cpp \ $$PHONON_DS9_DIR/videorenderer_soft.cpp \ - $$PHONON_DS9_DIR/videorenderer_vmr9.cpp \ $$PHONON_DS9_DIR/volumeeffect.cpp \ $$PHONON_DS9_DIR/qbasefilter.cpp \ $$PHONON_DS9_DIR/qpin.cpp \ @@ -53,6 +51,14 @@ SOURCES += \ $$PHONON_DS9_DIR/qaudiocdreader.cpp \ $$PHONON_DS9_DIR/qmeminputpin.cpp +#the EVR renderer (only available on desktop) +!wince*:SOURCES += $$PHONON_DS9_DIR/videorenderer_evr.cpp \ + $$PHONON_DS9_DIR/videorenderer_vmr9.cpp +!wince*:HEADERS += $$PHONON_DS9_DIR/qevr9.h \ + $$PHONON_DS9_DIR/videorenderer_evr.h \ + $$PHONON_DS9_DIR/videorenderer_vmr9.h +wince*:SOURCES += $$PHONON_DS9_DIR/videorenderer_default.cpp +wince*:HEADERS += $$PHONON_DS9_DIR/videorenderer_default.h target.path = $$[QT_INSTALL_PLUGINS]/phonon_backend INSTALLS += target diff --git a/src/plugins/phonon/gstreamer/gstreamer.pro b/src/plugins/phonon/gstreamer/gstreamer.pro index ae597fa..1013205 100644 --- a/src/plugins/phonon/gstreamer/gstreamer.pro +++ b/src/plugins/phonon/gstreamer/gstreamer.pro @@ -15,6 +15,7 @@ PHONON_GSTREAMER_DIR = $$QT_SOURCE_TREE/src/3rdparty/phonon/gstreamer HEADERS += $$PHONON_GSTREAMER_DIR/common.h \ $$PHONON_GSTREAMER_DIR/audiooutput.h \ + $$PHONON_GSTREAMER_DIR/audiodataoutput.h \ $$PHONON_GSTREAMER_DIR/artssink.h \ $$PHONON_GSTREAMER_DIR/abstractrenderer.h \ $$PHONON_GSTREAMER_DIR/backend.h \ @@ -35,26 +36,27 @@ HEADERS += $$PHONON_GSTREAMER_DIR/common.h \ $$PHONON_GSTREAMER_DIR/audioeffect.h \ $$PHONON_GSTREAMER_DIR/volumefadereffect.h -SOURCES += $$PHONON_GSTREAMER_DIR/audiooutput.cpp \ - $$PHONON_GSTREAMER_DIR/abstractrenderer.cpp \ +SOURCES += $$PHONON_GSTREAMER_DIR/abstractrenderer.cpp \ $$PHONON_GSTREAMER_DIR/artssink.cpp \ + $$PHONON_GSTREAMER_DIR/audioeffect.cpp \ + $$PHONON_GSTREAMER_DIR/audiooutput.cpp \ + $$PHONON_GSTREAMER_DIR/audiodataoutput.cpp \ $$PHONON_GSTREAMER_DIR/backend.cpp \ $$PHONON_GSTREAMER_DIR/devicemanager.cpp \ $$PHONON_GSTREAMER_DIR/effect.cpp \ $$PHONON_GSTREAMER_DIR/effectmanager.cpp \ + $$PHONON_GSTREAMER_DIR/glrenderer.cpp \ $$PHONON_GSTREAMER_DIR/gsthelper.cpp \ - $$PHONON_GSTREAMER_DIR/mediaobject.cpp \ $$PHONON_GSTREAMER_DIR/medianode.cpp \ $$PHONON_GSTREAMER_DIR/medianodeevent.cpp \ - $$PHONON_GSTREAMER_DIR/widgetrenderer.cpp \ - $$PHONON_GSTREAMER_DIR/videowidget.cpp \ - $$PHONON_GSTREAMER_DIR/glrenderer.cpp \ - $$PHONON_GSTREAMER_DIR/qwidgetvideosink.cpp \ + $$PHONON_GSTREAMER_DIR/mediaobject.cpp \ + $$PHONON_GSTREAMER_DIR/message.cpp \ $$PHONON_GSTREAMER_DIR/phononsrc.cpp \ + $$PHONON_GSTREAMER_DIR/qwidgetvideosink.cpp \ $$PHONON_GSTREAMER_DIR/streamreader.cpp \ - $$PHONON_GSTREAMER_DIR/message.cpp \ - $$PHONON_GSTREAMER_DIR/audioeffect.cpp \ - $$PHONON_GSTREAMER_DIR/volumefadereffect.cpp + $$PHONON_GSTREAMER_DIR/videowidget.cpp \ + $$PHONON_GSTREAMER_DIR/volumefadereffect.cpp \ + $$PHONON_GSTREAMER_DIR/widgetrenderer.cpp !embedded { HEADERS += $$PHONON_GSTREAMER_DIR/x11renderer.h diff --git a/src/plugins/phonon/mmf/mmf.pro b/src/plugins/phonon/mmf/mmf.pro index ac11188..691fc80 100644 --- a/src/plugins/phonon/mmf/mmf.pro +++ b/src/plugins/phonon/mmf/mmf.pro @@ -18,7 +18,7 @@ symbian { # This is necessary because both epoc32/include and Phonon contain videoplayer.h. # By making /epoc32/include the first SYSTEMINCLUDE, we ensure that # '#include <videoplayer.h>' picks up the Symbian header, as intended. - PREPEND_INCLUDEPATH = /epoc32/include + PREPEND_INCLUDEPATH = $${EPOCROOT}epoc32/include PREPEND_INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 004b816..722979d 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -1,14 +1,18 @@ TEMPLATE = subdirs -SUBDIRS *= accessible imageformats sqldrivers iconengines script +SUBDIRS *= sqldrivers script bearer unix:!symbian { contains(QT_CONFIG,iconv)|contains(QT_CONFIG,gnu-libiconv):SUBDIRS *= codecs } else { SUBDIRS *= codecs } +!contains(QT_CONFIG, no-gui): SUBDIRS *= imageformats iconengines !embedded:SUBDIRS *= graphicssystems embedded:SUBDIRS *= gfxdrivers decorations mousedrivers kbddrivers !win32:!embedded:!mac:!symbian:SUBDIRS *= inputmethods +!symbian:!contains(QT_CONFIG, no-gui):SUBDIRS += accessible symbian:SUBDIRS += s60 contains(QT_CONFIG, phonon): SUBDIRS *= phonon contains(QT_CONFIG, multimedia): SUBDIRS *= audio + + diff --git a/src/plugins/qpluginbase.pri b/src/plugins/qpluginbase.pri index 7eecf03..7cbffe0 100644 --- a/src/plugins/qpluginbase.pri +++ b/src/plugins/qpluginbase.pri @@ -1,6 +1,6 @@ TEMPLATE = lib isEmpty(QT_MAJOR_VERSION) { - VERSION=4.6.4 + VERSION=4.7.2 } else { VERSION=$${QT_MAJOR_VERSION}.$${QT_MINOR_VERSION}.$${QT_PATCH_VERSION} } diff --git a/src/plugins/s60/3_2/3_2.pro b/src/plugins/s60/3_2/3_2.pro index 9424c7c..0524866 100644 --- a/src/plugins/s60/3_2/3_2.pro +++ b/src/plugins/s60/3_2/3_2.pro @@ -10,7 +10,12 @@ contains(S60_VERSION, 3.1) { SOURCES += ../src/qlocale_3_2.cpp \ ../src/qdesktopservices_3_2.cpp \ ../src/qcoreapplication_3_2.cpp - LIBS += -lDirectoryLocalizer -lefsrv + contains(CONFIG, is_using_gnupoc) { + LIBS += -ldirectorylocalizer + } else { + LIBS += -lDirectoryLocalizer + } + LIBS += -lefsrv INCLUDEPATH += $$APP_LAYER_SYSTEMINCLUDE } diff --git a/src/plugins/s60/5_0/5_0.pro b/src/plugins/s60/5_0/5_0.pro index c787ab3..00aea1b 100644 --- a/src/plugins/s60/5_0/5_0.pro +++ b/src/plugins/s60/5_0/5_0.pro @@ -10,7 +10,12 @@ contains(S60_VERSION, 3.1) { SOURCES += ../src/qlocale_3_2.cpp \ ../src/qdesktopservices_3_2.cpp \ ../src/qcoreapplication_3_2.cpp - LIBS += -lDirectoryLocalizer -lefsrv + contains(CONFIG, is_using_gnupoc) { + LIBS += -ldirectorylocalizer + } else { + LIBS += -lDirectoryLocalizer + } + LIBS += -lefsrv INCLUDEPATH += $$APP_LAYER_SYSTEMINCLUDE } diff --git a/src/plugins/s60/feedback/feedback.pro b/src/plugins/s60/feedback/feedback.pro new file mode 100644 index 0000000..1069220 --- /dev/null +++ b/src/plugins/s60/feedback/feedback.pro @@ -0,0 +1,18 @@ +include(../../qpluginbase.pri) + +TARGET = qtactilefeedback$${QT_LIBINFIX} + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/s60/feedback + +INCLUDEPATH += $$APP_LAYER_SYSTEMINCLUDE + +contains(S60_VERSION, 5.0)|contains(S60_VERSION, symbian3) { + HEADERS += qtactileFeedback.h + SOURCES += qtactileFeedback_s60.cpp + + LIBS += -ltouchfeedback +} + +load(data_caging_paths) + +TARGET.UID3=0x200315B4 diff --git a/src/plugins/s60/feedback/qtactileFeedback.h b/src/plugins/s60/feedback/qtactileFeedback.h new file mode 100644 index 0000000..7c4cc29 --- /dev/null +++ b/src/plugins/s60/feedback/qtactileFeedback.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QEvent> +#include <QWidget> + +#include "private/qs60style_feedbackinterface_p.h" + +class QTactileFeedback : public TactileFeedbackInterface +{ + Q_OBJECT + Q_INTERFACES(TactileFeedbackInterface) + + public: + void touchFeedback(QEvent *event, const QWidget *widget); + }; diff --git a/src/plugins/s60/feedback/qtactileFeedback_s60.cpp b/src/plugins/s60/feedback/qtactileFeedback_s60.cpp new file mode 100644 index 0000000..c2f1d34 --- /dev/null +++ b/src/plugins/s60/feedback/qtactileFeedback_s60.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QApplication> +#include <QObject> +#include <QSlider> +#include <QScrollBar> + +#include <QtCore/qplugin.h> +#include "qtactileFeedback.h" + +#include <touchfeedback.h> + +void QTactileFeedback::touchFeedback(QEvent *event, const QWidget *widget) +{ + //Lets share the global instance for touch feedback (you are NOT allowed to try and delete it!). + MTouchFeedback* feedback = MTouchFeedback::Instance(); + + //If the widget itself is not handling focus, try to use focusProxy widget. + const QWidget *w = ((widget->focusPolicy() == Qt::NoFocus) && (widget->focusProxy())) ? widget->focusProxy() : widget; + + //Only give tactile feedback for enabled widgets that take focus. + if (feedback && w && w->isEnabled() && w->isWidgetType() && w->isVisible()) { + //Scrollbars are 'special' that they don't take focus (nor they have focusProxy), yet we'd like to have tactile feedback for them + if (w->focusPolicy() == Qt::NoFocus) + if (!qobject_cast<const QScrollBar *>(w)) + return; + + //Don't give tactile feedback for widgets that are outside topmost dialog. + QWidget *dialog = QApplication::activeModalWidget(); + if (dialog) { + QList<const QWidget *> allChildren = dialog->findChildren<const QWidget *>(); + if (!allChildren.contains(w)) + return; + } + + //Widget specific tactile feedback. + if (qobject_cast<const QSlider *>(w) || qobject_cast<const QScrollBar *>(w)) + feedback->InstantFeedback(ETouchFeedbackSensitive); + else + feedback->InstantFeedback(ETouchFeedbackBasic); + } +} + +Q_EXPORT_PLUGIN2("feedback", QTactileFeedback); diff --git a/src/plugins/s60/s60.pro b/src/plugins/s60/s60.pro index 8ae639c..ffcd170 100644 --- a/src/plugins/s60/s60.pro +++ b/src/plugins/s60/s60.pro @@ -1,3 +1,15 @@ TEMPLATE = subdirs -symbian:SUBDIRS = 3_1 3_2 5_0 + +symbian { + contains(S60_VERSION, 3.1)|contains(S60_VERSION, 3.2)|contains(S60_VERSION, 5.0) { + SUBDIRS += 3_1 3_2 + } + + contains(S60_VERSION, 5.0)|contains(S60_VERSION, symbian3) { + SUBDIRS += feedback + } + + # 5.0 is used also for Symbian3 and later + SUBDIRS += 5_0 +}
\ No newline at end of file diff --git a/src/plugins/s60/s60pluginbase.pri b/src/plugins/s60/s60pluginbase.pri index c1aa4ef..4e15102 100644 --- a/src/plugins/s60/s60pluginbase.pri +++ b/src/plugins/s60/s60pluginbase.pri @@ -4,13 +4,20 @@ include(../qpluginbase.pri) CONFIG -= plugin +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/s60 + MMP_RULES += NOEXPORTLIBRARY -defBlock = \ - "$${LITERAL_HASH}ifdef WINSCW" \ - "DEFFILE ../bwins/qts60plugin.def" \ - "$${LITERAL_HASH}else" \ - "DEFFILE ../eabi/qts60plugin.def" \ - "$${LITERAL_HASH}endif" +symbian-abld|symbian-sbsv2 { + defBlock = \ + "$${LITERAL_HASH}ifdef WINSCW" \ + "DEFFILE ../bwins/qts60plugin.def" \ + "$${LITERAL_HASH}else" \ + "DEFFILE ../eabi/qts60plugin.def" \ + "$${LITERAL_HASH}endif" +} else { + CONFIG *= def_files + DEF_FILE = ../eabi/qts60pluginu.def +} MMP_RULES += defBlock
\ No newline at end of file diff --git a/src/plugins/script/qtdbus/main.cpp b/src/plugins/script/qtdbus/main.cpp index 6f09326..452f0e9 100644 --- a/src/plugins/script/qtdbus/main.cpp +++ b/src/plugins/script/qtdbus/main.cpp @@ -44,6 +44,8 @@ #include <QMetaMethod> #include <QScriptExtensionPlugin> +#ifndef QT_NO_DBUS + QT_USE_NAMESPACE static QScriptValue setupDBusInterface(QScriptEngine *engine, QDBusAbstractInterface *iface); @@ -394,3 +396,5 @@ void QtDBusScriptPlugin::initialize(const QString &key, QScriptEngine *engine) Q_EXPORT_STATIC_PLUGIN(QtDBusScriptPlugin) Q_EXPORT_PLUGIN2(qtscriptdbus, QtDBusScriptPlugin) + +#endif // QT_NO_DBUS diff --git a/src/plugins/script/qtdbus/main.h b/src/plugins/script/qtdbus/main.h index 8544247..bc2d8a3 100644 --- a/src/plugins/script/qtdbus/main.h +++ b/src/plugins/script/qtdbus/main.h @@ -46,6 +46,8 @@ #include <QtScript/qscriptable.h> #include <QtScript/qscriptengine.h> +#ifndef QT_NO_DBUS + class QDBusConnectionConstructor : public QObject, public QScriptable { @@ -173,4 +175,5 @@ private: QScriptValue proto; }; +#endif // QT_NO_DBUS #endif // QDBUSBINDING_H diff --git a/src/plugins/sqldrivers/db2/db2.pro b/src/plugins/sqldrivers/db2/db2.pro index 5223beb..e053f37 100644 --- a/src/plugins/sqldrivers/db2/db2.pro +++ b/src/plugins/sqldrivers/db2/db2.pro @@ -1,10 +1,6 @@ -TARGET = qsqldb2 +TARGET = qsqldb2 -HEADERS = ../../../sql/drivers/db2/qsql_db2.h -SOURCES = main.cpp \ - ../../../sql/drivers/db2/qsql_db2.cpp - -unix:!contains( LIBS, .*db2.* ):LIBS *= -ldb2 -win32:!contains( LIBS, .*db2.* ):LIBS *= -ldb2cli +SOURCES = main.cpp +include(../../../sql/drivers/db2/qsql_db2.pri) include(../qsqldriverbase.pri) diff --git a/src/plugins/sqldrivers/ibase/ibase.pro b/src/plugins/sqldrivers/ibase/ibase.pro index ec2bc7b..7870ec8 100644 --- a/src/plugins/sqldrivers/ibase/ibase.pro +++ b/src/plugins/sqldrivers/ibase/ibase.pro @@ -1,14 +1,6 @@ -TARGET = qsqlibase +TARGET = qsqlibase -HEADERS = ../../../sql/drivers/ibase/qsql_ibase.h -SOURCES = main.cpp \ - ../../../sql/drivers/ibase/qsql_ibase.cpp - -unix:!contains( LIBS, .*gds.* ):!contains( LIBS, .*libfb.* ):LIBS *= -lgds - -win32:!contains( LIBS, .*gds.* ):!contains( LIBS, .*fbclient.* ) { - !win32-borland:LIBS *= -lgds32_ms - win32-borland:LIBS += gds32.lib -} +SOURCES = main.cpp +include(../../../sql/drivers/ibase/qsql_ibase.pri) include(../qsqldriverbase.pri) diff --git a/src/plugins/sqldrivers/mysql/mysql.pro b/src/plugins/sqldrivers/mysql/mysql.pro index 9f5c619..b6d42ff 100644 --- a/src/plugins/sqldrivers/mysql/mysql.pro +++ b/src/plugins/sqldrivers/mysql/mysql.pro @@ -1,23 +1,6 @@ -TARGET = qsqlmysql +TARGET = qsqlmysql -HEADERS = ../../../sql/drivers/mysql/qsql_mysql.h -SOURCES = main.cpp \ - ../../../sql/drivers/mysql/qsql_mysql.cpp - -unix: { - isEmpty(QT_LFLAGS_MYSQL) { - !contains(LIBS, .*mysqlclient.*):!contains(LIBS, .*mysqld.*) { - use_libmysqlclient_r:LIBS *= -lmysqlclient_r - else:LIBS *= -lmysqlclient - } - } else { - LIBS *= $$QT_LFLAGS_MYSQL - QMAKE_CXXFLAGS *= $$QT_CFLAGS_MYSQL - } -} - -win32:!contains(LIBS, .*mysql.*):!contains(LIBS, .*mysqld.*) { - LIBS *= -llibmysql -} +SOURCES = main.cpp +include(../../../sql/drivers/mysql/qsql_mysql.pri) include(../qsqldriverbase.pri) diff --git a/src/plugins/sqldrivers/oci/oci.pro b/src/plugins/sqldrivers/oci/oci.pro index 3bf70a1..d7dcce9 100644 --- a/src/plugins/sqldrivers/oci/oci.pro +++ b/src/plugins/sqldrivers/oci/oci.pro @@ -1,13 +1,6 @@ -TARGET = qsqloci +TARGET = qsqloci -HEADERS = ../../../sql/drivers/oci/qsql_oci.h -SOURCES = main.cpp \ - ../../../sql/drivers/oci/qsql_oci.cpp - -win32:LIBS *= -loci - -unix:!contains( LIBS, .*clnts.* ):LIBS *= -lclntsh - -macx:QMAKE_LFLAGS += -Wl,-flat_namespace,-U,_environ +SOURCES = main.cpp +include(../../../sql/drivers/oci/qsql_oci.pri) include(../qsqldriverbase.pri) diff --git a/src/plugins/sqldrivers/odbc/odbc.pro b/src/plugins/sqldrivers/odbc/odbc.pro index 2bf85f1..677eb6e 100644 --- a/src/plugins/sqldrivers/odbc/odbc.pro +++ b/src/plugins/sqldrivers/odbc/odbc.pro @@ -1,19 +1,6 @@ -TARGET = qsqlodbc +TARGET = qsqlodbc -HEADERS = ../../../sql/drivers/odbc/qsql_odbc.h -SOURCES = main.cpp \ - ../../../sql/drivers/odbc/qsql_odbc.cpp - -unix { - !contains( LIBS, .*odbc.* ) { - LIBS *= $$QT_LFLAGS_ODBC - } - DEFINES += UNICODE -} - -win32 { - !win32-borland:LIBS *= -lodbc32 - win32-borland:LIBS *= $(BCB)/lib/PSDK/odbc32.lib -} +SOURCES = main.cpp +include(../../../sql/drivers/odbc/qsql_odbc.pri) include(../qsqldriverbase.pri) diff --git a/src/plugins/sqldrivers/psql/psql.pro b/src/plugins/sqldrivers/psql/psql.pro index 29fbada..8276c0a 100644 --- a/src/plugins/sqldrivers/psql/psql.pro +++ b/src/plugins/sqldrivers/psql/psql.pro @@ -1,21 +1,6 @@ -TARGET = qsqlpsql +TARGET = qsqlpsql -HEADERS = ../../../sql/drivers/psql/qsql_psql.h -SOURCES = main.cpp \ - ../../../sql/drivers/psql/qsql_psql.cpp - -unix: { - !isEmpty(QT_LFLAGS_PSQL) { - LIBS *= $$QT_LFLAGS_PSQL - QMAKE_CXXFLAGS *= $$QT_CFLAGS_PSQL - } - !contains(LIBS, .*pq.*):LIBS *= -lpq -} - -win32:!contains(LIBS, .*pq.* ) { - !win32-g++:LIBS *= -llibpq - win32-g++:LIBS *= -lpq - LIBS *= -lws2_32 -ladvapi32 -} +SOURCES = main.cpp +include(../../../sql/drivers/psql/qsql_psql.pri) include(../qsqldriverbase.pri) diff --git a/src/plugins/sqldrivers/sqlite/sqlite.pro b/src/plugins/sqldrivers/sqlite/sqlite.pro index fb31233..f4c1671 100644 --- a/src/plugins/sqldrivers/sqlite/sqlite.pro +++ b/src/plugins/sqldrivers/sqlite/sqlite.pro @@ -1,18 +1,7 @@ -TARGET = qsqlite +TARGET = qsqlite -HEADERS = ../../../sql/drivers/sqlite/qsql_sqlite.h -SOURCES = smain.cpp \ - ../../../sql/drivers/sqlite/qsql_sqlite.cpp - -!system-sqlite:!contains( LIBS, .*sqlite.* ) { - CONFIG(release, debug|release):DEFINES *= NDEBUG - DEFINES += SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_COMPLETE - INCLUDEPATH += ../../../3rdparty/sqlite - SOURCES += ../../../3rdparty/sqlite/sqlite3.c -} else { - LIBS *= $$QT_LFLAGS_SQLITE - QMAKE_CXXFLAGS *= $$QT_CFLAGS_SQLITE -} +SOURCES = smain.cpp +include(../../../sql/drivers/sqlite/qsql_sqlite.pri) wince*: DEFINES += HAVE_LOCALTIME_S=0 diff --git a/src/plugins/sqldrivers/sqlite2/sqlite2.pro b/src/plugins/sqldrivers/sqlite2/sqlite2.pro index 88db22a..e6197b9 100644 --- a/src/plugins/sqldrivers/sqlite2/sqlite2.pro +++ b/src/plugins/sqldrivers/sqlite2/sqlite2.pro @@ -1,9 +1,6 @@ -TARGET = qsqlite2 +TARGET = qsqlite2 -HEADERS = ../../../sql/drivers/sqlite2/qsql_sqlite2.h -SOURCES = smain.cpp \ - ../../../sql/drivers/sqlite2/qsql_sqlite2.cpp - -!contains(LIBS, .*sqlite.*):LIBS *= -lsqlite +SOURCES = smain.cpp +include(../../../sql/drivers/sqlite2/qsql_sqlite2.pri) include(../qsqldriverbase.pri) diff --git a/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pri b/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pri new file mode 100644 index 0000000..494c64c --- /dev/null +++ b/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pri @@ -0,0 +1,40 @@ +# We just want to include the sqlite3 binaries for Symbian for platforms that do not have them. +!symbian-abld:!symbian-sbsv2 { + !symbian_no_export_sqlite:!exists($${EPOCROOT}epoc32/release/armv5/lib/sqlite3.dso) { + symbian_sqlite3_zip_file = $$PWD/SQLite3_v9.2.zip + + # The QMAKE_COPY section is to update timestamp on the file. + symbian_sqlite3_header.input = symbian_sqlite3_zip_file + symbian_sqlite3_header.output = sqlite3.h + !isEmpty(MOC_DIR):symbian_sqlite3_header.output = $$MOC_DIR/$$symbian_sqlite3_header.output + symbian_sqlite3_header.CONFIG = combine no_link + symbian_sqlite3_header.dependency_type = TYPE_C + symbian_sqlite3_header.commands = $$QMAKE_UNZIP -j ${QMAKE_FILE_NAME} epoc32/include/stdapis/${QMAKE_FILE_OUT_BASE}.h \ + && $$QMAKE_COPY ${QMAKE_FILE_OUT_BASE}.h ${QMAKE_FILE_OUT}.tmp \ + && $$QMAKE_DEL_FILE ${QMAKE_FILE_OUT_BASE}.h \ + && $$QMAKE_MOVE ${QMAKE_FILE_OUT}.tmp ${QMAKE_FILE_OUT} + silent:symbian_sqlite3_header.commands = @echo unzipping $@ && $$symbian_sqlite3_header.commands + QMAKE_EXTRA_COMPILERS += symbian_sqlite3_header + + # The QMAKE_COPY section is to update timestamp on the file. + symbian_sqlite3_dso.input = symbian_sqlite3_zip_file + symbian_sqlite3_dso.output = sqlite3.dso + !isEmpty(OBJECTS_DIR):symbian_sqlite3_dso.output = $$OBJECTS_DIR/$$symbian_sqlite3_dso.output + symbian_sqlite3_dso.CONFIG = combine no_link target_predeps + symbian_sqlite3_dso.commands = $$QMAKE_UNZIP -j ${QMAKE_FILE_NAME} epoc32/release/armv5/lib/${QMAKE_FILE_OUT_BASE}.dso \ + && $$QMAKE_COPY ${QMAKE_FILE_OUT_BASE}.dso ${QMAKE_FILE_OUT}.tmp \ + && $$QMAKE_DEL_FILE ${QMAKE_FILE_OUT_BASE}.dso \ + && $$QMAKE_MOVE ${QMAKE_FILE_OUT}.tmp ${QMAKE_FILE_OUT} + silent:symbian_sqlite3_dso.commands = @echo unzipping $@ && $$symbian_sqlite3_dso.commands + QMAKE_EXTRA_COMPILERS += symbian_sqlite3_dso + + symbian_sqlite3_ver_dso.input = symbian_sqlite3_zip_file + symbian_sqlite3_ver_dso.output = sqlite3{00060003}.dso + !isEmpty(OBJECTS_DIR):symbian_sqlite3_ver_dso.output = $$OBJECTS_DIR/$$symbian_sqlite3_ver_dso.output + symbian_sqlite3_ver_dso.CONFIG = $$symbian_sqlite3_dso.CONFIG + symbian_sqlite3_ver_dso.commands = $$symbian_sqlite3_dso.commands + QMAKE_EXTRA_COMPILERS += symbian_sqlite3_ver_dso + + QMAKE_LIBDIR *= $$OBJECTS_DIR + } +} diff --git a/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pro b/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pro index 691cce1..0d233e6 100644 --- a/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pro +++ b/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pro @@ -2,7 +2,7 @@ TEMPLATE = subdirs # We just want to export the sqlite3 binaries for Symbian for platforms that do not have them. -symbian { +symbian-abld|symbian-sbsv2 { !symbian_no_export_sqlite:!exists($${EPOCROOT}epoc32/release/armv5/lib/sqlite3.dso) { BLD_INF_RULES.prj_exports += ":zip SQLite3_v9.2.zip" } diff --git a/src/plugins/sqldrivers/tds/tds.pro b/src/plugins/sqldrivers/tds/tds.pro index 08a166b..b8e8ded 100644 --- a/src/plugins/sqldrivers/tds/tds.pro +++ b/src/plugins/sqldrivers/tds/tds.pro @@ -1,15 +1,6 @@ -TARGET = qsqltds +TARGET = qsqltds -HEADERS = ../../../sql/drivers/tds/qsql_tds.h - -SOURCES = main.cpp \ - ../../../sql/drivers/tds/qsql_tds.cpp - -unix:!contains( LIBS, .*sybdb.* ):LIBS *= -lsybdb - -win32 { - !win32-borland:LIBS *= -lNTWDBLIB - win32-borland:LIBS *= $(BCB)/lib/PSDK/NTWDBLIB.LIB -} +SOURCES = main.cpp +include(../../../sql/drivers/tds/qsql_tds.pri) include(../qsqldriverbase.pri) |