Index: runtime/kioslave/network/ioslave/networkuri.h =================================================================== --- runtime/kioslave/network/ioslave/networkuri.h (revision 1079783) +++ runtime/kioslave/network/ioslave/networkuri.h (revision 1079784) @@ -40,7 +40,7 @@ explicit NetworkUri( const KUrl& url ); public: - const QString& hostName() const; + const QString& hostAddress() const; const QString& serviceName() const; const QString& serviceType() const; NetworkUri::Type type() const; @@ -48,7 +48,7 @@ private: private: // data - QString mHostName; + QString mHostAddress; QString mServiceName; QString mServiceType; }; @@ -56,28 +56,28 @@ inline NetworkUri::NetworkUri( const KUrl& url ) { - mHostName = url.path().mid( 1 ); - const int slashIndex = mHostName.indexOf( '/' ); + mHostAddress = url.path().mid( 1 ); + const int slashIndex = mHostAddress.indexOf( '/' ); if( slashIndex != -1 ) { // servicetype is currently appended as .type to the name - const int serviceTypeIndex = mHostName.lastIndexOf( '.' ) + 1; - mServiceType = mHostName.mid( serviceTypeIndex ); + const int serviceTypeIndex = mHostAddress.lastIndexOf( '.' ) + 1; + mServiceType = mHostAddress.mid( serviceTypeIndex ); const int serviceNameLength = (serviceTypeIndex-1) - (slashIndex+1); - mServiceName = mHostName.mid( slashIndex + 1, serviceNameLength ); - mHostName.resize( slashIndex ); + mServiceName = mHostAddress.mid( slashIndex + 1, serviceNameLength ); + mHostAddress.resize( slashIndex ); } } -inline const QString& NetworkUri::hostName() const { return mHostName; } +inline const QString& NetworkUri::hostAddress() const { return mHostAddress; } inline const QString& NetworkUri::serviceName() const { return mServiceName; } inline const QString& NetworkUri::serviceType() const { return mServiceType; } inline NetworkUri::Type NetworkUri::type() const { Type result = - mHostName.isEmpty() ? Domain : + mHostAddress.isEmpty() ? Domain : mServiceName.isEmpty() ? Device : /*else*/ Service; @@ -87,7 +87,7 @@ /* inline QDataStream& operator<<( QDataStream& stream, const NetworkUri& networkUri ) { - stream << "NetworkUri(host:"<<networkUri.mHostName + stream << "NetworkUri(host:"<<networkUri.mHostAddress << ",service:"<<networkUri.mServiceName << ",type:"<<static_cast<int>(networkUri.type())<<")"; return stream; Index: runtime/kioslave/network/ioslave/networkslave.cpp =================================================================== --- runtime/kioslave/network/ioslave/networkslave.cpp (revision 1079783) +++ runtime/kioslave/network/ioslave/networkslave.cpp (revision 1079784) @@ -52,13 +52,13 @@ bool successfulGetting = false; const NetworkUri::Type type = networkUri.type(); -kDebug()<<"type="<<networkUri.type()<<"host="<<networkUri.hostName()<<"service="<<networkUri.serviceName()<<"stype="<<networkUri.serviceType(); +kDebug()<<"type="<<networkUri.type()<<"host="<<networkUri.hostAddress()<<"service="<<networkUri.serviceName()<<"stype="<<networkUri.serviceType(); if( type == NetworkUri::Service ) { - const QString hostName = networkUri.hostName(); + const QString hostAddress = networkUri.hostAddress(); const QString serviceName = networkUri.serviceName(); const QString serviceType = networkUri.serviceType(); - QDBusReply<Mollet::NetService> reply = mNetworkDBusProxy->serviceData( hostName, serviceName, serviceType ); + QDBusReply<Mollet::NetService> reply = mNetworkDBusProxy->serviceData( hostAddress, serviceName, serviceType ); kDebug()<<reply.isValid(); if( reply.isValid() ) // TODO: find how a not found service can be expressed in the reply @@ -84,7 +84,7 @@ bool successfulMimetyping = false; NetworkUri::Type type = networkUri.type(); -kDebug()<<"type="<<networkUri.type()<<"host="<<networkUri.hostName()<<"service="<<networkUri.serviceName()<<"stype="<<networkUri.serviceType(); +kDebug()<<"type="<<networkUri.type()<<"host="<<networkUri.hostAddress()<<"service="<<networkUri.serviceName()<<"stype="<<networkUri.serviceType(); if( type == NetworkUri::Domain ) { @@ -94,10 +94,10 @@ } else { - const QString hostName = networkUri.hostName(); + const QString hostAddress = networkUri.hostAddress(); if( type == NetworkUri::Device ) { - QDBusReply<Mollet::NetDevice> reply = mNetworkDBusProxy->deviceData( hostName ); + QDBusReply<Mollet::NetDevice> reply = mNetworkDBusProxy->deviceData( hostAddress ); kDebug()<<reply.isValid(); if( reply.isValid() ) // TODO: find how a not found service can be expressed in the reply @@ -113,7 +113,7 @@ { const QString serviceName = networkUri.serviceName(); const QString serviceType = networkUri.serviceType(); - QDBusReply<Mollet::NetService> reply = mNetworkDBusProxy->serviceData( hostName, serviceName, serviceType ); + QDBusReply<Mollet::NetService> reply = mNetworkDBusProxy->serviceData( hostAddress, serviceName, serviceType ); kDebug()<<reply.isValid(); if( reply.isValid() ) // TODO: find how a not found service can be expressed in the reply @@ -142,7 +142,7 @@ bool successfulStating = false; NetworkUri::Type type = networkUri.type(); -kDebug()<<"type="<<networkUri.type()<<"host="<<networkUri.hostName()<<"service="<<networkUri.serviceName()<<"stype="<<networkUri.serviceType(); +kDebug()<<"type="<<networkUri.type()<<"host="<<networkUri.hostAddress()<<"service="<<networkUri.serviceName()<<"stype="<<networkUri.serviceType(); if( type == NetworkUri::Domain ) { @@ -154,10 +154,10 @@ } else { - const QString hostName = networkUri.hostName(); + const QString hostAddress = networkUri.hostAddress(); if( type == NetworkUri::Device ) { - QDBusReply<Mollet::NetDevice> reply = mNetworkDBusProxy->deviceData( hostName ); + QDBusReply<Mollet::NetDevice> reply = mNetworkDBusProxy->deviceData( hostAddress ); kDebug()<<reply.isValid(); if( reply.isValid() ) // TODO: find how a not found service can be expressed in the reply @@ -175,7 +175,7 @@ { const QString serviceName = networkUri.serviceName(); const QString serviceType = networkUri.serviceType(); - QDBusReply<Mollet::NetService> reply = mNetworkDBusProxy->serviceData( hostName, serviceName, serviceType ); + QDBusReply<Mollet::NetService> reply = mNetworkDBusProxy->serviceData( hostAddress, serviceName, serviceType ); kDebug()<<reply.isValid(); if( reply.isValid() ) // TODO: find how a not found service can be expressed in the reply @@ -205,7 +205,7 @@ bool successfulListing = false; NetworkUri::Type networkUriType = networkUri.type(); -kDebug()<<"type="<<networkUri.type()<<"host="<<networkUri.hostName()<<"service="<<networkUri.serviceName()<<"stype="<<networkUri.serviceType(); +kDebug()<<"type="<<networkUri.type()<<"host="<<networkUri.hostAddress()<<"service="<<networkUri.serviceName()<<"stype="<<networkUri.serviceType(); if( networkUriType != NetworkUri::InvalidUrl ) { @@ -232,10 +232,10 @@ } else { - const QString hostName = networkUri.hostName(); + const QString hostAddress = networkUri.hostAddress(); if( networkUriType == NetworkUri::Device ) { - QDBusReply<Mollet::NetServiceList> reply = mNetworkDBusProxy->serviceDataList( hostName ); + QDBusReply<Mollet::NetServiceList> reply = mNetworkDBusProxy->serviceDataList( hostAddress ); kDebug()<<reply.isValid(); if( reply.isValid() ) // TODO: find how a not found service can be expressed in the reply @@ -258,7 +258,7 @@ { const QString serviceName = networkUri.serviceName(); const QString serviceType = networkUri.serviceType(); - QDBusReply<Mollet::NetService> reply = mNetworkDBusProxy->serviceData( hostName, serviceName, serviceType ); + QDBusReply<Mollet::NetService> reply = mNetworkDBusProxy->serviceData( hostAddress, serviceName, serviceType ); kDebug()<<reply.isValid(); if( reply.isValid() ) // TODO: find how a not found service can be expressed in the reply @@ -291,7 +291,7 @@ void NetworkSlave::feedEntryAsDevice( KIO::UDSEntry* entry, const Mollet::NetDevice& deviceData ) { - entry->insert( KIO::UDSEntry::UDS_NAME, deviceData.hostName() ); + entry->insert( KIO::UDSEntry::UDS_NAME, deviceData.hostAddress() ); entry->insert( KIO::UDSEntry::UDS_DISPLAY_NAME, deviceData.name() ); entry->insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR ); // entry->insert( KIO::UDSEntry::UDS_ICON_NAME, NetDevice::iconName(deviceData.type()) ); Index: runtime/kioslave/network/ioslave/networkdbusinterface.h =================================================================== --- runtime/kioslave/network/ioslave/networkdbusinterface.h (revision 1079783) +++ runtime/kioslave/network/ioslave/networkdbusinterface.h (revision 1079784) @@ -41,33 +41,33 @@ virtual ~NetworkDBusInterface(); public Q_SLOTS: - QDBusReply<Mollet::NetDevice> deviceData( const QString& hostName ); - QDBusReply<Mollet::NetService> serviceData( const QString& hostName, const QString& serviceName, const QString& serviceType ); + QDBusReply<Mollet::NetDevice> deviceData( const QString& hostAddress ); + QDBusReply<Mollet::NetService> serviceData( const QString& hostAddress, const QString& serviceName, const QString& serviceType ); QDBusReply<Mollet::NetDeviceList> deviceDataList(); - QDBusReply<Mollet::NetServiceList> serviceDataList( const QString& hostName ); + QDBusReply<Mollet::NetServiceList> serviceDataList( const QString& hostAddress ); }; // TODO: is QDBus::Block the right solution here? -inline QDBusReply<Mollet::NetDevice> NetworkDBusInterface::deviceData( const QString& hostName ) +inline QDBusReply<Mollet::NetDevice> NetworkDBusInterface::deviceData( const QString& hostAddress ) { QList<QVariant> argumentList; - argumentList << qVariantFromValue(hostName); + argumentList << qVariantFromValue(hostAddress); return callWithArgumentList( QDBus::Block, QString::fromLatin1("deviceData"), argumentList ); } -inline QDBusReply<Mollet::NetService> NetworkDBusInterface::serviceData( const QString& hostName, const QString& serviceName, const QString& serviceType ) +inline QDBusReply<Mollet::NetService> NetworkDBusInterface::serviceData( const QString& hostAddress, const QString& serviceName, const QString& serviceType ) { QList<QVariant> argumentList; - argumentList << qVariantFromValue(hostName) << qVariantFromValue(serviceName) << qVariantFromValue(serviceType); + argumentList << qVariantFromValue(hostAddress) << qVariantFromValue(serviceName) << qVariantFromValue(serviceType); return callWithArgumentList( QDBus::Block, QString::fromLatin1("serviceData"), argumentList ); } inline QDBusReply<Mollet::NetDeviceList> NetworkDBusInterface::deviceDataList() { return call( QString::fromLatin1("deviceDataList") ); } -inline QDBusReply<Mollet::NetServiceList> NetworkDBusInterface::serviceDataList( const QString& hostName ) +inline QDBusReply<Mollet::NetServiceList> NetworkDBusInterface::serviceDataList( const QString& hostAddress ) { QList<QVariant> argumentList; - argumentList << qVariantFromValue(hostName); + argumentList << qVariantFromValue(hostAddress); return callWithArgumentList( QDBus::Block, QString::fromLatin1("serviceDataList"), argumentList ); } Index: runtime/kioslave/network/kded/networkdbusadaptor.cpp =================================================================== --- runtime/kioslave/network/kded/networkdbusadaptor.cpp (revision 1079783) +++ runtime/kioslave/network/kded/networkdbusadaptor.cpp (revision 1079784) @@ -43,21 +43,21 @@ qDBusRegisterMetaType<Mollet::NetServiceList>(); } -NetDevice NetworkDBusAdaptor::deviceData( const QString& hostName ) +NetDevice NetworkDBusAdaptor::deviceData( const QString& hostAddress ) { - return parent()->deviceData( hostName ); + return parent()->deviceData( hostAddress ); } -NetService NetworkDBusAdaptor::serviceData( const QString& hostName, const QString& serviceName, const QString& serviceType ) +NetService NetworkDBusAdaptor::serviceData( const QString& hostAddress, const QString& serviceName, const QString& serviceType ) { - return parent()->serviceData( hostName, serviceName, serviceType ); + return parent()->serviceData( hostAddress, serviceName, serviceType ); } NetDeviceList NetworkDBusAdaptor::deviceDataList() { return parent()->deviceDataList(); } -NetServiceList NetworkDBusAdaptor::serviceDataList( const QString& hostName ) +NetServiceList NetworkDBusAdaptor::serviceDataList( const QString& hostAddress ) { - return parent()->serviceDataList( hostName ); + return parent()->serviceDataList( hostAddress ); } NetworkDBusAdaptor::~NetworkDBusAdaptor() Index: runtime/kioslave/network/kded/networkdbusadaptor.h =================================================================== --- runtime/kioslave/network/kded/networkdbusadaptor.h (revision 1079783) +++ runtime/kioslave/network/kded/networkdbusadaptor.h (revision 1079784) @@ -49,10 +49,10 @@ NetworkWatcher* parent() const; public Q_SLOTS: - Mollet::NetDevice deviceData( const QString& hostName ); - Mollet::NetService serviceData( const QString& hostName, const QString& serviceName, const QString& serviceType ); + Mollet::NetDevice deviceData( const QString& hostAddress ); + Mollet::NetService serviceData( const QString& hostAddress, const QString& serviceName, const QString& serviceType ); Mollet::NetDeviceList deviceDataList(); - Mollet::NetServiceList serviceDataList( const QString& hostName ); + Mollet::NetServiceList serviceDataList( const QString& hostAddress ); }; Index: runtime/kioslave/network/kded/networkwatcher.cpp =================================================================== --- runtime/kioslave/network/kded/networkwatcher.cpp (revision 1079783) +++ runtime/kioslave/network/kded/networkwatcher.cpp (revision 1079784) @@ -46,14 +46,14 @@ } // TODO: instead use networkuri and return QVariant for all these -NetDevice NetworkWatcher::deviceData( const QString& hostName ) +NetDevice NetworkWatcher::deviceData( const QString& hostAddress ) { NetDevice result; const QList<NetDevice> deviceList = mNetwork->deviceList(); foreach( const NetDevice& device, deviceList ) { - if( device.hostName() == hostName ) + if( device.hostAddress() == hostAddress ) { result = device; break; @@ -63,14 +63,14 @@ return result; } -NetService NetworkWatcher::serviceData( const QString& hostName, const QString& serviceName, const QString& serviceType ) +NetService NetworkWatcher::serviceData( const QString& hostAddress, const QString& serviceName, const QString& serviceType ) { NetService result; const QList<NetDevice> deviceList = mNetwork->deviceList(); foreach( const NetDevice& device, deviceList ) { - if( device.hostName() == hostName ) + if( device.hostAddress() == hostAddress ) { const QList<NetService> serviceList = device.serviceList(); @@ -94,14 +94,14 @@ return mNetwork->deviceList(); } -NetServiceList NetworkWatcher::serviceDataList( const QString& hostName ) +NetServiceList NetworkWatcher::serviceDataList( const QString& hostAddress ) { NetServiceList result; const QList<NetDevice> deviceList = mNetwork->deviceList(); foreach( const NetDevice& device, deviceList ) { - if( device.hostName() == hostName ) + if( device.hostAddress() == hostAddress ) { result = device.serviceList(); break; Index: runtime/kioslave/network/kded/networkwatcher.h =================================================================== --- runtime/kioslave/network/kded/networkwatcher.h (revision 1079783) +++ runtime/kioslave/network/kded/networkwatcher.h (revision 1079784) @@ -45,10 +45,10 @@ virtual ~NetworkWatcher(); public: - Mollet::NetDevice deviceData( const QString& hostName ); - Mollet::NetService serviceData( const QString& hostName, const QString& serviceName, const QString& serviceType ); + Mollet::NetDevice deviceData( const QString& hostAddress ); + Mollet::NetService serviceData( const QString& hostAddress, const QString& serviceName, const QString& serviceType ); Mollet::NetDeviceList deviceDataList(); - Mollet::NetServiceList serviceDataList( const QString& hostName ); + Mollet::NetServiceList serviceDataList( const QString& hostAddress ); private: Network* mNetwork; Index: runtime/kioslave/network/kded/kioslavenotifier.cpp =================================================================== --- runtime/kioslave/network/kded/kioslavenotifier.cpp (revision 1079783) +++ runtime/kioslave/network/kded/kioslavenotifier.cpp (revision 1079784) @@ -43,9 +43,9 @@ static inline QString idFrom( const NetworkUri& networkUri ) { - return networkUri.hostName().isEmpty() ? QString() : - networkUri.serviceName().isEmpty() ? networkUri.hostName() : - /*else*/ networkUri.hostName()+'/'+networkUri.serviceName(); + return networkUri.hostAddress().isEmpty() ? QString() : + networkUri.serviceName().isEmpty() ? networkUri.hostAddress() : + /*else*/ networkUri.hostAddress()+'/'+networkUri.serviceName(); } static inline QString dirIdFor( const NetDevice& device ) @@ -55,17 +55,17 @@ } static inline QString pathFor( const NetDevice& device ) { - return device.hostName(); + return device.hostAddress(); } static inline QString dirIdFor( const NetService& service ) { - return service.device().hostName(); + return service.device().hostAddress(); } static inline QString pathFor( const NetService& service ) { - return service.device().hostName() + '/' + service.name()+'.'+service.type(); + return service.device().hostAddress() + '/' + service.name()+'.'+service.type(); } Index: runtime/kioslave/network/network/builder/simpleitemfactory.cpp =================================================================== --- runtime/kioslave/network/network/builder/simpleitemfactory.cpp (revision 1079783) +++ runtime/kioslave/network/network/builder/simpleitemfactory.cpp (revision 1079784) @@ -24,6 +24,8 @@ // lib #include "netservice_p.h" +#include "upnp/service.h" +#include "upnp/device.h" // KDE #include <KUrl> @@ -191,6 +193,28 @@ return result; } +bool SimpleItemFactory::canCreateNetSystemFromUpnp( const UPnP::Device& upnpDevice ) const +{ +Q_UNUSED( upnpDevice ) + return true; +} +// TODO: add KIcon with specialiced KIconLoader (fetches Icons via D-Bus) +NetServicePrivate* SimpleItemFactory::createNetService( const UPnP::Device& upnpDevice, const NetDevice& device ) const +{ + NetServicePrivate* result; + + QString url = upnpDevice.presentationUrl(); + if( url.isEmpty() ) + { + url = QString::fromLatin1( "upnp://" ); + url.append( upnpDevice.udn() ); + } + result = new NetServicePrivate( upnpDevice.displayName(), QString::fromLatin1("unknown"), + "upnp."+upnpDevice.type(), device, url ); + + return result; +} + SimpleItemFactory::~SimpleItemFactory() {} } Index: runtime/kioslave/network/network/builder/upnp/upnpnetworkbuilder.cpp =================================================================== --- runtime/kioslave/network/network/builder/upnp/upnpnetworkbuilder.cpp (revision 0) +++ runtime/kioslave/network/network/builder/upnp/upnpnetworkbuilder.cpp (revision 1079784) @@ -0,0 +1,220 @@ +/* + This file is part of the Mollet network library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "upnpnetworkbuilder.h" + +// lib +#include "upnpnetsystemable.h" +#include "abstractnetsystemfactory.h" +#include "network_p.h" +#include "netdevice_p.h" +#include "netservice_p.h" +// KUPnP +#include <upnp/devicebrowser.h> +#include <upnp/device.h> +// Qt +#include <QtCore/QStringList> + +#include <KDebug> + +namespace Mollet +{ + +UpnpNetworkBuilder::UpnpNetworkBuilder( NetworkPrivate* networkPrivate ) + : AbstractNetworkBuilder() + , mNetworkPrivate( networkPrivate ) + , mDeviceBrowser( 0 ) +{ +kDebug(); +} + +void UpnpNetworkBuilder::registerNetSystemFactory( AbstractNetSystemFactory* netSystemFactory ) +{ + UpnpNetSystemAble* upnpNetSystemAble = qobject_cast<UpnpNetSystemAble*>( netSystemFactory ); + + if( upnpNetSystemAble ) + mNetSystemFactoryList.append( upnpNetSystemAble ); +} + +void UpnpNetworkBuilder::start() +{ + mDeviceBrowser = new UPnP::DeviceBrowser(); + + connect( mDeviceBrowser, SIGNAL(deviceAdded( const UPnP::Device& )), SLOT(onUPnPDeviceAdded( const UPnP::Device& )) ); + connect( mDeviceBrowser, SIGNAL(deviceRemoved( const UPnP::Device& )), SLOT(onUPnPDeviceRemoved( const UPnP::Device& )) ); + + const QList<UPnP::Device> devices = mDeviceBrowser->devices(); + + addUPnPDevices( devices ); + + // TODO: works already here, but is this a good design? + emit initDone(); +} + +void UpnpNetworkBuilder::addUPnPDevices( const QList<UPnP::Device>& upnpDevices ) +{ + QList<NetDevice> addedDevices; + QList<NetService> addedServices; + + QList<NetDevice>& deviceList = mNetworkPrivate->deviceList(); + foreach( const UPnP::Device& upnpDevice, upnpDevices ) + { + if( upnpDevice.hasParentDevice() ) + continue; + + const QString ipAddress = upnpDevice.ipAddress(); + + NetDevicePrivate* d = 0; + const NetDevice* deviceOfService; + foreach( const NetDevice& device, deviceList ) + { + const bool isSameAddress = ( device.ipAddress() == ipAddress ); +kDebug()<<"existing device:"<<device.hostName()<<"at"<<device.ipAddress()<<"vs."<<ipAddress<<":"<<isSameAddress; + // TODO: lookup hostname and try to use that + if( isSameAddress ) + { + d = device.dPtr(); + deviceOfService = &device; + break; + } + } + if( ! d ) + { + const QString displayName = upnpDevice.displayName(); + + const QString deviceName = displayName; + d = new NetDevicePrivate( deviceName ); + d->setIpAddress( ipAddress ); + + NetDevice device( d ); + addedDevices.append( device ); + deviceList.append( device ); + deviceOfService = &deviceList.last(); +kDebug()<<"new device:"<<deviceName<<"at"<<ipAddress; + } + + NetServicePrivate* netServicePrivate = 0; + // do a priority based lookup who can build the object + // TODO: priorisation + foreach( const UpnpNetSystemAble* factory, mNetSystemFactoryList ) + { + if( factory->canCreateNetSystemFromUpnp(upnpDevice) ) + { + // TODO: here we should rather see if this service already exists + netServicePrivate = factory->createNetService( upnpDevice, *deviceOfService ); + break; + } + } + + NetService netService( netServicePrivate ); + d->addService( netService ); + + addedServices.append( netService ); +kDebug()<<"new service:"<<netService.name()<<netService.url(); + + // try guessing the device type by the services on it + // TODO: move into devicefactory + const QString serviceType = upnpDevice.type(); + NetDevice::Type deviceTypeByService = NetDevice::Unknown; + QString deviceName; + if( serviceType == "InternetGatewayDevice1" ) + deviceTypeByService = NetDevice::Router; + + if( deviceTypeByService != NetDevice::Unknown ) + { + if( deviceTypeByService > d->type() ) + { + d->setType( deviceTypeByService ); + if( ! deviceName.isEmpty() ) + d->setName( deviceName ); + } + } + } + + if( ! addedDevices.isEmpty() ) + mNetworkPrivate->emitDevicesAdded( addedDevices ); + if( ! addedServices.isEmpty() ) + mNetworkPrivate->emitServicesAdded( addedServices ); +} + + +void UpnpNetworkBuilder::removeUPnPDevices( const QList<UPnP::Device>& upnpDevices ) +{ + QList<NetDevice> removedDevices; + QList<NetService> removedServices; + + QList<NetDevice>& deviceList = mNetworkPrivate->deviceList(); + foreach( const UPnP::Device& upnpDevice, upnpDevices ) + { + const QString ipAddress = upnpDevice.ipAddress(); + + QMutableListIterator<NetDevice> it( deviceList ); + while( it.hasNext()) + { + const NetDevice& device = it.next(); + if( device.ipAddress() == ipAddress ) + { + NetDevicePrivate* d = device.dPtr(); + NetService netService = d->removeService( upnpDevice.displayName() ); + if( ! netService.isValid() ) + break; + + removedServices.append( netService ); + + // remove device on last service + if( d->serviceList().count() == 0 ) + { + QList<NetDevice> removedDevices; + removedDevices.append( device ); + // remove only after taking copy from reference into removed list + it.remove(); + } + break; + } + } + } + if( ! removedServices.isEmpty() ) + mNetworkPrivate->emitServicesRemoved( removedServices ); + if( ! removedDevices.isEmpty() ) + mNetworkPrivate->emitDevicesRemoved( removedDevices ); +} + + +void UpnpNetworkBuilder::onUPnPDeviceAdded( const UPnP::Device& device ) +{ + QList<UPnP::Device> devices; + devices.append( device ); + addUPnPDevices( devices ); +} + +void UpnpNetworkBuilder::onUPnPDeviceRemoved( const UPnP::Device& device ) +{ + QList<UPnP::Device> devices; + devices.append( device ); + removeUPnPDevices( devices ); +} + +UpnpNetworkBuilder::~UpnpNetworkBuilder() +{ +} + +} Index: runtime/kioslave/network/network/builder/upnp/upnpnetsystemable.h =================================================================== --- runtime/kioslave/network/network/builder/upnp/upnpnetsystemable.h (revision 0) +++ runtime/kioslave/network/network/builder/upnp/upnpnetsystemable.h (revision 1079784) @@ -0,0 +1,58 @@ +/* + This file is part of the Mollet network library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef UPNPNETSYSTEMABLE_H +#define UPNPNETSYSTEMABLE_H + +// Qt +#include <QtCore/QtPlugin> + +namespace UPnP { +class Device; +} +class QString; + + +namespace Mollet +{ +class NetServicePrivate; +class NetDevice; + + +class UpnpNetSystemAble +{ + public: + virtual ~UpnpNetSystemAble(); + + public: // API to be implemented + virtual bool canCreateNetSystemFromUpnp( const UPnP::Device& upnpDevice ) const = 0; + virtual NetServicePrivate* createNetService( const UPnP::Device& upnpDevice, const NetDevice& device ) const = 0; +}; + + +inline UpnpNetSystemAble::~UpnpNetSystemAble() {} + +} + +Q_DECLARE_INTERFACE( Mollet::UpnpNetSystemAble, "org.kde.mollet.upnpnetsystemable/1.0" ) + +#endif Index: runtime/kioslave/network/network/builder/upnp/upnpnetworkbuilder.h =================================================================== --- runtime/kioslave/network/network/builder/upnp/upnpnetworkbuilder.h (revision 0) +++ runtime/kioslave/network/network/builder/upnp/upnpnetworkbuilder.h (revision 1079784) @@ -0,0 +1,73 @@ +/* + This file is part of the Mollet network library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef UPNPNETWORKBUILDER_H +#define UPNPNETWORKBUILDER_H + +// lib +#include <abstractnetworkbuilder.h> +#include <network.h> +#include <netdevice.h> + +namespace UPnP { +class DeviceBrowser; +class Device; +} + + +namespace Mollet +{ +class UpnpNetSystemAble; + + +class UpnpNetworkBuilder : public AbstractNetworkBuilder +{ + Q_OBJECT + + public: + explicit UpnpNetworkBuilder( NetworkPrivate* networkPrivate ); + virtual ~UpnpNetworkBuilder(); + + public: // AbstractNetworkBuilder API + virtual void registerNetSystemFactory( AbstractNetSystemFactory* netSystemFactory ); + virtual void start(); + //TODO: void stop(); ? why needed, what to do? + + protected: + void addUPnPDevices( const QList<UPnP::Device>& devices ); + void removeUPnPDevices( const QList<UPnP::Device>& devices ); + + private Q_SLOTS: + void onUPnPDeviceAdded( const UPnP::Device& device ); + void onUPnPDeviceRemoved( const UPnP::Device& device ); + + private: // data + NetworkPrivate* mNetworkPrivate; + + QList<UpnpNetSystemAble*> mNetSystemFactoryList; + + UPnP::DeviceBrowser* mDeviceBrowser; +}; + +} + +#endif Index: runtime/kioslave/network/network/builder/simpleitemfactory.h =================================================================== --- runtime/kioslave/network/network/builder/simpleitemfactory.h (revision 1079783) +++ runtime/kioslave/network/network/builder/simpleitemfactory.h (revision 1079784) @@ -25,16 +25,22 @@ // lib #include <dnssd/dnssdnetsystemable.h> +#include <upnp/upnpnetsystemable.h> #include <abstractnetsystemfactory.h> namespace Mollet { -class SimpleItemFactory : public AbstractNetSystemFactory, public DNSSDNetSystemAble +class SimpleItemFactory : public AbstractNetSystemFactory, + public DNSSDNetSystemAble, + public UpnpNetSystemAble { - Q_OBJECT - Q_INTERFACES( Mollet::DNSSDNetSystemAble ) + Q_OBJECT + Q_INTERFACES( + Mollet::DNSSDNetSystemAble + Mollet::UpnpNetSystemAble + ) public: SimpleItemFactory(); @@ -44,6 +50,10 @@ virtual bool canCreateNetSystemFromDNSSD( const QString& serviceType ) const; virtual NetServicePrivate* createNetService( const DNSSD::RemoteService::Ptr& service, const NetDevice& device ) const; + public: // UpnpNetSystemAble API + virtual bool canCreateNetSystemFromUpnp( const UPnP::Device& upnpDevice ) const; + virtual NetServicePrivate* createNetService( const UPnP::Device& upnpDevice, const NetDevice& device ) const; + private: }; Index: runtime/kioslave/network/network/builder/dnssd/dnssdnetworkbuilder.cpp =================================================================== --- runtime/kioslave/network/network/builder/dnssd/dnssdnetworkbuilder.cpp (revision 1079783) +++ runtime/kioslave/network/network/builder/dnssd/dnssdnetworkbuilder.cpp (revision 1079784) @@ -28,9 +28,10 @@ #include "network_p.h" #include "netdevice_p.h" // KDE -#include <dnssd/servicetypebrowser.h> +#include <DNSSD/ServiceTypeBrowser> #include <DNSSD/ServiceBrowser> // Qt +#include <QtNetwork/QHostAddress> #include <QtCore/QMutableListIterator> #include <KDebug> @@ -117,14 +118,27 @@ { QList<NetDevice>& deviceList = mNetworkPrivate->deviceList(); - const QString hostName = service->hostName(); + QString hostName = service->hostName(); + // TODO: this blocks. and the ip address should be delivered from DNS-SD with resolve + const QHostAddress hostAddress = DNSSD::ServiceBrowser::resolveHostName( hostName ); + const QString ipAddress = hostAddress.toString(); + // forget domain name if just ip address + if( hostName == ipAddress ) + hostName = QString(); // device TODO: only search for if we can create the service? NetDevicePrivate* d = 0; const NetDevice* deviceOfService; foreach( const NetDevice& device, deviceList ) { - if( device.hostName() == hostName ) + const QString deviceHostName = device.hostName(); + const bool useIpAddress = ( deviceHostName.isEmpty() || hostName.isEmpty() ); + const bool isSameAddress = useIpAddress ? + ( device.ipAddress() == ipAddress ) : + ( deviceHostName == hostName ); +kDebug()<<"existing device:"<<deviceHostName<<"at"<<device.ipAddress()<<"vs."<<hostName<<"at"<<ipAddress<<":"<<isSameAddress; + + if( isSameAddress ) { d = device.dPtr(); deviceOfService = &device; @@ -134,7 +148,9 @@ if( !d ) { const QString deviceName = hostName.left( hostName.indexOf('.') ); - d = new NetDevicePrivate( deviceName, hostName ); + d = new NetDevicePrivate( deviceName ); + d->setHostName( hostName ); + d->setIpAddress( ipAddress ); NetDevice device( d ); deviceList.append( device ); deviceOfService = &deviceList.last(); @@ -146,6 +162,11 @@ mNetworkPrivate->emitDevicesAdded( newDevices ); kDebug()<<"new device:"<<deviceName<<"at"<<hostName<<"by"<<service->type(); } + else + { + if( d->hostName().isEmpty() && ! hostName.isEmpty() ) + d->setHostName( hostName ); + } const QString serviceType = service->type(); Index: runtime/kioslave/network/network/netdevice.cpp =================================================================== --- runtime/kioslave/network/network/netdevice.cpp (revision 1079783) +++ runtime/kioslave/network/network/netdevice.cpp (revision 1079784) @@ -29,7 +29,7 @@ namespace Mollet { -K_GLOBAL_STATIC_WITH_ARGS(KSharedPtr< NetDevicePrivate >, dummyNetDevicePrivate, ( new NetDevicePrivate(QString(),QString()) )) +K_GLOBAL_STATIC_WITH_ARGS(KSharedPtr< NetDevicePrivate >, dummyNetDevicePrivate, ( new NetDevicePrivate(QString()) )) QString NetDevice::iconName( Type type ) @@ -59,6 +59,8 @@ QString NetDevice::name() const { return d->name(); } QString NetDevice::hostName() const { return d->hostName(); } +QString NetDevice::ipAddress() const { return d->ipAddress(); } +QString NetDevice::hostAddress() const { return d->hostAddress(); } NetDevice::Type NetDevice::type() const { return d->type(); } QList<NetService> NetDevice::serviceList() const { return d->serviceList(); } Index: runtime/kioslave/network/network/networkdbus.cpp =================================================================== --- runtime/kioslave/network/network/networkdbus.cpp (revision 1079783) +++ runtime/kioslave/network/network/networkdbus.cpp (revision 1079784) @@ -38,6 +38,7 @@ argument.beginStructure(); argument << devicePrivate->name(); argument << devicePrivate->hostName(); + argument << devicePrivate->ipAddress(); argument << (int) devicePrivate->type(); argument.endStructure(); @@ -47,15 +48,19 @@ { QString name; QString hostName; + QString ipAddress; int type; argument.beginStructure(); argument >> name; argument >> hostName; + argument >> ipAddress; argument >> type; argument.endStructure(); - Mollet::NetDevicePrivate* d = new Mollet::NetDevicePrivate( name, hostName ); + Mollet::NetDevicePrivate* d = new Mollet::NetDevicePrivate( name ); + d->setHostName( hostName ); + d->setIpAddress( ipAddress ); d->setType( (Mollet::NetDevice::Type)type ); device.setDPtr( d ); Index: runtime/kioslave/network/network/network_p.cpp =================================================================== --- runtime/kioslave/network/network/network_p.cpp (revision 1079783) +++ runtime/kioslave/network/network/network_p.cpp (revision 1079784) @@ -26,6 +26,7 @@ #include <config-slp.h> // lib #include "builder/dnssd/dnssdnetworkbuilder.h" +#include "builder/upnp/upnpnetworkbuilder.h" #include "builder/simpleitemfactory.h" #ifdef HAVE_SLP #include "builder/slp/slpnetworkbuilder.h" @@ -47,10 +48,12 @@ mNetSystemFactoryList.append( simpleItemFactory ); DNSSDNetworkBuilder* dnssdBuilder = new DNSSDNetworkBuilder( this ); + UpnpNetworkBuilder* upnpBuilder = new UpnpNetworkBuilder( this ); #ifdef HAVE_SLP // mSlpBuilder = new SlpNetworkBuilder( this ); #endif mNetworkBuilderList.append( dnssdBuilder ); + mNetworkBuilderList.append( upnpBuilder ); mNoOfInitBuilders = mNetworkBuilderList.count(); foreach( AbstractNetworkBuilder* builder, mNetworkBuilderList ) Index: runtime/kioslave/network/network/netdevice.h =================================================================== --- runtime/kioslave/network/network/netdevice.h (revision 1079783) +++ runtime/kioslave/network/network/netdevice.h (revision 1079784) @@ -49,6 +49,7 @@ class MOLLETNETWORK_EXPORT NetDevice { friend class DNSSDNetworkBuilder; + friend class UpnpNetworkBuilder; friend QDBusArgument& ::operator<<( QDBusArgument& argument, const NetDevice& device ); friend const QDBusArgument& ::operator>>( const QDBusArgument& argument, NetDevice& device ); @@ -65,6 +66,10 @@ public: QString name() const; QString hostName() const; + /// if hostName is not set, use ipAddress to identify device + QString ipAddress() const; + /// returns hostName if set, otherwise ipAddress TODO: find better name + QString hostAddress() const; Type type() const; QList<NetService> serviceList() const; Index: runtime/kioslave/network/network/netservice.h =================================================================== --- runtime/kioslave/network/network/netservice.h (revision 1079783) +++ runtime/kioslave/network/network/netservice.h (revision 1079784) @@ -49,6 +49,7 @@ class MOLLETNETWORK_EXPORT NetService { friend class DNSSDNetworkBuilder; + friend class UpnpNetworkBuilder; friend QDBusArgument& ::operator<<( QDBusArgument& argument, const NetService& service ); friend const QDBusArgument& ::operator>>( const QDBusArgument& argument, NetService& service ); Index: runtime/kioslave/network/network/netdevice_p.cpp =================================================================== --- runtime/kioslave/network/network/netdevice_p.cpp (revision 1079783) +++ runtime/kioslave/network/network/netdevice_p.cpp (revision 1079784) @@ -29,9 +29,8 @@ namespace Mollet { -NetDevicePrivate::NetDevicePrivate( const QString& name, const QString& hostName ) +NetDevicePrivate::NetDevicePrivate( const QString& name ) : mName( name ) - , mHostName( hostName ) , mType( NetDevice::Unknown ) { } Index: runtime/kioslave/network/network/netdevice_p.h =================================================================== --- runtime/kioslave/network/network/netdevice_p.h (revision 1079783) +++ runtime/kioslave/network/network/netdevice_p.h (revision 1079784) @@ -38,17 +38,21 @@ class NetDevicePrivate : public QSharedData { public: - explicit NetDevicePrivate( const QString& name, const QString& hostName ); + explicit NetDevicePrivate( const QString& name ); virtual ~NetDevicePrivate(); public: const QString& name() const; const QString& hostName() const; + const QString& ipAddress() const; + const QString& hostAddress() const; NetDevice::Type type() const; const QList<NetService>& serviceList() const; public: void setName( const QString& name ); + void setHostName( const QString& hostName ); + void setIpAddress( const QString& ipAddress ); void setType( NetDevice::Type type ); void addService( const NetService& service ); NetService removeService( const QString& serviceName ); @@ -56,17 +60,22 @@ private: QString mName; QString mHostName; + QString mIpAddress; NetDevice::Type mType; QList<NetService> mServiceList; }; -inline const QString& NetDevicePrivate::name() const { return mName; } -inline const QString& NetDevicePrivate::hostName() const { return mHostName; } -inline NetDevice::Type NetDevicePrivate::type() const { return mType; } +inline const QString& NetDevicePrivate::name() const { return mName; } +inline const QString& NetDevicePrivate::hostName() const { return mHostName; } +inline const QString& NetDevicePrivate::ipAddress() const { return mIpAddress; } +inline NetDevice::Type NetDevicePrivate::type() const { return mType; } inline const QList<NetService>& NetDevicePrivate::serviceList() const { return mServiceList; } +inline const QString& NetDevicePrivate::hostAddress() const { return mHostName.isEmpty() ? mIpAddress : mHostName; } inline void NetDevicePrivate::setName( const QString& name ) { mName = name; } +inline void NetDevicePrivate::setHostName( const QString& hostName ) { mHostName = hostName; } +inline void NetDevicePrivate::setIpAddress( const QString& ipAddress ) { mIpAddress = ipAddress; } inline void NetDevicePrivate::setType( NetDevice::Type type ) { mType = type; } inline void NetDevicePrivate::addService( const NetService& service ) { mServiceList.append( service ); } Index: runtime/kioslave/network/network/CMakeLists.txt =================================================================== --- runtime/kioslave/network/network/CMakeLists.txt (revision 1079783) +++ runtime/kioslave/network/network/CMakeLists.txt (revision 1079784) @@ -1,11 +1,13 @@ project( molletnetwork ) +set( LIBKUPNP_REL_DIR ../kupnp/lib ) macro_bool_to_01( SLP_FOUND HAVE_SLP ) configure_file( config-slp.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-slp.h ) include_directories( builder + ${LIBKUPNP_REL_DIR} ) set( netsystemdriver_SRCS @@ -24,6 +26,10 @@ builder/dnssd/dnssdnetworkbuilder.cpp ) +set( upnpnetworkbuilder_SRCS + builder/upnp/upnpnetworkbuilder.cpp +) + set( networkbuilder_SRCS builder/abstractnetworkbuilder.cpp builder/abstractnetsystemfactory.cpp @@ -36,6 +42,7 @@ set( molletnetwork_LIB_SRCS ${netsystemdriver_SRCS} # ${slpnetworkbuilder_SRCS} + ${upnpnetworkbuilder_SRCS} ${dnssdnetworkbuilder_SRCS} ${networkbuilder_SRCS} ${networkdbus_LIB_SRCS} @@ -48,7 +55,7 @@ ) -set( molletnetwork_LINK_LIBS ${KDE4_KDECORE_LIBS} ${KDE4_KDNSSD_LIBS} ) +set( molletnetwork_LINK_LIBS kupnp ${KDE4_KDECORE_LIBS} ${KDE4_KDNSSD_LIBS} ${QT_QTNETWORK_LIBRARY} ) if(SLP_FOUND) set( molletnetwork_LINK_LIBS ${molletnetwork_LINK_LIBS} ${SLP_LIBRARIES} ) Index: runtime/kioslave/network/mimetypes/network.xml =================================================================== --- runtime/kioslave/network/mimetypes/network.xml (revision 1079783) +++ runtime/kioslave/network/mimetypes/network.xml (revision 1079784) @@ -274,7 +274,109 @@ <comment>RealPlayer Shared Favorites</comment> </mime-type> + <!-- UPnP --> + <mime-type type="inode/vnd.kde.service.upnp.BasicDevice1"> + <generic-icon name="network-server"/> + <comment>UPnP Basic Device</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.WLANAccessPointDevice1"> + <generic-icon name="network-wireless"/> + <comment>UPnP WLAN Access Point Device</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.InternetGatewayDevice1"> + <generic-icon name="network-server"/> + <comment>UPnP Internet Gateway Device</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.PrinterBasic1"> + <generic-icon name="printer"/> + <comment>UPnP Printer (Basic)</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.PrinterEnhanced1"> + <generic-icon name="printer"/> + <comment>UPnP Printer (Enhanced)</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.Scanner1"> + <generic-icon name="scanner"/> + <comment>UPnP Scanner</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.MediaServer1"> + <generic-icon name="folder-remote"/> + <comment>UPnP Media Server</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.MediaRenderer1"> + <generic-icon name="terminal"/> + <comment>UPnP Media Renderer</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.MediaServer2"> + <generic-icon name="folder-remote"/> + <comment>UPnP Media Server</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.MediaRenderer2"> + <generic-icon name="terminal"/> + <comment>UPnP Media Renderer</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.MediaServer3"> + <generic-icon name="folder-remote"/> + <comment>UPnP Media Server</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.SolarProtectionBlind1"> + <generic-icon name="device"/> + <comment>UPnP Solar Protection Blind</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.DigitalSecurityCamera1"> + <generic-icon name="camera"/> + <comment>UPnP Digital Security Camera</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.HVAC1"> + <generic-icon name="device"/> + <comment>UPnP HVAC</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.LightingControls1"> + <generic-icon name="light"/> + <comment>UPnP Lighting Controls</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.RemoteUIClient1"> + <generic-icon name="printer"/> + <comment>UPnP Remote UI Client</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.RemoteUIServer1"> + <generic-icon name="printer"/> + <comment>UPnP Remote UI Server</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.Unknown"> + <generic-icon name="device"/> + <comment>Unknown UPnP Device</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.WANDevice1"> + <generic-icon name="network-wireless"/> + <comment>UPnP WAN Device</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <mime-type type="inode/vnd.kde.service.upnp.WANConnectionDevice1"> + <generic-icon name="network-wireless"/> + <comment>UPnP WAN Connection Device</comment> + <expanded-acronym>UPnP Universal Plug and Play</expanded-acronym> + </mime-type> + <!-- uri/ fake mime types --> <!-- <mime-type type="uri/mms"> <comment>mms: URIs</comment> Index: runtime/kioslave/network/CMakeLists.txt =================================================================== --- runtime/kioslave/network/CMakeLists.txt (revision 1079783) +++ runtime/kioslave/network/CMakeLists.txt (revision 1079784) @@ -2,3 +2,4 @@ add_subdirectory( ioslave ) add_subdirectory( kded ) add_subdirectory( mimetypes ) +add_subdirectory( kupnp ) Index: runtime/kioslave/network/kupnp/browser/main.cpp =================================================================== --- runtime/kioslave/network/kupnp/browser/main.cpp (revision 0) +++ runtime/kioslave/network/kupnp/browser/main.cpp (revision 1079784) @@ -0,0 +1,58 @@ +/* + This file is part of the KUPnP library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License or (at your option) version 3 or any later version + accepted by the membership of KDE e.V. (or its successor approved + by the membership of KDE e.V.), which shall act as a proxy + defined in Section 14 of version 3 of the license. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +// lib +#include <devicebrowser.h> +#include <device.h> +#include <service.h> +// KDE +#include <KApplication> +#include <KCmdLineArgs> +#include <KAboutData> +// Qt +#include <QtCore/QTextStream> +#include <QtCore/QTimer> + + +int main( int argc, char* argv[] ) +{ + KAboutData aboutData( "kupnpbrowser", "KUpnpBrowser", ki18n(""), "", ki18n("") ); + KCmdLineArgs::init( argc, argv, &aboutData ); + KApplication programCore; + + UPnP::DeviceBrowser deviceBrowser; + const QList<UPnP::Device> devices = deviceBrowser.devices(); + + QTextStream out( stdout ); + foreach( const UPnP::Device& device, devices ) + { + const QList<UPnP::Service> services = device.services(); + + out << device.displayName() << " ("<<device.type()<<")"<<endl; + foreach( const UPnP::Service& service, services ) + out << "* " << service.displayName() << " ("<<service.type()<<")"<<endl; + } + + // run loop at least once + QTimer::singleShot( 0, &programCore, SLOT(quit()) ); + return programCore.exec(); +} Index: runtime/kioslave/network/kupnp/browser/CMakeLists.txt =================================================================== --- runtime/kioslave/network/kupnp/browser/CMakeLists.txt (revision 0) +++ runtime/kioslave/network/kupnp/browser/CMakeLists.txt (revision 1079784) @@ -0,0 +1,18 @@ +include_directories( + ../lib +) + +set( kupnpbrowser_SRCS + main.cpp +) + +kde4_add_executable( kupnpbrowser ${kupnpbrowser_SRCS} ) + +target_link_libraries( kupnpbrowser + kupnp + ${KDE4_KDEUI_LIBS} + ${QT_QTGUI_LIBRARY} + ${QT_QTCORE_LIBRARY} +) + +install( TARGETS kupnpbrowser ${INSTALL_TARGETS_DEFAULT_ARGS} ) Index: runtime/kioslave/network/kupnp/lib/device.cpp =================================================================== --- runtime/kioslave/network/kupnp/lib/device.cpp (revision 0) +++ runtime/kioslave/network/kupnp/lib/device.cpp (revision 1079784) @@ -0,0 +1,72 @@ +/* + This file is part of the KUPnP library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "device.h" +#include "device_p.h" + + +namespace UPnP +{ + +Device::Device() + : d( new DevicePrivate() ) +{} + +Device::Device( DevicePrivate* _d ) + : d( _d ) +{ +} + +Device::Device( const Device& other ) + : d( other.d ) +{ +} + + +QString Device::udn() const { return d->udn(); } +QString Device::displayName() const { return d->displayName(); } +QString Device::type() const { return d->type(); } +QList<Service> Device::services() const { return d->services(); } +QString Device::ipAddress() const { return d->ipAddress(); } +int Device::ipPortNumber() const { return d->ipPortNumber(); } +QString Device::presentationUrl() const { return d->presentationUrl(); } +Device Device::parentDevice() const { return d->parentDevice(); } +QList<Device> Device::childDevices() const { return d->childDevices(); } +bool Device::hasParentDevice() const { return d->hasParentDevice(); } +bool Device::isValid() const { return d->isValid(); } + +Device& Device::operator =( const Device& other ) +{ + d = other.d; + return *this; +} + +bool Device::operator==( const Device& other ) const +{ + return ( d == other.d ); +} + +Device::~Device() +{ +} + +} Index: runtime/kioslave/network/kupnp/lib/org.Coherence.xml =================================================================== --- runtime/kioslave/network/kupnp/lib/org.Coherence.xml (revision 0) +++ runtime/kioslave/network/kupnp/lib/org.Coherence.xml (revision 1079784) @@ -0,0 +1,116 @@ +<?xml version="1.0" standalone='no'?><!--*-nxml-*--> +<?xml-stylesheet type="text/xsl" href="introspect.xsl"?> +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> + +<!-- + This file is part of ? + Found by introspection output via qdbusviewer + + License +--> + +<node> + <interface name="org.Coherence"> + <method name="pin"> + <arg direction="in" type="s" name="key" /> + <arg direction="in" type="v" name="value" /> + </method> + <method name="create_oob"> + <arg direction="in" type="s" name="file" /> + <arg direction="out" type="s" /> + </method> + <signal name="DMR_added"> + <arg type="v" name="device" /> + <arg type="s" name="udn" /> + </signal> + <method name="import_resource"> + <arg direction="in" type="s" name="device_id" /> + <arg direction="in" type="s" name="source_uri" /> + <arg direction="in" type="s" name="destination_uri" /> + <arg direction="out" type="v" /> + </method> + <signal name="DMS_added"> + <arg type="v" name="device" /> + <arg type="s" name="udn" /> + </signal> + <method name="get_device_with_id"> + <arg direction="in" type="s" name="id" /> + <arg direction="out" type="v" /> + </method> + <method name="get_devices_async"> + <arg direction="out" type="av" /> + </method> + <method name="put_resource"> + <arg direction="in" type="s" name="destination_uri" /> + <arg direction="in" type="s" name="filepath" /> + <arg direction="out" type="v" /> + </method> + <method name="hostname"> + <arg direction="out" type="s" /> + </method> + <method name="version"> + <arg direction="out" type="s" /> + </method> + <signal name="DMS_removed"> + <arg type="s" name="udn" /> + </signal> + <signal name="UPnP_ControlPoint_MediaServer_removed"> + <arg type="s" name="udn" /> + </signal> + <method name="create_object"> + <arg direction="in" type="s" name="device_id" /> + <arg direction="in" type="s" name="container_id" /> + <arg direction="in" type="a{ss}" name="arguments" /> + <arg direction="out" type="v" /> + <annotation name="com.trolltech.QtDBus.QtTypeName.In2" value="QVariantMap"/> + </method> + <signal name="DMR_removed"> + <arg type="s" name="udn" /> + </signal> + <method name="remove_plugin"> + <arg direction="in" type="s" name="uuid" /> + <arg direction="out" type="s" /> + </method> + <signal name="UPnP_ControlPoint_MediaRenderer_detected"> + <arg type="v" name="device" /> + <arg type="s" name="udn" /> + </signal> + <method name="add_plugin"> + <arg direction="in" type="s" name="backend" /> + <arg direction="in" type="a{ss}" name="arguments" /> + <arg direction="out" type="s" /> + <annotation name="com.trolltech.QtDBus.QtTypeName.In1" value="QVariantMap"/> + </method> + <signal name="UPnP_ControlPoint_MediaServer_detected"> + <arg type="v" name="device" /> + <arg type="s" name="udn" /> + </signal> + <method name="call_plugin"> + <arg direction="in" type="s" name="uuid" /> + <arg direction="in" type="s" name="method" /> + <arg direction="in" type="a{ss}" name="arguments" /> + <arg direction="out" type="s" /> + <annotation name="com.trolltech.QtDBus.QtTypeName.In2" value="QVariantMap"/> + </method> + <method name="get_devices"> + <arg direction="out" type="av" /> + </method> + <signal name="UPnP_ControlPoint_MediaRenderer_removed"> + <arg type="s" name="udn" /> + </signal> + <signal name="device_removed"> + <arg type="s" name="udn" /> + </signal> + <method name="unpin"> + <arg direction="in" type="s" name="key" /> + </method> + <signal name="device_detected"> + <arg type="v" name="device" /> + <arg type="s" name="udn" /> + </signal> + <method name="get_pin"> + <arg direction="in" type="s" name="key" /> + <arg direction="out" type="v" /> + </method> + </interface> +</node> Index: runtime/kioslave/network/kupnp/lib/service.cpp =================================================================== --- runtime/kioslave/network/kupnp/lib/service.cpp (revision 0) +++ runtime/kioslave/network/kupnp/lib/service.cpp (revision 1079784) @@ -0,0 +1,61 @@ +/* + This file is part of the KUPnP library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "service.h" +#include "service_p.h" + + +namespace UPnP +{ + +Service::Service() + : d( new ServicePrivate() ) // TODO: would a static default null object increase performance? +{} + +Service::Service( ServicePrivate* _d ) + : d( _d ) +{ +} + +Service::Service( const Service& other ) + : d( other.d ) +{ +} + +// QString Service::udn() const { return d->udn(); } +Device Service::device() const { return d->device(); } + +QString Service::displayName() const { return d->displayName(); } +QString Service::type() const { return d->type(); } + + +Service& Service::operator =( const Service& other ) +{ + d = other.d; + return *this; +} + +Service::~Service() +{ +} + +} Index: runtime/kioslave/network/kupnp/lib/devicebrowser_p.cpp =================================================================== --- runtime/kioslave/network/kupnp/lib/devicebrowser_p.cpp (revision 0) +++ runtime/kioslave/network/kupnp/lib/devicebrowser_p.cpp (revision 1079784) @@ -0,0 +1,284 @@ +/* + This file is part of the KUPnP library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + Copyright 2009 Adriaan de Groot <groot@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as argument proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received argument copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "devicebrowser_p.h" + +// lib +#include "device_p.h" +#include "service_p.h" +// Qt +#include <QtDBus/QDBusArgument> + +#include <QtCore/QDebug> + +namespace UPnP +{ + +static const char requiredCoherenceVersionString[] = "0.6.5"; +static const int requiredCoherenceVersion[] = {0,6,5}; +static const int requiredCoherenceVersionLength = + sizeof(requiredCoherenceVersion) / sizeof(requiredCoherenceVersion[0]); + + +static bool checkVersion( const QString& coherenceVersionString ) +{ + const QStringList coherenceVersionParts = coherenceVersionString.split( '.' ); + + for( int i=0; i<requiredCoherenceVersionLength; ++i ) + { + const int versionPart = coherenceVersionParts[i].toInt(); + if( requiredCoherenceVersion[i] < versionPart ) + break; + + if( requiredCoherenceVersion[i] > versionPart ) + { +qDebug() << "Coherence version" << coherenceVersionString << "is not ok," + << requiredCoherenceVersionString << "required."; + return false; + } + } +qDebug() << "Coherence version" << coherenceVersionString << "is ok."; + + return true; +} + +QList<UPnP::Service> DeviceBrowserPrivate::demarshallServices( const Device& device, const QVariant& variant ) +{ + QList<UPnP::Service> result; + + const QStringList serviceDBusPathList = variant.value<QStringList>(); + foreach( const QString& serviceDBusPath, serviceDBusPathList ) + { + const QString typeName = serviceDBusPath.mid( serviceDBusPath.lastIndexOf('/')+1 ); + + ServicePrivate* servicePrivate = new ServicePrivate(); + servicePrivate->setDevice( device ); + servicePrivate->setDisplayName( typeName ); + servicePrivate->setType( typeName ); + servicePrivate->setDBusPath( serviceDBusPath ); + + result.append( Service(servicePrivate) ); + } + + return result; +} + +Device DeviceBrowserPrivate::addDevice( const QDBusArgument& dBusArgument ) +{ + DevicePrivate* devicePrivate = new DevicePrivate(); + Device device( devicePrivate ); + + QString parentUdn; + + dBusArgument.beginMap(); + while( ! dBusArgument.atEnd() ) + { + dBusArgument.beginMapEntry(); + QString key; + QDBusVariant dBusVariant; + dBusArgument >> key >> dBusVariant; + const QVariant variant = dBusVariant.variant(); + + if( key == QLatin1String("udn") ) + { + const QString uuid = variant.value<QString>().mid( 5 ); + devicePrivate->setUdn( uuid ); + } + else if( key == QLatin1String("friendly_name") ) + devicePrivate->setDisplayName( variant.value<QString>() ); + else if( key == QLatin1String("parent_udn") ) + parentUdn = variant.value<QString>().mid( 5 ); + else if( key == QLatin1String("device_type") ) + { + const QStringList typeParts = variant.value<QString>().split( ':' ); + devicePrivate->setType( typeParts[3]+typeParts[4] ); + } + else if( key == QLatin1String("path") ) + devicePrivate->setDBusPath( variant.value<QString>() ); + else if( key == QLatin1String("presentation_url") ) + devicePrivate->setPresentationUrl( variant.value<QString>() ); + else if( key == QLatin1String("uri") ) + { + const QString hostAddressAndPort = variant.value<QStringList>()[1]; + const int indexOfSeparator = hostAddressAndPort.indexOf( ':' ); + const QString hostAddress = hostAddressAndPort.left( indexOfSeparator ); + const int portNumber = hostAddressAndPort.mid( indexOfSeparator+1 ).toInt(); + devicePrivate->setIpAddress( hostAddress ); + devicePrivate->setIpPortNumber( portNumber ); + } + else if( key == QLatin1String("services") ) + { + QList<Service> services = demarshallServices( device, variant ); + devicePrivate->setServices( services ); + } +// else + { + if( variant.canConvert<QString>()) + { + const QString value = variant.value<QString>(); +qDebug() << " " << key << value; + } + else + { +qDebug() << " " << key << "-not argument string-"; + } + } + dBusArgument.endMapEntry(); + } + dBusArgument.endMap(); + + const QString& udn = devicePrivate->udn(); + if( udn.isEmpty() ) + { +qDebug()<<"No udn found!"; + devicePrivate->setInvalid(); + } + else if( mDevices.contains(udn) ) + { +qDebug()<<"Already inserted:"<<udn<<"!"; + devicePrivate->setInvalid(); + } + else if( ! mBrowsedDeviceTypes.isEmpty() && ! mBrowsedDeviceTypes.contains(devicePrivate->type()) ) + { +qDebug()<<"Not interested in:"<<devicePrivate->type(); + devicePrivate->setInvalid(); + } + else + { +qDebug()<<"Adding: "<<device.displayName()<<udn; + mDevices[udn] = device; + + if( ! parentUdn.isEmpty() ) + { + if( mDevices.contains(parentUdn) ) + { + devicePrivate->setParentDevice( mDevices[parentUdn].dPtr() ); + // TODO: else set to pending devices waiting for their parent device streamed + // but how to find about orphaned devices? might increase by time if the backend is broken + // what to do if devices browsed are filtered? set a flag like wouldHaveParent? + } + } + } + + return device; +} + + + +void DeviceBrowserPrivate::init() +{ +qDebug() << "Connecting to Coherence..."; + + // TODO: or use system bus? + mCoherence = new org::Coherence( "org.Coherence", "/org/Coherence", QDBusConnection::sessionBus()/*systemBus*/, q ); + + QDBusPendingReply<QString> versionReply = mCoherence->version(); + versionReply.waitForFinished(); + if( versionReply.isError() ) + { +qDebug()<< versionReply.error(); + return; + } + + const QString version = versionReply.value(); + + const bool versionOk = checkVersion( version ); + if( ! versionOk ) + return; + + connect( mCoherence, SIGNAL(device_detected( const QDBusVariant&, const QString& )), + SLOT(onDeviceAdded( const QDBusVariant&, const QString& )) ); + + connect( mCoherence, SIGNAL(device_removed(const QString& )), + SLOT(onDeviceRemoved( const QString& )) ); + + QDBusPendingReply<QVariantList> devicesReply = mCoherence->get_devices(); + devicesReply.waitForFinished(); + if( devicesReply.isError() ) + { +qDebug()<< devicesReply.error(); + return; + } + +qDebug()<< "Current devices..."; + QVariantList devicesReplyValue = devicesReply.value(); + foreach( const QVariant& devicesReplyValueItem, devicesReplyValue ) + { + const QVariant variant = qvariant_cast<QDBusVariant>( devicesReplyValueItem ).variant(); + const QDBusArgument dBusArgument = variant.value<QDBusArgument>(); + addDevice( dBusArgument ); + } +qDebug()<<"That's all."; +} + +QList<Device> DeviceBrowserPrivate::devices() const +{ + QList<Device> result; + + QHashIterator<QString,Device> it( mDevices); + while( it.hasNext() ) + { + it.next(); + result.append( it.value() ); + } + + return result; +} + +void DeviceBrowserPrivate::onDeviceAdded( const QDBusVariant& dBusVariant, const QString& udn ) +{ + Q_UNUSED( udn ); + + const QVariant variant = dBusVariant.variant(); + const QDBusVariant sv = variant.value<QDBusVariant>(); + const QVariant v = sv.variant(); + const QDBusArgument dBusArgument = v.value<QDBusArgument>(); + + Device device = addDevice( dBusArgument ); + if( device.isValid() ) + emit q->deviceAdded( device ); +} + +void DeviceBrowserPrivate::onDeviceRemoved( const QString& _udn ) +{ + const QString udn = _udn.mid( 5 ); + QHash<QString,Device>::Iterator it = mDevices.find( udn ); + if( it != mDevices.end() ) + { + Device device = it.value(); + mDevices.erase( it ); +qDebug() << "Removing"<<device.displayName(); + emit q->deviceRemoved( device ); + } + else +qDebug() << "Not found in device list:"<<udn; +} + + +DeviceBrowserPrivate::~DeviceBrowserPrivate() +{ + delete mCoherence; +} + + +} Index: runtime/kioslave/network/kupnp/lib/device_p.h =================================================================== --- runtime/kioslave/network/kupnp/lib/device_p.h (revision 0) +++ runtime/kioslave/network/kupnp/lib/device_p.h (revision 1079784) @@ -0,0 +1,147 @@ +/* + This file is part of the KUPnP library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef UPNP_DEVICE_P_H +#define UPNP_DEVICE_P_H + +// lib +#include "device.h" +#include "service.h" +// Qt +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QSharedData> + + +namespace UPnP +{ + +class DevicePrivate : public QSharedData +{ + public: + DevicePrivate(); + + ~DevicePrivate(); + + public: + const QString& udn() const; + const QString& displayName() const; + const QString& type() const; + const QString& ipAddress() const; + int ipPortNumber() const; + const QString& presentationUrl() const; + const QString& dBusPath() const; + const QList<Service>& services() const; + Device parentDevice() const; + const QList<Device>& childDevices() const; + + bool hasParentDevice() const; + bool isValid() const; + + public: + void setUdn( const QString& udn ); + void setType( const QString& deviceType ); + void setDisplayName( const QString& displayName ); + void setIpAddress( const QString& ipAddress ); + void setIpPortNumber( int portNumber ); + void setPresentationUrl( const QString& presentationUrl ); + void setDBusPath( const QString& dBusPath ); + void setServices( const QList<Service>& services ); + void setParentDevice( DevicePrivate* parentDevicePrivate ); + + void setInvalid(); + + void addChildDevice( DevicePrivate* childDevice ); + void removeChildDevice( DevicePrivate* childDevice ); + + protected: + // TODO: could just be a QByteArray + QString mUdn; + QString mDeviceType; + QString mDisplayName; + QString mIpAddress; + int mPortNumber; + QString mPresentationUrl; + QString mDBusPath; + + QList<Service> mServices; + + //just pointer to private to avoid circular refcounting + DevicePrivate* mParentDevicePrivate; + QList<Device> mChildDevices; +}; + + +inline DevicePrivate::DevicePrivate() + : mParentDevicePrivate( 0 ) +{} + +inline const QString& DevicePrivate::udn() const { return mUdn; } +inline const QString& DevicePrivate::type() const { return mDeviceType; } +inline const QString& DevicePrivate::displayName() const { return mDisplayName; } +inline const QString& DevicePrivate::ipAddress() const { return mIpAddress; } +inline int DevicePrivate::ipPortNumber() const { return mPortNumber; } +inline const QString& DevicePrivate::presentationUrl() const { return mPresentationUrl; } +inline const QString& DevicePrivate::dBusPath() const { return mDBusPath; } +inline const QList<Service>& DevicePrivate::services() const { return mServices; } +inline Device DevicePrivate::parentDevice() const { return Device(mParentDevicePrivate); } +inline const QList<Device>& DevicePrivate::childDevices() const { return mChildDevices; } +inline bool DevicePrivate::hasParentDevice() const { return (mParentDevicePrivate != 0); } +inline bool DevicePrivate::isValid() const { return ! mUdn.isEmpty(); } + +inline void DevicePrivate::setUdn( const QString& udn ) { mUdn = udn; } +inline void DevicePrivate::setType( const QString& deviceType ) { mDeviceType = deviceType; } +inline void DevicePrivate::setDisplayName( const QString& displayName ) { mDisplayName = displayName; } +inline void DevicePrivate::setIpAddress( const QString& ipAddress ) { mIpAddress = ipAddress; } +inline void DevicePrivate::setIpPortNumber( int portNumber ) { mPortNumber = portNumber; } +inline void DevicePrivate::setPresentationUrl( const QString& presentationUrl ) { mPresentationUrl = presentationUrl; } +inline void DevicePrivate::setDBusPath( const QString& dBusPath ) { mDBusPath = dBusPath; } +inline void DevicePrivate::setServices( const QList<Service>& services ) { mServices = services; } +inline void DevicePrivate::setParentDevice( DevicePrivate* parentDevicePrivate ) +{ + mParentDevicePrivate = parentDevicePrivate; + if( mParentDevicePrivate ) + mParentDevicePrivate->addChildDevice( this ); +} + +inline void DevicePrivate::setInvalid() { mUdn.clear(); } + +inline void DevicePrivate::addChildDevice( DevicePrivate* childDevice ) +{ + mChildDevices.append( Device(childDevice) ); +} +inline void DevicePrivate::removeChildDevice( DevicePrivate* childDevice ) +{ + mChildDevices.removeOne( Device(childDevice) ); +} + +inline DevicePrivate::~DevicePrivate() +{ + if( mParentDevicePrivate ) + mParentDevicePrivate->removeChildDevice( this ); + foreach( const Device& device, mChildDevices ) + device.dPtr()->setParentDevice( 0 ); +} + +} + +#endif Index: runtime/kioslave/network/kupnp/lib/devicebrowser.cpp =================================================================== --- runtime/kioslave/network/kupnp/lib/devicebrowser.cpp (revision 0) +++ runtime/kioslave/network/kupnp/lib/devicebrowser.cpp (revision 1079784) @@ -0,0 +1,56 @@ +/* + This file is part of the KUPnP library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "devicebrowser.h" +#include "devicebrowser_p.h" + + +namespace UPnP +{ + +DeviceBrowser::DeviceBrowser( const QStringList& deviceTypes ) + : d( new DeviceBrowserPrivate(this,deviceTypes) ) +{ + d->init(); +} +DeviceBrowser::DeviceBrowser( const QString& deviceType ) + : d( new DeviceBrowserPrivate(this,deviceType) ) +{ + d->init(); +} + +QList<Device> DeviceBrowser::devices() const +{ + return d->devices(); +} + +QStringList DeviceBrowser::browsedDeviceTypes() const +{ + return d->browsedDeviceTypes(); +} + +DeviceBrowser::~DeviceBrowser() +{ + delete d; +} + +} Index: runtime/kioslave/network/kupnp/lib/device.h =================================================================== --- runtime/kioslave/network/kupnp/lib/device.h (revision 0) +++ runtime/kioslave/network/kupnp/lib/device.h (revision 1079784) @@ -0,0 +1,86 @@ +/* + This file is part of the KUPnP library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef UPNP_DEVICE_H +#define UPNP_DEVICE_H + +// lib +#include "upnp_export.h" +// Qt +#include <QtCore/QExplicitlySharedDataPointer> + +template<class T> class QList; + + +namespace UPnP +{ +class DevicePrivate; +class Service; + + +class KUPNP_EXPORT Device +{ + friend class ServicePrivate; + friend class DevicePrivate; + friend class DeviceBrowserPrivate; + + protected: + explicit Device( DevicePrivate* d ); + + public: + Device(); + Device( const Device& other ); + + virtual ~Device(); + + public: + /// without the prefix "uuid:" + QString udn() const; + QString displayName() const; + QString type() const; + QString ipAddress() const; + int ipPortNumber() const; + QString presentationUrl() const; + QList<Service> services() const; + Device parentDevice() const; + QList<Device> childDevices() const; + + bool hasParentDevice() const; + bool isValid() const; + + public: + Device& operator =( const Device& other ); + bool operator==( const Device& other ) const; + + private: + DevicePrivate* dPtr() const; + + protected: + QExplicitlySharedDataPointer<DevicePrivate> d; +}; + + +inline DevicePrivate* Device::dPtr() const { return const_cast<DevicePrivate*>( d.data() ); } + +} + +#endif Index: runtime/kioslave/network/kupnp/lib/service_p.h =================================================================== --- runtime/kioslave/network/kupnp/lib/service_p.h (revision 0) +++ runtime/kioslave/network/kupnp/lib/service_p.h (revision 1079784) @@ -0,0 +1,81 @@ +/* + This file is part of the KUPnP library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef UPNP_SERVICE_P_H +#define UPNP_SERVICE_P_H + +// lib +#include "service.h" +#include "device.h" +// Qt +#include <QtCore/QString> +#include <QtCore/QSharedData> + + +namespace UPnP +{ + +class ServicePrivate : public QSharedData +{ + public: + ServicePrivate(); + + ~ServicePrivate(); + + public: + const Device& device() const; + const QString& displayName() const; + const QString& type() const; + const QString& dBusPath() const; + + public: + void setDevice( const Device& device ); + void setDisplayName( const QString& displayName ); + void setType( const QString& type ); + void setDBusPath( const QString& dBusPath ); + + protected: + Device mDevice; + + QString mDisplayName; + QString mType; + QString mDBusPath; +}; + + +inline ServicePrivate::ServicePrivate() {} + +inline const Device& ServicePrivate::device() const { return mDevice; } +inline const QString& ServicePrivate::displayName() const { return mDisplayName; } +inline const QString& ServicePrivate::type() const { return mType; } +inline const QString& ServicePrivate::dBusPath() const { return mDBusPath; } + +inline void ServicePrivate::setDevice( const Device& device ) { mDevice = device; } +inline void ServicePrivate::setDisplayName( const QString& displayName ) { mDisplayName = displayName; } +inline void ServicePrivate::setType( const QString& type ) { mType = type; } +inline void ServicePrivate::setDBusPath( const QString& dBusPath ) { mDBusPath = dBusPath; } + +inline ServicePrivate::~ServicePrivate() {} + +} + +#endif Index: runtime/kioslave/network/kupnp/lib/service.h =================================================================== --- runtime/kioslave/network/kupnp/lib/service.h (revision 0) +++ runtime/kioslave/network/kupnp/lib/service.h (revision 1079784) @@ -0,0 +1,74 @@ +/* + This file is part of the KUPnP library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef UPNP_SERVICE_H +#define UPNP_SERVICE_H + +// lib +#include "upnp_export.h" +// #include "device.h" +// Qt +#include <QtCore/QExplicitlySharedDataPointer> + + +namespace UPnP +{ +class ServicePrivate; +class Device; + + +class KUPNP_EXPORT Service +{ + friend class ServicePrivate; + friend class DeviceBrowserPrivate; + + protected: + explicit Service( ServicePrivate* d ); + + public: + Service(); + Service( const Service& other ); + + virtual ~Service(); + + public: +// QString udn() const; + QString displayName() const; + QString type() const; + Device device() const; + + public: + Service& operator =( const Service& other ); + + private: + ServicePrivate* dPtr() const; + + protected: + QExplicitlySharedDataPointer<ServicePrivate> d; +}; + + +inline ServicePrivate* Service::dPtr() const { return const_cast<ServicePrivate*>( d.data() ); } + +} + +#endif Index: runtime/kioslave/network/kupnp/lib/devicebrowser_p.h =================================================================== --- runtime/kioslave/network/kupnp/lib/devicebrowser_p.h (revision 0) +++ runtime/kioslave/network/kupnp/lib/devicebrowser_p.h (revision 1079784) @@ -0,0 +1,88 @@ +/* + This file is part of the KUPnP library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef UPNP_DEVICEBROWSER_P_H +#define UPNP_DEVICEBROWSER_P_H + +// lib +#include "devicebrowser.h" +#include "device.h" +#include "coherence_interface.h" + + +namespace UPnP +{ + +class DeviceBrowserPrivate : public QObject +{ + Q_OBJECT + + protected: + static QList<Service> demarshallServices( const Device& device, const QVariant& variant ); + + public: + explicit DeviceBrowserPrivate( DeviceBrowser* q, const QStringList& deviceTypes ); + explicit DeviceBrowserPrivate( DeviceBrowser* q, const QString& deviceType ); + + ~DeviceBrowserPrivate(); + + public: + QList<Device> devices() const; + const QStringList& browsedDeviceTypes() const; + + public: + void init(); + + protected: + Device addDevice( const QDBusArgument& dbusArgument ); + + protected Q_SLOTS: + void onDeviceAdded( const QDBusVariant&, const QString& udn ); + void onDeviceRemoved( const QString& udn ); + + protected: + DeviceBrowser* const q; + + org::Coherence* mCoherence; + + QStringList mBrowsedDeviceTypes; + QHash<QString,Device> mDevices; +}; + + +inline DeviceBrowserPrivate::DeviceBrowserPrivate( DeviceBrowser* _q, const QStringList& deviceTypes ) + : q( _q ), + mCoherence( 0 ), + mBrowsedDeviceTypes( deviceTypes ) +{} +inline DeviceBrowserPrivate::DeviceBrowserPrivate( DeviceBrowser* _q, const QString& deviceType ) + : q( _q ), + mCoherence( 0 ) +{ + mBrowsedDeviceTypes.append( deviceType ); +} + +inline const QStringList& DeviceBrowserPrivate::browsedDeviceTypes() const { return mBrowsedDeviceTypes; } + +} + +#endif Index: runtime/kioslave/network/kupnp/lib/devicebrowser.h =================================================================== --- runtime/kioslave/network/kupnp/lib/devicebrowser.h (revision 0) +++ runtime/kioslave/network/kupnp/lib/devicebrowser.h (revision 1079784) @@ -0,0 +1,68 @@ +/* + This file is part of the KUPnP library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef UPNP_DEVICEBROWSER_H +#define UPNP_DEVICEBROWSER_H + +// lib +#include "upnp_export.h" +// Qt +#include <QtCore/QStringList> +#include <QtCore/QObject> + +template<class T> class QList; + + +namespace UPnP +{ +class DeviceBrowserPrivate; +class Device; + + +class KUPNP_EXPORT DeviceBrowser : public QObject +{ + Q_OBJECT + + friend class DeviceBrowserPrivate; + + public: + explicit DeviceBrowser( const QStringList& deviceTypes = QStringList() ); + explicit DeviceBrowser( const QString& deviceType ); + + virtual ~DeviceBrowser(); + + public: + QList<Device> devices() const; + + QStringList browsedDeviceTypes() const; + + Q_SIGNALS: + void deviceAdded( const UPnP::Device& device ); + void deviceRemoved( const UPnP::Device& device ); + + protected: + DeviceBrowserPrivate* const d; +}; + +} + +#endif Index: runtime/kioslave/network/kupnp/lib/upnp_export.h =================================================================== --- runtime/kioslave/network/kupnp/lib/upnp_export.h (revision 0) +++ runtime/kioslave/network/kupnp/lib/upnp_export.h (revision 1079784) @@ -0,0 +1,44 @@ +/* + This file is part of the KUPnP library, part of the KDE project. + + Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef UPNP_EXPORT_H +#define UPNP_EXPORT_H + +// KDE +#include <kdemacros.h> + + +#ifndef KUPNP_EXPORT + // building the library? +# if defined(MAKE_KUPNP_LIB) +# define KUPNP_EXPORT KDE_EXPORT + // using the library +# else +# define KUPNP_EXPORT KDE_IMPORT +# endif +#endif + +# ifndef KUPNP_EXPORT_DEPRECATED +# define KUPNP_EXPORT_DEPRECATED KDE_DEPRECATED KUPNP_EXPORT +# endif + +#endif Index: runtime/kioslave/network/kupnp/lib/CMakeLists.txt =================================================================== --- runtime/kioslave/network/kupnp/lib/CMakeLists.txt (revision 0) +++ runtime/kioslave/network/kupnp/lib/CMakeLists.txt (revision 1079784) @@ -0,0 +1,37 @@ +include_directories( +) + +set( kupnp_LIB_SRCS + service.cpp + device.cpp + devicebrowser_p.cpp + devicebrowser.cpp +) +set( kupnp_LIB_HDRS + upnp_export.h + service.h + device.h + devicebrowser.h +) + +# http://techbase.kde.org/Development/Tutorials/D-Bus/Accessing_Interfaces also adds: +#PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX) +#set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml) +qt4_add_dbus_interface( kupnp_LIB_SRCS org.Coherence.xml coherence_interface ) + + +kde4_add_library( kupnp STATIC ${kupnp_LIB_SRCS} ) + +# If making the lib SHARED again, uncomment again: +# target_link_libraries( kupnp +# ${QT_QTDBUS_LIBRARY} +# ${QT_QTCORE_LIBRARY} +# ) +# set_target_properties( kupnp PROPERTIES +# VERSION ${GENERIC_LIB_VERSION} +# SOVERSION ${GENERIC_LIB_SOVERSION} +# ) + +# install( TARGETS kupnp ${INSTALL_TARGETS_DEFAULT_ARGS} ) + +# install( FILES ${kupnp_LIB_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/upnp COMPONENT Devel ) Index: runtime/kioslave/network/kupnp/lib/org.Coherence.device.xml =================================================================== --- runtime/kioslave/network/kupnp/lib/org.Coherence.device.xml (revision 0) +++ runtime/kioslave/network/kupnp/lib/org.Coherence.device.xml (revision 1079784) @@ -0,0 +1,32 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.Coherence.device"> + <method name="get_friendly_device_type"> + <arg direction="out" type="s" /> + </method> + <method name="get_friendly_name"> + <arg direction="out" type="s" /> + </method> + <method name="get_device_icons"> + <arg direction="out" type="av" /> + </method> + <method name="get_usn"> + <arg direction="out" type="s" /> + </method> + <method name="get_device_type_version"> + <arg direction="out" type="i" /> + </method> + <method name="get_device_type"> + <arg direction="out" type="s" /> + </method> + <method name="get_id"> + <arg direction="out" type="s" /> + </method> + <method name="get_info"> + <arg direction="out" type="v" /> + </method> + <method name="get_markup_name"> + <arg direction="out" type="s" /> + </method> + </interface> +</node> Index: runtime/kioslave/network/kupnp/CMakeLists.txt =================================================================== --- runtime/kioslave/network/kupnp/CMakeLists.txt (revision 0) +++ runtime/kioslave/network/kupnp/CMakeLists.txt (revision 1079784) @@ -0,0 +1,4 @@ +project( kupnp ) + +macro_optional_add_subdirectory(lib) +#macro_optional_add_subdirectory(browser)