diff options
Diffstat (limited to 'src/modules')
| -rw-r--r-- | src/modules/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/modules/upnp/CMakeLists.txt | 30 | ||||
| -rw-r--r-- | src/modules/upnp/igdcontrolpoint.cpp | 190 | ||||
| -rw-r--r-- | src/modules/upnp/igdcontrolpoint.h | 100 | ||||
| -rw-r--r-- | src/modules/upnp/layer3forwardingservice.cpp | 137 | ||||
| -rw-r--r-- | src/modules/upnp/layer3forwardingservice.h | 84 | ||||
| -rw-r--r-- | src/modules/upnp/libkviupnp.cpp | 77 | ||||
| -rw-r--r-- | src/modules/upnp/manager.cpp | 154 | ||||
| -rw-r--r-- | src/modules/upnp/manager.h | 110 | ||||
| -rw-r--r-- | src/modules/upnp/rootservice.cpp | 281 | ||||
| -rw-r--r-- | src/modules/upnp/rootservice.h | 100 | ||||
| -rw-r--r-- | src/modules/upnp/service.cpp | 286 | ||||
| -rw-r--r-- | src/modules/upnp/service.h | 128 | ||||
| -rw-r--r-- | src/modules/upnp/ssdpconnection.cpp | 134 | ||||
| -rw-r--r-- | src/modules/upnp/ssdpconnection.h | 78 | ||||
| -rw-r--r-- | src/modules/upnp/wanconnectionservice.cpp | 192 | ||||
| -rw-r--r-- | src/modules/upnp/wanconnectionservice.h | 113 | ||||
| -rw-r--r-- | src/modules/upnp/xmlfunctions.cpp | 126 | ||||
| -rw-r--r-- | src/modules/upnp/xmlfunctions.h | 61 |
19 files changed, 2383 insertions, 2 deletions
diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt index 7eb6aee5e..b6f617e87 100644 --- a/src/modules/CMakeLists.txt +++ b/src/modules/CMakeLists.txt @@ -36,7 +36,7 @@ SUBDIRS( serverdb setup sharedfile sharedfileswindow snd socketspy spaste str system texticons term theme tip tmphighlight toolbar toolbareditor trayicon - url + upnp url window # broken modules @@ -54,4 +54,4 @@ SUBDIRS( IF(NOT MINGW) ADD_SUBDIRECTORY(rijndael) -ENDIF()
\ No newline at end of file +ENDIF() diff --git a/src/modules/upnp/CMakeLists.txt b/src/modules/upnp/CMakeLists.txt new file mode 100644 index 000000000..9ca767097 --- /dev/null +++ b/src/modules/upnp/CMakeLists.txt @@ -0,0 +1,30 @@ +# CMakeLists for src/modules/upnp + +SET(kviupnp_SRCS + igdcontrolpoint.cpp + layer3forwardingservice.cpp + libkviupnp.cpp + manager.cpp + rootservice.cpp + service.cpp + ssdpconnection.cpp + wanconnectionservice.cpp + xmlfunctions.cpp +) + +SET(kviupnp_MOC_HDRS + igdcontrolpoint.h + layer3forwardingservice.h + manager.h + rootservice.h + service.h + ssdpconnection.h + wanconnectionservice.h + xmlfunctions.h +) + +# After this call, files will be moc'ed to moc_kvi_*.cpp +QT4_WRAP_CPP(kviupnp_MOC_SRCS ${kviupnp_MOC_HDRS}) + +SET(kvi_module_name kviupnp) +INCLUDE(${CMAKE_SOURCE_DIR}/cmake/module.rules.txt) diff --git a/src/modules/upnp/igdcontrolpoint.cpp b/src/modules/upnp/igdcontrolpoint.cpp new file mode 100644 index 000000000..9c0dde69e --- /dev/null +++ b/src/modules/upnp/igdcontrolpoint.cpp @@ -0,0 +1,190 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + igdcontrolpoint.cpp - description + ------------------- + begin : Mon Jul 25 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#include <QDebug> + +#include "igdcontrolpoint.h" + +#include "rootservice.h" +#include "layer3forwardingservice.h" +#include "wanconnectionservice.h" + +namespace UPnP +{ + +#define InternetGatewayDeviceType "urn:schemas-upnp-org:device:InternetGatewayDevice:1" +#define Layer3ForwardingType "urn:schemas-upnp-org:service:Layer3Forwarding:1" + + +// The constructor +IgdControlPoint::IgdControlPoint(const QString &hostname, int port, const QString &rootUrl) + : QObject() + , forwardingService_(0) + , gatewayAvailable_(false) + , igdPort_(0) + , rootService_(0) + , wanConnectionService_(0) +{ + qDebug() << "CREATED UPnP::IgdControlPoint: Created control point" + << " url='" << hostname << ":" << port << "/" << rootUrl << "'." << endl; + qDebug() << "UPnP::IgdControlPoint: querying services..." << endl; + + + // Store device url + igdHostname_ = hostname; + igdPort_ = port; + + // Query the device for it's services + rootService_ = new RootService(igdHostname_, igdPort_, rootUrl); + connect(rootService_, SIGNAL(queryFinished(bool)), this, SLOT(slotDeviceQueried(bool))); +} + + + +// The destructor +IgdControlPoint::~IgdControlPoint() +{ + delete rootService_; + delete forwardingService_; + delete wanConnectionService_; + + qDebug() << "DESTROYED UPnP::IgdControlPoint [host=" << igdHostname_ << ", port=" << igdPort_ << "]" << endl; +} + + + +// Return the external IP address +QString IgdControlPoint::getExternalIpAddress() const +{ + // Do not expose wanConnectionService_; + if(wanConnectionService_ != 0) + { + return wanConnectionService_->getExternalIpAddress(); + } + else + { + return QString::null; + } +} + + + +// Initialize the control point +void IgdControlPoint::initialize() +{ + rootService_->queryDevice(); +} + + + +// Return true if a controlable gateway is available +bool IgdControlPoint::isGatewayAvailable() +{ + return gatewayAvailable_; +} + + + +// The IGD was queried for it's services +void IgdControlPoint::slotDeviceQueried(bool error) +{ + if(! error) + { + // Get the Layer3ForwardingService from the retrieved service list + ServiceParameters params = rootService_->getServiceByType(Layer3ForwardingType); + + if(! params.controlUrl.isNull()) + { + qDebug() << "UPnP::IgdControlPoint: Services found, " + << "querying service '" << params.serviceId << "' for port mapping service..." << endl; + + // Call the service + forwardingService_ = new Layer3ForwardingService(params); + connect(forwardingService_, SIGNAL(queryFinished(bool)), this, SLOT(slotWanConnectionFound(bool))); + forwardingService_->queryDefaultConnectionService(); + } + else + { + // TODO: error + } + } +} + + + +// A WAN connection service was found +void IgdControlPoint::slotWanConnectionFound(bool error) +{ + if(! error) + { + // Get the retreived service description + QString deviceUrn = forwardingService_->getConnectionDeviceUdn(); + QString serviceId = forwardingService_->getConnectionServiceId(); + ServiceParameters params = rootService_->getServiceById(serviceId, deviceUrn); + + if(! params.controlUrl.isNull()) + { + qDebug() << "UPnP::IgdControlPoint: wan/ipconnection service found, " + << "querying service '" << params.serviceId << "' for external ip address..." << endl; + + // Call the service + wanConnectionService_ = new WanConnectionService(params); + connect(wanConnectionService_, SIGNAL(queryFinished(bool)), this, SLOT(slotWanQueryFinished(bool))); + wanConnectionService_->queryExternalIpAddress(); + } + } + + // No longer need the forwarding service + forwardingService_->deleteLater(); + forwardingService_ = 0; +} + + + +// A WAN connection query was finished +void IgdControlPoint::slotWanQueryFinished(bool error) +{ + if(! error) + { + qDebug() << "IgdControlPoint: UPnP Gateway Device found." << endl; + gatewayAvailable_ = true; + } + else + { + // Just started, the request for the external IP failed. This should succeed, abort portation + qDebug() << "Requesting external IP address failed, leaving UPnP Gateway Device untouched." << endl; + } +} + + + +} // End of namespace diff --git a/src/modules/upnp/igdcontrolpoint.h b/src/modules/upnp/igdcontrolpoint.h new file mode 100644 index 000000000..d2df850d6 --- /dev/null +++ b/src/modules/upnp/igdcontrolpoint.h @@ -0,0 +1,100 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + igdcontrolpoint.cpp - description + ------------------- + begin : Mon Jul 25 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#ifndef UPNP_IGDCONTROLPOINT_H +#define UPNP_IGDCONTROLPOINT_H + +#include <qobject.h> + +namespace UPnP +{ + +class SsdpConnection; +class RootService; +class Layer3ForwardingService; +class WanConnectionService; + +/** + * A control point is a UPnP term for "client". + * It's the host that controls the UPnP device. + * This control point specifically handles Internet Gateway Devices (routers in UPnP terminology). + * It queries the device for its port mapping service (an instance of a WanIPConnection or WanPPPConnection service). + * Once the service is found, it can be used from the Manager class to configure port mappings. + * + * @author Diederik van der Boor + * @ingroup NetworkUPnP + */ +class IgdControlPoint : public QObject +{ + Q_OBJECT + + public: // public methods + + // The constructor + IgdControlPoint(const QString &hostname, int port, const QString &rootUrl); + // The destructor + virtual ~IgdControlPoint(); + + // Return the external IP address + QString getExternalIpAddress() const; + // Initialize the control point + void initialize(); + // Return true if a controlable gateway is available + bool isGatewayAvailable(); + + private slots: + // The IGD was queried for it's services + void slotDeviceQueried(bool error); + // A WAN connection service was found + void slotWanConnectionFound(bool error); + // A WAN connection query was finished + void slotWanQueryFinished(bool error); + + private: // private attibutes + // The forwarding service + Layer3ForwardingService *forwardingService_; + // Is a gateway available? + bool gatewayAvailable_; + // The host of the gateway + QString igdHostname_; + // The port of the gateway + int igdPort_; + // The root service + RootService *rootService_; + // The wan connection service + WanConnectionService *wanConnectionService_; +}; + + +} + +#endif diff --git a/src/modules/upnp/layer3forwardingservice.cpp b/src/modules/upnp/layer3forwardingservice.cpp new file mode 100644 index 000000000..bdd62d377 --- /dev/null +++ b/src/modules/upnp/layer3forwardingservice.cpp @@ -0,0 +1,137 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + layer3forwardingservice.cpp - description + ------------------- + begin : Mon Jul 25 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#include <QDebug> +#include <QStringList> + +#include "layer3forwardingservice.h" + +namespace UPnP +{ + +// The constructor +Layer3ForwardingService::Layer3ForwardingService(const ServiceParameters ¶ms) + : Service(params) +{ + +} + + +// The destructor +Layer3ForwardingService::~Layer3ForwardingService() +{ + +} + + + +// Get the device UDN of the default connection service +QString Layer3ForwardingService::getConnectionDeviceUdn() const +{ + return connectionDeviceUdn_; +} + + + +// Get the service ID of the default connection service +QString Layer3ForwardingService::getConnectionServiceId() const +{ + return connectionServiceId_; +} + + + +// The control point received a response to callAction() +void Layer3ForwardingService::gotActionResponse(const QString &responseType, const QMap<QString,QString> &resultValues) +{ + qDebug() << "UPnP::Layer3ForwardingService: Got action response" + << " type='" << responseType << "'." << endl; + + // Example: + // + // <m:GetDefaultConnectionServiceResponse xmlns:m="urn:schemas-upnp-org:service:Layer3Forwarding:1" > + // <NewDefaultConnectionService> + // (there is no white space between these parts!) + // uuid:UPnP-SpeedTouch510-1_00-90-D0-8E-A1-6F_WCDpppoa:WANConnectionDevice:1, + // urn:upnp-org:serviceId:wanpppc:pppoa + // </NewDefaultConnectionService> + // </m:GetDefaultConnectionServiceResponse> + + + if(responseType == "GetDefaultConnectionServiceResponse" ) + { + QString newService = resultValues["NewDefaultConnectionService"]; + QStringList serviceItems = QStringList::split(',', newService); + QString uuid; + QString urn; + + // Extract the uuid and urn from the NewDefaultConnectionService value + for(uint i = 0; i < serviceItems.count(); i++) + { + QString type = serviceItems[i].section(':', 0, 0); + if(type == "uuid") + { + // format: uuid:<id>:<class>:<ver> + connectionDeviceUdn_ = serviceItems[i].section(':', 0, 1); + } + else if(type == "urn") + { + connectionServiceId_ = serviceItems[i]; + } + else + { + qDebug() << "UPnP::Layer3ForwardingService - Unexpected section" + << " '" << type << "' encountered in NewDefaultConnectionService value." << endl; + } + } + + qDebug() << "UPnP::Layer3ForwardingService:" + << " udn='" << connectionDeviceUdn_ << "'" + << " serviceid='" << connectionServiceId_ << "'." << endl; + } + else + { + qDebug() << "UPnP::Layer3ForwardingService - Unexpected response type" + << " '" << responseType << "' encountered." << endl; + } +} + + + +// Query the Layer3Forwarding service for the default connection service +void Layer3ForwardingService::queryDefaultConnectionService() +{ + callAction("GetDefaultConnectionService"); +} + + +} diff --git a/src/modules/upnp/layer3forwardingservice.h b/src/modules/upnp/layer3forwardingservice.h new file mode 100644 index 000000000..18edde929 --- /dev/null +++ b/src/modules/upnp/layer3forwardingservice.h @@ -0,0 +1,84 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + layer3forwardingservice.h - description + ------------------- + begin : Mon Jul 25 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#ifndef UPNP_LAYER3FORWARDINGSERVICE_H +#define UPNP_LAYER3FORWARDINGSERVICE_H + +#include "service.h" + +namespace UPnP { + +/** + * The Layer3Forwarding service is used to query a Internet Gateway Device (router in UPnP terms) + * for it's WanConnection service. This can be an instance of the WanIPConnection or WanPPPConnection service, + * which is implemented by the WanConnectionService class. + * The WanIPConnection/WanPPPConnection service can be used to configure the external connection settings and port mappings of the router. + * The Layer3Forwarding service itself is resolved by the RootService class. + * + * @author Diederik van der Boor + * @ingroup NetworkUPnP + */ +class Layer3ForwardingService : public Service +{ + public: // public methods + + // The constructor + Layer3ForwardingService(const ServiceParameters ¶ms); + // The destructor + virtual ~Layer3ForwardingService(); + + // Get the device UDN of the default connection service + QString getConnectionDeviceUdn() const; + // Get the service ID of the default connection service + QString getConnectionServiceId() const; + + // Query the Layer3Forwarding service for the default connection service + void queryDefaultConnectionService(); + + + protected: // protected methods + + // The control point received a response to callAction() + virtual void gotActionResponse(const QString &responseType, const QMap<QString,QString> &resultValues); + + + private: // private attributes + + // The device UDN of the default connection service + QString connectionServiceId_; + // The service ID of the default connection service + QString connectionDeviceUdn_; +}; + +} + +#endif diff --git a/src/modules/upnp/libkviupnp.cpp b/src/modules/upnp/libkviupnp.cpp new file mode 100644 index 000000000..99fa7a795 --- /dev/null +++ b/src/modules/upnp/libkviupnp.cpp @@ -0,0 +1,77 @@ +//============================================================================= +// +// File : libkviupnp.cpp +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This math is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_module.h" +#include "kvi_string.h" + +#include "manager.h" + +UPnP::Manager* p_manager = 0; + + +static bool upnp_kvs_fnc_getExternalIpAddress(KviKvsModuleFunctionCall * c) +{ + QString buffer; + + if(p_manager) + buffer = p_manager->getExternalIpAddress(); + + c->returnValue()->setString(buffer); + return true; +} + +static bool upnp_kvs_cmd_test(KviKvsModuleCommandCall * c) +{ + return true; +} + +static bool upnp_module_init(KviModule * m) +{ + p_manager = UPnP::Manager::instance(); + //p_manager->initialize(); + + KVSM_REGISTER_FUNCTION(m,"getExternalIpAddress",upnp_kvs_fnc_getExternalIpAddress); + KVSM_REGISTER_SIMPLE_COMMAND(m,"test",upnp_kvs_cmd_test); + + return true; +} + +static bool upnp_module_cleanup(KviModule *m) +{ + delete p_manager; + p_manager = 0; + return true; +} + +KVIRC_MODULE( + "Upnp", // module name + "4.0.0", // module version + "Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net),", + "Universal Plug and Play", + upnp_module_init, + 0, + 0, + upnp_module_cleanup +) diff --git a/src/modules/upnp/manager.cpp b/src/modules/upnp/manager.cpp new file mode 100644 index 000000000..127e0a7d9 --- /dev/null +++ b/src/modules/upnp/manager.cpp @@ -0,0 +1,154 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + manager.cpp - description + ------------------- + begin : Fri Aug 05 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#include "manager.h" + +#include "igdcontrolpoint.h" +#include "ssdpconnection.h" + +#include <QDebug> +#include <QTimer> + + +namespace UPnP +{ + +// Set the static variable +Manager* Manager::instance_(0); + + +// The constructor +Manager::Manager() + : activeIgdControlPoint_(0) + , broadcastFailed_(false) + , ssdpConnection_(0) + , ssdpTimer_(0) +{ + +} + + + +// The destructor +Manager::~Manager() +{ + delete ssdpTimer_; + delete ssdpConnection_; + instance_ = 0; // Unregister the instance +} + + + +// Initialize the manager, detect all devices +void Manager::initialize() +{ + qDebug() << "UPnP::Manager: Initiating a broadcast to detect UPnP devices..." << endl; + + + // Create the SSDP object to detect devices + ssdpConnection_ = new SsdpConnection(); + connect(ssdpConnection_, SIGNAL( deviceFound(const QString&,int,const QString&) ) , + this, SLOT( slotDeviceFound(const QString&,int,const QString&) ) ); + + // Create a timer + ssdpTimer_ = new QTimer(this); + connect(ssdpTimer_, SIGNAL(timeout()), this, SLOT(slotBroadcastTimeout())); + + // Start a UPnP broadcast + broadcastFailed_ = false; + ssdpConnection_->queryDevices(); + ssdpTimer_->start(2000, true); +} + + + +// Return the instance of the manager class +Manager * Manager::instance() +{ + // Create when it's required + if(instance_ == 0) + { + instance_ = new Manager(); + instance_->initialize(); + } + + return instance_; +} + + + +// Return the external IP address +QString Manager::getExternalIpAddress() const +{ + // Do not expose activeIgd_; + return (activeIgdControlPoint_ != 0 ? activeIgdControlPoint_->getExternalIpAddress() : QString::null); +} + + + +// Return true if a controlable gateway is available +bool Manager::isGatewayAvailable() +{ + return (activeIgdControlPoint_ != 0 && + activeIgdControlPoint_->isGatewayAvailable()); +} + + + +// The broadcast failed +void Manager::slotBroadcastTimeout() +{ +qDebug() << "UPnP::Manager: Timeout, no broadcast response received!" << endl; + + broadcastFailed_ = true; +} + + + +// A device was discovered by the SSDP broadcast +void Manager::slotDeviceFound(const QString &hostname, int port, const QString &rootUrl) +{ +qDebug() << "UPnP::Manager: Device found, initializing IgdControlPoint to query it." << endl; + + IgdControlPoint *controlPoint = new IgdControlPoint(hostname, port, rootUrl); + igdControlPoints_.append(controlPoint); + + if(activeIgdControlPoint_ == 0) + { + activeIgdControlPoint_ = controlPoint; + activeIgdControlPoint_->initialize(); + } +} + + + +} // end of namespace diff --git a/src/modules/upnp/manager.h b/src/modules/upnp/manager.h new file mode 100644 index 000000000..b42b1c9ef --- /dev/null +++ b/src/modules/upnp/manager.h @@ -0,0 +1,110 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + manager.h - description + ------------------- + begin : Fri Aug 05 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#ifndef UPNPMANAGER_H +#define UPNPMANAGER_H + +#include <QObject> +#include "kvi_pointerlist.h" + +class QTimer; + +namespace UPnP +{ + +class IgdControlPoint; +class SsdpConnection; + + +/** + * The manager class is the public interface used by other networking classes. + * It's implemented as singleton to provide easy access by other classes. + * Devices are automatically detected at start-up, and maintained by this class. + * Underneath, the actual work is done by the SsdpConnection and IgdControlPoint classes. + * + * @author Diederik van der Boor + * @ingroup NetworkUPnP + */ +class Manager : public QObject +{ + Q_OBJECT + + public: // public methods + + // The destructor + virtual ~Manager(); + + // Return the external IP address + QString getExternalIpAddress() const; + + // Return the instance of the manager class + static Manager * instance(); + + // Return true if a controlable gateway is available + bool isGatewayAvailable(); + + private slots: + // The broadcast failed + void slotBroadcastTimeout(); + // A device was discovered by the SSDP broadcast + void slotDeviceFound(const QString &hostname, int port, const QString &rootUrl); + + + private: // private methods + // The constructor (it's a singleton) + Manager(); + // Disable the copy constructor + Manager(const Manager &); + // Disable the assign operator + Manager& operator=(const Manager&); + // Initialize the manager, detect all devices + void initialize(); + + private: + // The active control point we're working with + IgdControlPoint *activeIgdControlPoint_; + // True if the broadcast failed + bool broadcastFailed_; + // The instance of the singleton class + static Manager *instance_; + // A list of all detected gateway devices + KviPointerList<IgdControlPoint> igdControlPoints_; + // The SSDP connection to find all UPnP devices + SsdpConnection *ssdpConnection_; + // The timer to detect a broadcast timeout + QTimer *ssdpTimer_; +}; + + +} // End of namespace + +#endif diff --git a/src/modules/upnp/rootservice.cpp b/src/modules/upnp/rootservice.cpp new file mode 100644 index 000000000..57de03b11 --- /dev/null +++ b/src/modules/upnp/rootservice.cpp @@ -0,0 +1,281 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + rootservice.cpp - description + ------------------- + begin : Mon Jul 25 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#include "rootservice.h" +#include "xmlfunctions.h" + +#include <QDebug> + +namespace UPnP +{ + + // Example message result: + // + // <root xmlns="urn:schemas-upnp-org:device-1-0" > + // <specVersion> + // <major>1</major> + // <minor>0</minor> + // </specVersion> + // <URLBase>http://10.0.0.138</URLBase> + // <device> + // <deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType> + // <friendlyName>SpeedTouch 510 (0313QZ6S2)</friendlyName> + // <manufacturer>THOMSON multimedia</manufacturer> + // <manufacturerURL>http://www.thomson-multimedia.com</manufacturerURL> + // <modelDescription>DSL Internet Gateway</modelDescription> + // <modelName>SpeedTouch</modelName> + // <modelNumber>510</modelNumber> + // <modelURL>http://www.speedtouch.com</modelURL> + // <serialNumber>0313QZ6S2</serialNumber> + // <UDN>uuid:UPnP-SpeedTouch510-1_00-90-D0-8E-A1-6F</UDN> + // <presentationURL>/index.htm</presentationURL> + // <serviceList> + // <service> + // <serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType> + // <serviceId>urn:upnp-org:serviceId:layer3f</serviceId> + // <controlURL>/upnp/control/layer3f</controlURL> + // <eventSubURL>/upnp/event/layer3f</eventSubURL> + // <SCPDURL>/Layer3Forwarding.xml</SCPDURL> + // </service> + // </serviceList> + // <deviceList> + // <device> + // <deviceType>urn:schemas-upnp-org:device:LANDevice:1</deviceType> + // <friendlyName>LANDevice</friendlyName> + // <manufacturer>THOMSON multimedia</manufacturer> + // <modelName>SpeedTouch</modelName> + // <serialNumber>0313QZ6S2</serialNumber> + // <UDN>uuid:UPnP-SpeedTouch510-1_00-90-D0-8E-A1-6F_LD</UDN> + // <serviceList> + // <service> + // <serviceType>urn:schemas-upnp-org:service:LANHostConfigManagement:1</serviceType> + // <serviceId>urn:upnp-org:serviceId:lanhcm</serviceId> + // <controlURL>/upnp/control/lanhcm</controlURL> + // <eventSubURL>/upnp/event/lanhcm</eventSubURL> + // <SCPDURL>/LANHostConfigManagement.xml</SCPDURL> + // </service> + // </serviceList> + // </device> + // <device> + // <deviceType>urn:schemas-upnp-org:device:WANDevice:1</deviceType> + // <friendlyName>WANDevice</friendlyName> + // <manufacturer>THOMSON multimedia</manufacturer> + // <modelName>SpeedTouch</modelName> + // <serialNumber>0313QZ6S2</serialNumber> + // <UDN>uuid:UPnP-SpeedTouch510-1_00-90-D0-8E-A1-6F_WD</UDN> + // <serviceList> + // <service> + // <serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType> + // <serviceId>urn:upnp-org:serviceId:wancic</serviceId> + // <controlURL>/upnp/control/wancic</controlURL> + // <eventSubURL>/upnp/event/wancic</eventSubURL> + // <SCPDURL>/WANCommonInterfaceConfig.xml</SCPDURL> + // </service> + // </serviceList> + // <deviceList> + // <device> + // <deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType> + // <friendlyName>WANConnectionDevice</friendlyName> + // <manufacturer>THOMSON multimedia</manufacturer> + // <modelName>SpeedTouch</modelName> + // <serialNumber>0313QZ6S2</serialNumber> + // <UDN>uuid:UPnP-SpeedTouch510-1_00-90-D0-8E-A1-6F_WCDpppoa</UDN> + // <serviceList> + // <service> + // <serviceType>urn:schemas-upnp-org:service:WANDSLLinkConfig:1</serviceType> + // <serviceId>urn:upnp-org:serviceId:wandsllc:pppoa</serviceId> + // <controlURL>/upnp/control/wandsllcpppoa</controlURL> + // <eventSubURL>/upnp/event/wandsllcpppoa</eventSubURL> + // <SCPDURL>/WANDSLLinkConfig.xml</SCPDURL> + // </service> + // <service> + // <serviceType>urn:schemas-upnp-org:service:WANPPPConnection:1</serviceType> + // <serviceId>urn:upnp-org:serviceId:wanpppc:pppoa</serviceId> + // <controlURL>/upnp/control/wanpppcpppoa</controlURL> + // <eventSubURL>/upnp/event/wanpppcpppoa</eventSubURL> + // <SCPDURL>/WANPPPConnection.xml</SCPDURL> + // </service> + // </serviceList> + // </device> + // </deviceList> + // </device> + // </deviceList> + // </device> + // </root> + + +// The contructor +RootService::RootService(const QString &hostname, int port, + const QString &rootUrl) + : Service(hostname, port, rootUrl) + , hostname_(hostname) + , port_(port) +{ +} + + +// The destructor +RootService::~RootService() +{ + +} + + + +// Recursively add all devices and embedded devices to the deviceServices_ map +void RootService::addDeviceServices(const QDomNode &device) +{ +qDebug() << "UPnP Discovered device " << XmlFunctions::getNodeValue(device, "/UDN") << endl; + + // Insert the given device node + // The "key" is the device/UDN tag, the value is a list of device/serviceList/service nodes + deviceServices_.insert(XmlFunctions::getNodeValue(device, "/UDN"), + device.namedItem("serviceList").childNodes()); + + // Find all embedded device nodes + QDomNodeList embeddedDevices = device.namedItem("deviceList").childNodes(); + for(uint i = 0; i < embeddedDevices.count(); i++) + { + if(embeddedDevices.item(i).nodeName() != "device") continue; + addDeviceServices(embeddedDevices.item(i)); + } +} + + + +// Return the device type +QString RootService::getDeviceType() const +{ + return deviceType_; +} + + + +// Return a service from the cached root device entry +ServiceParameters RootService::getServiceById(const QString &serviceId) const +{ + // Get a /root/device/serviceList/service/ tag + return getServiceById(serviceId, rootUdn_); +} + + + +// Return a service from a cached embedded device entry +ServiceParameters RootService::getServiceById(const QString &serviceId, const QString &deviceUdn) const +{ + // Get a /root/device/deviceList/device/.../serviceList/service/serviceId tag + QDomNode service = XmlFunctions::getNodeChildByKey( deviceServices_[deviceUdn], "serviceId", serviceId ); + + // Initialize a ServiceParameters struct + ServiceParameters params; + + if(! service.isNull()) + { + params.hostname = hostname_; + params.port = port_; + params.controlUrl = XmlFunctions::getNodeValue(service, "/controlURL"); + params.scdpUrl = XmlFunctions::getNodeValue(service, "/SCDPURL"); + params.serviceId = XmlFunctions::getNodeValue(service, "/serviceId"); + } else + { + qWarning() << "UPnP::RootService::getServiceById -" + << " id '" << serviceId << "' not found for device '" << deviceUdn << "'." << endl; + } + + return params; +} + + + +// Return a service from the cached root device entry +ServiceParameters RootService::getServiceByType(const QString &serviceType) const +{ + // Get a /root/device/serviceList/service/ tag + return getServiceByType(serviceType, rootUdn_); +} + + + +// Return a service from a cached embedded device entry +ServiceParameters RootService::getServiceByType(const QString &serviceType, const QString &deviceUdn) const +{ + // Get a /root/device/deviceList/device/.../serviceList/service/serviceType tag + QDomNode service = XmlFunctions::getNodeChildByKey( deviceServices_[deviceUdn], "serviceType", serviceType ); + + // Initialize a ServiceParameters struct + ServiceParameters params; + + if(! service.isNull()) + { + params.hostname = hostname_; + params.port = port_; + params.controlUrl = XmlFunctions::getNodeValue(service, "/controlURL"); + params.scdpUrl = XmlFunctions::getNodeValue(service, "/SCDPURL"); + params.serviceId = XmlFunctions::getNodeValue(service, "/serviceId"); + } else + { + qWarning() << "UPnP::RootService::getServiceByType -" + << " type '" << serviceType << "' not found for device '" << deviceUdn << "'." << endl; + } + + return params; +} + + + +// The control point received a response to callInformationUrl() +void RootService::gotInformationResponse(const QDomNode &response) +{ + // Register all device UDN nodes for later + deviceServices_.clear(); + addDeviceServices( XmlFunctions::getNode(response, "/device") ); + + // Fetch the required data + deviceType_ = XmlFunctions::getNodeValue(response, "/device/deviceType"); + rootUdn_ = XmlFunctions::getNodeValue(response, "/device/UDN"); + + // The rootUdn_ is used to retrieve + // the /root/device/serviceList/service + // nodes from the deviceServices_ map +} + + + +// Query the device for its service list +void RootService::queryDevice() +{ + callInformationUrl(); +} + + + +} // end of namespae diff --git a/src/modules/upnp/rootservice.h b/src/modules/upnp/rootservice.h new file mode 100644 index 000000000..ba2999478 --- /dev/null +++ b/src/modules/upnp/rootservice.h @@ -0,0 +1,100 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + rootservice.h - description + ------------------- + begin : Mon Jul 25 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#ifndef UPNP_ROOTSERVICE_H +#define UPNP_ROOTSERVICE_H + +#include "service.h" + + +namespace UPnP +{ + +/** + * The services of a device can be retrieved using the device root service. + * The URL of the root service is returned by an SSDP broadcast. + * The root service returns the meta information and list of services the device supports. + * + * @author Diederik van der Boor + * @ingroup NetworkUPnP + */ +class RootService : public Service +{ + public: // public methods + + // The constructor + RootService(const QString &hostname, int port, const QString &rootUrl); + // The destructor + virtual ~RootService(); + + // Return the device type + QString getDeviceType() const; + + // Return a service from the cached root device entry + ServiceParameters getServiceById(const QString &serviceId) const; + // Return a service from a cached embedded device entry + ServiceParameters getServiceById(const QString &serviceId, const QString &deviceUdn) const; + // Return a service from the cached root device entry + ServiceParameters getServiceByType(const QString &serviceType) const; + // Return a service from a cached embedded device entry + ServiceParameters getServiceByType(const QString &serviceType, const QString &deviceUdn) const; + + // Query the device for its service list + void queryDevice(); + + + protected: // Protected methods + // The control point received a response to callInformationUrl() + virtual void gotInformationResponse(const QDomNode &response); + + + private: // Private methods + // Recursively add all devices and embedded devices to the deviceServices_ map + void addDeviceServices(const QDomNode &device); + + + private: + // The device type + QString deviceType_; + // A collection of all services provided by the device + QMap<QString,QDomNodeList> deviceServices_; + // The hostname of the device + QString hostname_; + // The port of the device + int port_; + // The udn of the root device + QString rootUdn_; +}; + +} + +#endif diff --git a/src/modules/upnp/service.cpp b/src/modules/upnp/service.cpp new file mode 100644 index 000000000..055b968de --- /dev/null +++ b/src/modules/upnp/service.cpp @@ -0,0 +1,286 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + service.cpp - description + ------------------- + begin : Sun Jul 24 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#include "service.h" +#include "xmlfunctions.h" + +#include <QDebug> +#include <QHttp> +#include <QByteArray> + +// This implementation was created with the help of the following documentation: +// http://www.upnp.org/standardizeddcps/documents/UPnP_IGD_1.0.zip +// http://zacbowling.com/upnp/ +// http://www.knoxscape.com/Upnp/NAT.htm +// http://www.artima.com/spontaneous/upnp_digihome2.html + + +namespace UPnP +{ + + +// The constructor for information services +Service::Service(const QString &hostname, int port, const QString &informationUrl) + : informationUrl_(informationUrl) + , pendingRequests_(0) +{ + http_ = new QHttp(hostname, port); + connect(http_, SIGNAL( requestFinished(int,bool) ) , + this, SLOT( slotRequestFinished(int,bool) ) ); + +qDebug() << "UPnP::Service: Created information service url='" << informationUrl_ << "'." << endl; +} + + +// The constructor for action services +Service::Service(const ServiceParameters ¶ms) + : controlUrl_(params.controlUrl) + , informationUrl_(params.scdpUrl) + , pendingRequests_(0) + , serviceId_(params.serviceId) +{ + http_ = new QHttp(params.hostname, params.port); + connect(http_, SIGNAL( requestFinished(int,bool) ) , + this, SLOT( slotRequestFinished(int,bool) ) ); + + qDebug() << "CREATED UPnP::Service: url='" << controlUrl_ << "' id='" << serviceId_ << "'." << endl; +} + + + +// The destructor +Service::~Service() +{ + qDebug() << "DESTROYED UPnP::Service [url=" << controlUrl_ << ", id=" << serviceId_ << "]" << endl; + + delete http_; +} + + + +// Makes a UPnP action request +// TODO: rename to callMethod / callSoapMethod +int Service::callAction(const QString &actionName) +{ + return callActionInternal(actionName, 0); +} + + + +// Makes a UPnP action request +int Service::callAction(const QString &actionName, const QMap<QString,QString> &arguments) +{ + return callActionInternal(actionName, &arguments); +} + + + +// Makes a UPnP action request (keeps pointers from the external interface) +int Service::callActionInternal(const QString &actionName, const QMap<QString,QString> *arguments) +{ + qDebug() << "UPnP::Service: calling remote prodecure '" << actionName << "'." << endl; + + // Create the data message + QString soapMessage = "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"" + " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<s:Body>" + "<u:" + actionName + " xmlns:u=\"" + serviceId_ + "\">"; + + // Do we have any arguments? + if(arguments != 0) + { + // Add the arguments + QMap<QString,QString>::const_iterator it; + for(it = arguments->begin(); it != arguments->end(); ++it) + { + QString argumentName = it.key(); + soapMessage += "<" + argumentName + ">" + it.data() + "</" + argumentName + ">"; + } + } + + // Add the closing tags + soapMessage += "</u:" + actionName + "></s:Body></s:Envelope>"; + + // Get an utf8 encoding string + QByteArray content = soapMessage.utf8(); + + // Create the HTTP header + QHttpRequestHeader header("POST", controlUrl_); + header.setContentType("text/xml; charset=\"utf-8\""); + header.setContentLength(content.size()); + header.setValue("SoapAction", serviceId_ + "#" + actionName); + + // Send the POST request + pendingRequests_++; + return http_->request(header, content); +} + + + +// Makes a UPnP service request +// TODO: rename to downloadFile() +int Service::callInformationUrl() +{ + qDebug() << "UPnP::Service: requesting file '" << informationUrl_ << "'." << endl; + + // Send the GET request + // TODO: User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1) + pendingRequests_++; + return http_->get(informationUrl_); +} + + + +// Get the number of pending requests +int Service::getPendingRequests() const +{ + return pendingRequests_; +} + + +// The control point received an action failure indication +void Service::gotActionErrorResponse(const QDomNode &response) +{ + QString faultString = XmlFunctions::getNodeValue(response, "/faultstring"); + QString errorCode = XmlFunctions::getNodeValue(response, "/detail/" + faultString + "/errorCode"); + QString errorDescription = XmlFunctions::getNodeValue(response, "/detail/" + faultString + "/errorDescription"); + qWarning() << "UPnP::Service - Action failed: " << errorCode << " " << errorDescription << endl; +} + + + +// The control point received a response to callAction() +void Service::gotActionResponse(const QString &responseType, const QMap<QString,QString> &/*resultValues*/) +{ + qWarning() << "UPnP::Service - Action response '" << responseType << "' is not handled." << endl; +} + + + +// The control point received a response to callInformationUrl() +void Service::gotInformationResponse(const QDomNode &response) +{ + QString rootTagName = response.nodeName(); + qWarning() << "UPnP::Service - Service response (with root '" << rootTagName << "') is not handled." << endl; +} + + + +// The QHttp object retrieved data. +void Service::slotRequestFinished(int /*id*/, bool error) +{ + qDebug() << "UPnP::Service: Got HTTP response." << endl; + + if(! error) + { + // Not sure why this happens + if(http_->bytesAvailable() > 0) + { + // Get the XML content + QByteArray response = http_->readAll(); + QDomDocument xml; + + // TODO: handle 401 Authorisation required messages + + // Parse the XML + QString errorMessage; + error = ! xml.setContent(response, false, &errorMessage); + + if(! error) + { + // Determine how to process the data + if(xml.namedItem("s:Envelope").isNull()) + { + qDebug() << "UPnP::Service: Plain XML detected, calling gotInformationResponse()." << endl; + // No SOAP envelope found, this is a normal response to callService() + gotInformationResponse( xml.lastChild() ); + } + else + { + qDebug() << xml.toString() << endl; + // Got a SOAP message response to callAction() + QDomNode resultNode = XmlFunctions::getNode(xml, "/s:Envelope/s:Body").firstChild(); + + error = (resultNode.nodeName() == "s:Fault"); + + if(! error) + { + if(resultNode.nodeName().startsWith("m:")) + { + qDebug() << "UPnP::Service: SOAP Envelope detected, calling gotActionResponse()." << endl; + // Action success, return SOAP body + QMap<QString,QString> resultValues; + + // Parse all parameters + // It's possible to pass the entire QDomNode object to the gotActionResponse() + // function, but this is somewhat nicer, and reduces code boat in the subclasses + QDomNodeList children = resultNode.childNodes(); + for(uint i = 0; i < children.count(); i++) + { + QString key = children.item(i).nodeName(); + resultValues[ key ] = children.item(i).toElement().text(); + } + + // Call the gotActionResponse() + gotActionResponse(resultNode.nodeName().mid(2), resultValues); + } + } + else + { + qDebug() << "UPnP::Service: SOAP Error detected, calling gotActionResponse()." << endl; + + // Action failed + gotActionErrorResponse(resultNode); + } + } + } + else + { + qWarning() << "UPnP::Service - XML Parsing failed: " << errorMessage << endl; + } + + // Only emit when bytes>0 + pendingRequests_--; + emit queryFinished(error); + } + } + else + { + qWarning() << "UPnP::Service - HTTP Request failed: " << http_->errorString() << endl; + pendingRequests_--; + emit queryFinished(error); + } + +} + + +} // end of namespace diff --git a/src/modules/upnp/service.h b/src/modules/upnp/service.h new file mode 100644 index 000000000..9e9e72af6 --- /dev/null +++ b/src/modules/upnp/service.h @@ -0,0 +1,128 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + service.h - description + ------------------- + begin : Sun Jul 24 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#ifndef UPNP_CONTROLPOINT_H +#define UPNP_CONTROLPOINT_H + +#include <qobject.h> +#include <qdom.h> +#include <qmap.h> +#include <qstring.h> + +class QHttp; + +namespace UPnP +{ + +// A datablock to make the exchange +// of service information easier +struct ServiceParameters +{ + QString hostname; + int port; + QString scdpUrl; + QString controlUrl; + QString serviceId; +}; + + +/** + * This base class to implement calls to a UPnP-enabled device. + * In UPnP terminology, a client is called a Control Point, and a service is a UPnP device. + * + * This class different kind of calls. + * An information request queries the service for data with a HTTP GET. + * An action request issues a HTTP POST call to the given service. + * + * @author Diederik van der Boor + * @ingroup NetworkUPnP + */ +class Service : public QObject +{ + Q_OBJECT + + public: // public methods + // The constructor for the root service + Service(const QString &hostname, int port, + const QString &informationUrl); + // The constructor for action services + Service(const ServiceParameters ¶ms); + // The destructor + virtual ~Service(); + + // Get the number of pending requests + int getPendingRequests() const; + + + protected: // Protected methods + // Makes a UPnP action request + int callAction(const QString &actionName); + // Makes a UPnP action request + int callAction(const QString &actionName, const QMap<QString,QString> &arguments); + // Makes a UPnP service request + int callInformationUrl(); + + // The control point received an action failure indication + virtual void gotActionErrorResponse(const QDomNode &response); + // The control point received a response to callAction() + virtual void gotActionResponse(const QString &responseType, const QMap<QString,QString> &resultValues); + // The control point received a response to callInformationUrl() + virtual void gotInformationResponse(const QDomNode &response); + + private slots: + // The QHttp object retrieved data. + void slotRequestFinished(int id, bool error); + + private: + // Makes a UPnP action request (keeps pointers from the external interface) + int callActionInternal(const QString &actionName, const QMap<QString,QString> *arguments); + + private: + // The URL to control the service + QString controlUrl_; + // The HTTP requester + QHttp *http_; + // The URL to request service information + QString informationUrl_; + // The number of pending queries/actions + int pendingRequests_; + // The ID of the service + QString serviceId_; + + signals: + // Called when a query completed + void queryFinished(bool error); +}; + +} + +#endif diff --git a/src/modules/upnp/ssdpconnection.cpp b/src/modules/upnp/ssdpconnection.cpp new file mode 100644 index 000000000..1e9fd08a2 --- /dev/null +++ b/src/modules/upnp/ssdpconnection.cpp @@ -0,0 +1,134 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + ssdpconnection.cpp - description + ------------------- + begin : Fri Jul 29 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#include "ssdpconnection.h" + +#include <QHostAddress> +#include <QUdpSocket> + +#include <QByteArray> +#include <QDebug> +#include <QUrl> + +namespace UPnP +{ + +SsdpConnection::SsdpConnection() +: QObject() +{ + socket_ = new QUdpSocket(); + connect(socket_, SIGNAL(readyRead()), this, SLOT(slotDataReceived())); +} + +SsdpConnection::~SsdpConnection() +{ + if(socket_ != 0) + { + socket_->close(); + delete socket_; + } +} + + + +// Data was received by the socket +void SsdpConnection::slotDataReceived() +{ + qDebug() << "UPnP::SsdpConnection: received " << socket_->bytesAvailable() << " bytes." << endl; + + // Get the HTTP-like content + // TODO: How to handle multiple packets arriving from different devices? + QByteArray response = socket_->readAll(); + + // Response from my Acatel router: + // + // HTTP/1.1 200 OK + // CACHE-CONTROL:max-age=1800 + // EXT: + // LOCATION:http://10.0.0.138:80/IGD.xml + // SERVER:SpeedTouch 510 4.0.2.0.0 UPnP/1.0 (0313QZ6S2) + // ST:upnp:rootdevice + // USN:uuid:UPnP-SpeedTouch510-1_00-90-D0-8E-A1-6F::upnp:rootdevice + // + + QString sspdResponse = QString::fromUtf8(response.data(), response.size()); + + // Find the location field manually, MimeMessage is not required + int locationStart = sspdResponse.find("LOCATION:",0,false); // case insensitive + int locationEnd = sspdResponse.find("\r\n",locationStart); + + locationStart += 9; // length of field name + QString location = sspdResponse.mid(locationStart, locationEnd - locationStart); + + // Parse the URL syntax using KURL + QUrl url(location); + + // Emit success + emit deviceFound(url.host(), url.port(), url.path()); +} + + +// Send a broadcast to detect all devices +void SsdpConnection::queryDevices(int bindPort) +{ + qDebug() << "UPnP::SsdpConnection: Sending broadcast packet." << endl; + + // Send a packet to a broadcast address + QHostAddress address("239.255.255.250"); + + QString data = "M-SEARCH * HTTP/1.1\r\n" + "Host:239.255.255.250:1900\r\n" + "ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n" + "Man:\"ssdp:discover\"\r\n" + "MX:3\r\n" + "\r\n"; + + // Bind the socket to a certain port + bool success = socket_->bind(address, bindPort); + if(! success) + { + qDebug() << "UPnP::SsdpConnection: Failed to bind to port " << bindPort << "." << endl; + } + + // Send the data + QByteArray dataBlock = data.utf8(); + int bytesWritten = socket_->writeDatagram(dataBlock.data(), dataBlock.size(), address, 1900); + + if(bytesWritten == -1) + { + qDebug() << "UPnP::SsdpConnection: Failed to send the UPnP broadcast packet." << endl; + } +} + + + +} // end of namespace diff --git a/src/modules/upnp/ssdpconnection.h b/src/modules/upnp/ssdpconnection.h new file mode 100644 index 000000000..19ecddd09 --- /dev/null +++ b/src/modules/upnp/ssdpconnection.h @@ -0,0 +1,78 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + ssdpconnection.h - description + ------------------- + begin : Fri Jul 29 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#ifndef UPNP_SSDPCONNECTION_H +#define UPNP_SSDPCONNECTION_H + +#include <QObject> + +class QUdpSocket; + +namespace UPnP +{ + + +/** + * The Simple Service Discovery Protocol allows UPnP clients + * to discover UPnP devices on a network. + * This is achieved by broadcasting a HTTP-like message over UDP. + * Devices can respond with their location and root service name. + * The RootService class uses this information to query the device for + * it's meta information and service list. + * + * @author Diederik van der Boor + * @ingroup NetworkUPnP + */ +class SsdpConnection : public QObject +{ + Q_OBJECT + + public: + SsdpConnection(); + virtual ~SsdpConnection(); + + void queryDevices(int bindPort = 1500); + + private slots: + // Data was received by the socket + void slotDataReceived(); + + private: + QUdpSocket *socket_; + signals: + // Called when a query completed + void deviceFound(const QString &hostname, int port, const QString &rootUrl); +}; + +} + +#endif diff --git a/src/modules/upnp/wanconnectionservice.cpp b/src/modules/upnp/wanconnectionservice.cpp new file mode 100644 index 000000000..3b61241d7 --- /dev/null +++ b/src/modules/upnp/wanconnectionservice.cpp @@ -0,0 +1,192 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + wanconnectionservice.cpp - description + ------------------- + begin : Mon Jul 25 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#include "wanconnectionservice.h" +#include <QDebug> + +namespace UPnP +{ + + +// The constructor +WanConnectionService::WanConnectionService(const ServiceParameters ¶ms) + : Service(params) + , natEnabled_(false) +{ + +} + + +// The destructor +WanConnectionService::~WanConnectionService() +{ + +} + + + +// Add a port mapping +void WanConnectionService::addPortMapping(const QString &protocol, const QString &remoteHost, int externalPort, + const QString &internalClient, int internalPort, const QString &description, + bool enabled, int leaseDuration) +{ + // TODO: this still needs to be tested + QMap<QString,QString> arguments; + arguments["NewProtocol"] = protocol; + arguments["NewRemoteHost"] = remoteHost; + arguments["NewExternalPort"] = QString::number(externalPort); + arguments["NewInternalClient"] = internalClient; + arguments["NewInternalPort"] = QString::number(internalPort); + arguments["NewPortMappingDescription"] = description; + arguments["NewEnabled"] = QString::number(enabled ? 1 : 0); + arguments["NewLeaseDuration"] = QString::number(leaseDuration); + callAction("AddPortMapping", arguments); +} + + + +// Delete a port mapping +void WanConnectionService::deletePortMapping(const QString &protocol, const QString &remoteHost, int externalPort) +{ + // TODO: this still needs to be tested + QMap<QString,QString> arguments; + arguments["NewProtocol"] = protocol; + arguments["NewRemoteHost"] = remoteHost; + arguments["NewExternalPort"] = QString::number(externalPort); + callAction("DeletePortMapping", arguments); +} + + + +// Return the external IP address +QString WanConnectionService::getExternalIpAddress() const +{ + return externalIpAddress_; +} + + + +// Return true if NAT is enabled +bool WanConnectionService::getNatEnabled() const +{ + return natEnabled_; +} + + + +// Return the port mappings +const KviPointerList<PortMapping>& WanConnectionService::getPortMappings() const +{ + return portMappings_; +} + + + +// The control point received a response to callAction() +void WanConnectionService::gotActionResponse(const QString &responseType, const QMap<QString,QString> &resultValues) +{ + qDebug() << "UPnP::WanConnectionService: Parsing action response:" + << " type='" << responseType << "'." << endl; + + // Check the message type + if(responseType == "GetExternalIPAddressResponse") + { + // Get the external IP address from the response + externalIpAddress_ = resultValues["NewExternalIPAddress"]; + + qDebug() << "UPnP::WanConnectionService: externalIp='" << externalIpAddress_ << "'." << endl; + } + else if(responseType == "GetNATRSIPStatusResponse") + { + // Get the nat status from the response + natEnabled_ = (resultValues["NewNATEnabled"] == "1"); + + qDebug() << "UPnP::WanConnectionService: natEnabled=" << natEnabled_ << "." << endl; + } + else if(responseType == "GetGenericPortMappingEntryResponse") + { + // Find a place to store the data + PortMapping *map = new PortMapping; + + // Get the port mapping data from the response + map->enabled = (resultValues["NewEnabled"] == "1"); + map->externalPort = resultValues["NewExternalPort"].toInt(); + map->internalClient = resultValues["NewInternalClient"]; + map->internalPort = resultValues["NewInternalPort"].toInt(); + map->leaseDuration = resultValues["NewLeaseDuration"].toInt(); + map->description = resultValues["NewPortMappingDescription"]; + map->protocol = resultValues["NewProtocol"]; + map->remoteHost = resultValues["NewRemoteHost"]; + + // Register the mapping + portMappings_.append(map); + + qDebug() << "UPnP::WanConnectionService - Got mapping: " << map->protocol << " " << map->remoteHost << ":" << map->externalPort + << " to " << map->internalClient << ":" << map->internalPort + << " max " << map->leaseDuration << "s '" << map->description << "' " << (map->enabled ? "enabled" : "disabled") << endl; + } + else + { + qDebug() << "UPnP::WanConnectionService - Unexpected response type" + << " '" << responseType << "' encountered." << endl; + } +} + + + +// Query for the external IP address +void WanConnectionService::queryExternalIpAddress() +{ + callAction("GetExternalIPAddress"); +} + + + +// Query for the Nat status +void WanConnectionService::queryNatEnabled() +{ + callAction("GetNATRSIPStatus"); +} + + + +// Query for a port mapping entry +void WanConnectionService::queryPortMappingEntry(int index) +{ + QMap<QString,QString> arguments; + arguments["NewPortMappingIndex"] = QString::number(index); + callAction("GetGenericPortMappingEntry", arguments); +} + + + +} // End of namespace diff --git a/src/modules/upnp/wanconnectionservice.h b/src/modules/upnp/wanconnectionservice.h new file mode 100644 index 000000000..4552f8ebc --- /dev/null +++ b/src/modules/upnp/wanconnectionservice.h @@ -0,0 +1,113 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + wanconnectionservice.h - description + ------------------- + begin : Mon Jul 25 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#ifndef UPNP_WANCONNECTIONSERVICE_H +#define UPNP_WANCONNECTIONSERVICE_H + +#include "service.h" +#include "kvi_pointerlist.h" + +namespace UPnP +{ + +struct PortMapping +{ + QString protocol; + QString remoteHost; + int externalPort; + QString internalClient; + int internalPort; + int leaseDuration; + QString description; + bool enabled; +}; + + +/** + * The Wan(IP/PPP)Connection service controls the connection and port forwarding settings of a router. + * The Layer3ForwardingService result either defines a WanIPConnection or WanPPPConnection service. + * Which one is returned depends on the external connection type. + * This class implements the common actions both services support, + * which is sufficient to control the port mappings of the router. + * + * @author Diederik van der Boor + * @ingroup NetworkUPnP + */ +class WanConnectionService : public Service +{ + public: // public methods + + // The constructor + WanConnectionService(const ServiceParameters ¶ms); + // The destructor + virtual ~WanConnectionService(); + + // Add a port mapping + void addPortMapping(const QString &protocol, const QString &remoteHost, int externalPort, + const QString &internalClient, int internalPort, const QString &description, + bool enabled = true, int leaseDuration = 0); + // Delete a port mapping + void deletePortMapping(const QString &protocol, const QString &remoteHost, int externalPort); + + // Return the external IP address + QString getExternalIpAddress() const; + // Return true if NAT is enabled + bool getNatEnabled() const; + // Return the port mappings + const KviPointerList<PortMapping>& getPortMappings() const; + + // Query for the external IP address + void queryExternalIpAddress(); + // Query for the Nat status + void queryNatEnabled(); + // Query for a port mapping entry + void queryPortMappingEntry(int index); + + + protected: // protected methods + + // The control point received a response to callAction() + virtual void gotActionResponse(const QString &responseType, const QMap<QString,QString> &resultValues); + + + private: // private attributes + // The external IP address + QString externalIpAddress_; + // True if NAT is enabled + bool natEnabled_; + // The current port mappings + KviPointerList<PortMapping> portMappings_; +}; + +} + +#endif diff --git a/src/modules/upnp/xmlfunctions.cpp b/src/modules/upnp/xmlfunctions.cpp new file mode 100644 index 000000000..c311f4d97 --- /dev/null +++ b/src/modules/upnp/xmlfunctions.cpp @@ -0,0 +1,126 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + xmlfunctions.cpp - description + ------------------- + begin : Sun Jul 24 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#include "xmlfunctions.h" + +#include <QStringList> + + +// Helper function, get a specific node +QDomNode XmlFunctions::getNode( const QDomNode &rootNode, const QString &path ) +{ + + QStringList pathItems = QStringList::split( "/", path, false ); + QDomNode childNode = rootNode.namedItem( pathItems[0] ); // can be a null node + + uint i = 1; + while( i < pathItems.count() ) + { + if( childNode.isNull() ) + { + break; + } + + childNode = childNode.namedItem( pathItems[ i ] ); + i++; // not using for loop so i is always correct for kdDebug() below. + } + + if( childNode.isNull() ) { + qDebug() << "XmlFunctions::getNode() - notice: node '" << pathItems[ i - 1 ] << "'" + << " does not exist (root=" << rootNode.nodeName() << " path=" << path << ")." << endl; + } + + return childNode; +} + + + +// Helper function, get the attribute text of a node +QString XmlFunctions::getNodeAttribute( const QDomNode &node, const QString &attribute ) +{ + + // Writing this is not funny + return node.attributes().namedItem( attribute ).toAttr().value(); +// node.toElement().attribute( attribute ); does not work for const nodes. +} + + + +// Helper function, get a specific child node +QDomNode XmlFunctions::getNodeChildByKey( const QDomNodeList &childNodes, const QString &keyTagName, const QString &keyValue ) +{ + + for( uint i = 0; i < childNodes.count(); i++ ) + { +// kdDebug() << "node " << childNodes.item(i).nodeName() << "/" << keyTagName +// << "=" << childNodes.item(i).namedItem(keyTagName).toElement().text() << " == " << keyValue << "?" << endl; + + // If the node has an childname with a certain value... e.g. <childNodes> <item><name>value</name></item> .. </childNodes> + if( childNodes.item( i ).namedItem( keyTagName ).toElement().text() == keyValue) + { + // Return the node + return childNodes.item( i ); + } + } + + // Return a null node (is there a better way?) + return childNodes.item( childNodes.count() ); +} + + + +// Helper function, get the text value of a node +QString XmlFunctions::getNodeValue( const QDomNode &rootNode, const QString &path ) +{ + + // Added code to avoid more assertion errors, and trace the cause. + if( rootNode.isNull() ) + { + qWarning() << "XmlFunctions::getNodeValue: Attempted to request '" << path << "' on null root node." << endl; + return QString::null; + } + + + // Because writing node.namedItem("childItem").namedItem("child2").toElement().text() is not funny. + return getNode( rootNode, path ).toElement().text(); +} + + +// Helper function, get the source XML of a node. +QString XmlFunctions::getSource( const QDomNode &node, int indent ) +{ + QString source; + QTextStream textStream( &source, IO_WriteOnly ); + node.save( textStream, indent ); + return source; +} + diff --git a/src/modules/upnp/xmlfunctions.h b/src/modules/upnp/xmlfunctions.h new file mode 100644 index 000000000..b4680b3b9 --- /dev/null +++ b/src/modules/upnp/xmlfunctions.h @@ -0,0 +1,61 @@ +//============================================================================= +// +// Creation date : Fri Aug 08 18:00:00 2000 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// 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, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Original Copyright following: +//============================================================================= + +/*************************************************************************** + xmlfunctions.cpp - description + ------------------- + begin : Sun Jul 24 2005 + copyright : (C) 2005 by Diederik van der Boor + email : vdboor --at-- codingdomain.com + ***************************************************************************/ + +#ifndef XMLFUNCTIONS_H +#define XMLFUNCTIONS_H + +#include <QDomNode> +#include <QDebug> + +/** + * Some helper functions to make the handling of QDom easier. + * + * @author Diederik van der Boor + * @ingroup NetworkExtra + */ +class XmlFunctions +{ + public: + // Helper function, get a specific node + static QDomNode getNode(const QDomNode &rootNode, const QString &path); + // Helper function, get the attribute text of a node + static QString getNodeAttribute(const QDomNode &node, const QString &attribute); + // Helper function, get a specific child node + static QDomNode getNodeChildByKey(const QDomNodeList &childNodes, + const QString &keyTagName, const QString &keyValue); + // Helper function, get the text value of a node + static QString getNodeValue(const QDomNode &rootNode, const QString &path); + // Helper function, get the source XML of a node. + static QString getSource( const QDomNode &node, int indent = 0 ); +}; + +#endif |
