Commit 54de8fa2 authored by Albert Vaca Cintora's avatar Albert Vaca Cintora

Android: Uses Apache Mina to abstract socket management

KDE: Housekeeping
parent 87513455
set(kded_kdeconnect_SRCS set(kded_kdeconnect_SRCS
announcers/announcer.cpp linkproviders/linkprovider.cpp
announcers/fakeannouncer.cpp linkproviders/loopbacklinkprovider.cpp
announcers/avahiannouncer.cpp linkproviders/avahitcplinkprovider.cpp
announcers/avahitcpannouncer.cpp
devicelinks/devicelink.cpp devicelinks/devicelink.cpp
devicelinks/echodevicelink.cpp devicelinks/echodevicelink.cpp
devicelinks/udpdevicelink.cpp
devicelinks/tcpdevicelink.cpp devicelinks/tcpdevicelink.cpp
packageinterfaces/packagereceiver.cpp packageinterfaces/packageinterface.cpp
packageinterfaces/pingpackagereceiver.cpp packageinterfaces/pingpackageinterface.cpp
packageinterfaces/notificationpackagereceiver.cpp packageinterfaces/notificationpackageinterface.cpp
packageinterfaces/pausemusicpackagereceiver.cpp packageinterfaces/pausemusicpackageinterface.cpp
packageinterfaces/clipboardpackageinterface.cpp packageinterfaces/clipboardpackageinterface.cpp
networkpackage.cpp networkpackage.cpp
......
/**
* Copyright 2013 Albert Vaca <albertvaka@gmail.com>
*
* 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/>.
*/
#include "avahiannouncer.h"
#include "devicelinks/udpdevicelink.h"
#include <QHostInfo>
AvahiAnnouncer::AvahiAnnouncer()
{
QString serviceType = "_kdeconnect._udp";
quint16 port = 10601;
//http://api.kde.org/4.x-api/kdelibs-apidocs/dnssd/html/index.html
service = new DNSSD::PublicService(QHostInfo::localHostName(), serviceType, port);
mUdpSocket = new QUdpSocket();
mUdpSocket->bind(port);
connect(mUdpSocket, SIGNAL(readyRead()), this, SLOT(newConnection()));
qDebug() << "Listening to udp messages";
}
void AvahiAnnouncer::newConnection()
{
qDebug() << "AvahiAnnouncer newConnection";
while (mUdpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(mUdpSocket->pendingDatagramSize());
NetAddress client;
mUdpSocket->readDatagram(datagram.data(), datagram.size(), &(client.ip), &(client.port));
//log.write(datagram);
qDebug() << "AvahiAnnouncer incomming udp datagram: " << datagram;
NetworkPackage np;
NetworkPackage::unserialize(datagram,&np);
if (np.type() == "kdeconnect.identity") {
const QString& id = np.get<QString>("deviceId");
//const QString& name = np.get<QString>("deviceName");
qDebug() << "AvahiAnnouncer creating link to device" << id << "(" << client.ip << "," << client.port << ")";
DeviceLink* dl = new UdpDeviceLink(id, this, client.ip);
connect(dl,SIGNAL(destroyed(QObject*)),this,SLOT(deviceLinkDestroyed(QObject*)));
emit onNewDeviceLink(np, dl);
NetworkPackage::createIdentityPackage(&np);
dl->sendPackage(np);
if (links.contains(id)) {
//Delete old link if we already know it, probably it is down if this happens.
qDebug() << "Destroying old link";
delete links[id];
}
links[id] = dl;
} else {
qDebug() << "Not an identification package (wuh?)";
}
}
}
void AvahiAnnouncer::deviceLinkDestroyed(QObject* deviceLink)
{
const QString& id = ((DeviceLink*)deviceLink)->deviceId();
if (links.contains(id)) links.remove(id);
}
AvahiAnnouncer::~AvahiAnnouncer()
{
delete service;
}
void AvahiAnnouncer::setDiscoverable(bool b)
{
qDebug() << "Avahi announcing";
if (b) service->publishAsync();
}
/**
* Copyright 2013 Albert Vaca <albertvaka@gmail.com>
*
* 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/>.
*/
#ifndef AVAHIANNOUNCER_H
#define AVAHIANNOUNCER_H
#include <QObject>
#include <QUdpSocket>
#include <KDE/DNSSD/PublicService>
#include "announcer.h"
#include "netaddress.h"
class AvahiAnnouncer
: public Announcer
{
Q_OBJECT
public:
AvahiAnnouncer();
~AvahiAnnouncer();
QString name() { return "Avahi"; }
int priority() { return PRIORITY_HIGH; }
void setDiscoverable(bool b);
private Q_SLOTS:
void newConnection();
void deviceLinkDestroyed(QObject*);
private:
DNSSD::PublicService* service;
QUdpSocket* mUdpSocket;
QMap<QString, DeviceLink*> links;
};
#endif
...@@ -19,15 +19,16 @@ ...@@ -19,15 +19,16 @@
*/ */
#include "daemon.h" #include "daemon.h"
#include "networkpackage.h" #include "networkpackage.h"
#include "packageinterfaces/pingpackagereceiver.h"
#include "packageinterfaces/notificationpackagereceiver.h" #include "packageinterfaces/pingpackageinterface.h"
#include "packageinterfaces/pausemusicpackagereceiver.h" #include "packageinterfaces/notificationpackageinterface.h"
#include "packageinterfaces/pausemusicpackageinterface.h"
#include "packageinterfaces/clipboardpackageinterface.h" #include "packageinterfaces/clipboardpackageinterface.h"
#include "announcers/avahiannouncer.h"
#include "announcers/avahitcpannouncer.h" #include "linkproviders/avahitcplinkprovider.h"
#include "announcers/fakeannouncer.h" #include "linkproviders/loopbacklinkprovider.h"
#include "devicelinks/echodevicelink.h"
#include <QtNetwork/QUdpSocket> #include <QtNetwork/QUdpSocket>
#include <QFile> #include <QFile>
...@@ -54,23 +55,20 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&) ...@@ -54,23 +55,20 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&)
} }
//Debugging //Debugging
qDebug() << "GO GO GO!"; qDebug() << "Starting KdeConnect daemon";
config->group("devices").group("paired").group("fake_unreachable").writeEntry("name","Fake device"); config->group("devices").group("paired").group("fake_unreachable").writeEntry("name","Fake device");
//TODO: Do not hardcode the load of the package receivers //TODO: Do not hardcode the load of the package interfaces
//use: https://techbase.kde.org/Development/Tutorials/Services/Plugins //use: https://techbase.kde.org/Development/Tutorials/Services/Plugins
packageReceivers.push_back(new PingPackageReceiver()); mPackageInterfaces.push_back(new PingPackageInterface());
packageReceivers.push_back(new NotificationPackageReceiver()); mPackageInterfaces.push_back(new NotificationPackageInterface());
packageReceivers.push_back(new PauseMusicPackageReceiver()); mPackageInterfaces.push_back(new PauseMusicPackageInterface());
packageReceivers.push_back(new ClipboardPackageInterface()); mPackageInterfaces.push_back(new ClipboardPackageInterface());
//TODO: Do not hardcode the load of the device locators //TODO: Do not hardcode the load of the device locators
//use: https://techbase.kde.org/Development/Tutorials/Services/Plugins //use: https://techbase.kde.org/Development/Tutorials/Services/Plugins
// announcers.insert(new AvahiAnnouncer()); mLinkProviders.insert(new AvahiTcpLinkProvider());
announcers.insert(new AvahiTcpAnnouncer()); //mLinkProviders.insert(new LoopbackLinkProvider());
//announcers.insert(new LoopbackAnnouncer());
//TODO: Add package emitters
//Read remebered paired devices //Read remebered paired devices
const KConfigGroup& known = config->group("devices").group("paired"); const KConfigGroup& known = config->group("devices").group("paired");
...@@ -80,8 +78,8 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&) ...@@ -80,8 +78,8 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&)
const KConfigGroup& data = known.group(id); const KConfigGroup& data = known.group(id);
const QString& name = data.readEntry<QString>("name",defaultName); const QString& name = data.readEntry<QString>("name",defaultName);
Device* device = new Device(id,name); Device* device = new Device(id,name);
m_devices[id] = device; mDevices[id] = device;
Q_FOREACH (PackageReceiver* pr, packageReceivers) { Q_FOREACH (PackageInterface* pr, mPackageInterfaces) {
connect(device,SIGNAL(receivedPackage(const Device&, const NetworkPackage&)), connect(device,SIGNAL(receivedPackage(const Device&, const NetworkPackage&)),
pr,SLOT(receivePackage(const Device&, const NetworkPackage&))); pr,SLOT(receivePackage(const Device&, const NetworkPackage&)));
connect(pr,SIGNAL(sendPackage(const NetworkPackage&)), connect(pr,SIGNAL(sendPackage(const NetworkPackage&)),
...@@ -90,7 +88,7 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&) ...@@ -90,7 +88,7 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&)
} }
//Listen to incomming connections //Listen to incomming connections
Q_FOREACH (Announcer* a, announcers) { Q_FOREACH (LinkProvider* a, mLinkProviders) {
connect(a,SIGNAL(onNewDeviceLink(NetworkPackage,DeviceLink*)), connect(a,SIGNAL(onNewDeviceLink(NetworkPackage,DeviceLink*)),
this,SLOT(onNewDeviceLink(NetworkPackage,DeviceLink*))); this,SLOT(onNewDeviceLink(NetworkPackage,DeviceLink*)));
} }
...@@ -102,9 +100,8 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&) ...@@ -102,9 +100,8 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&)
} }
void Daemon::setDiscoveryEnabled(bool b) void Daemon::setDiscoveryEnabled(bool b)
{ {
qDebug() << "Discovery:" << b;
//Listen to incomming connections //Listen to incomming connections
Q_FOREACH (Announcer* a, announcers) { Q_FOREACH (LinkProvider* a, mLinkProviders) {
a->setDiscoverable(b); a->setDiscoverable(b);
} }
...@@ -112,7 +109,7 @@ void Daemon::setDiscoveryEnabled(bool b) ...@@ -112,7 +109,7 @@ void Daemon::setDiscoveryEnabled(bool b)
QStringList Daemon::devices() QStringList Daemon::devices()
{ {
return m_devices.keys(); return mDevices.keys();
} }
...@@ -120,12 +117,12 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* ...@@ -120,12 +117,12 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink*
{ {
const QString& id = identityPackage.get<QString>("deviceId"); const QString& id = identityPackage.get<QString>("deviceId");
qDebug() << "Device discovered" << id << "via" << dl->announcer()->name(); qDebug() << "Device discovered" << id << "via" << dl->provider()->name();
if (m_devices.contains(id)) { if (mDevices.contains(id)) {
qDebug() << "It is a known device"; qDebug() << "It is a known device";
Device* device = m_devices[id]; Device* device = mDevices[id];
device->addLink(dl); device->addLink(dl);
KNotification* notification = new KNotification("pingReceived"); //KNotification::Persistent KNotification* notification = new KNotification("pingReceived"); //KNotification::Persistent
...@@ -142,8 +139,8 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* ...@@ -142,8 +139,8 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink*
const QString& name = identityPackage.get<QString>("deviceName"); const QString& name = identityPackage.get<QString>("deviceName");
Device* device = new Device(id,name,dl); Device* device = new Device(id,name,dl);
m_devices[id] = device; mDevices[id] = device;
Q_FOREACH (PackageReceiver* pr, packageReceivers) { Q_FOREACH (PackageInterface* pr, mPackageInterfaces) {
connect(device,SIGNAL(receivedPackage(const Device&, const NetworkPackage&)), connect(device,SIGNAL(receivedPackage(const Device&, const NetworkPackage&)),
pr,SLOT(receivePackage(const Device&, const NetworkPackage&))); pr,SLOT(receivePackage(const Device&, const NetworkPackage&)));
connect(pr,SIGNAL(sendPackage(const NetworkPackage&)), connect(pr,SIGNAL(sendPackage(const NetworkPackage&)),
...@@ -156,6 +153,6 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* ...@@ -156,6 +153,6 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink*
Daemon::~Daemon() Daemon::~Daemon()
{ {
qDebug() << "SAYONARA BABY";
} }
...@@ -39,9 +39,9 @@ ...@@ -39,9 +39,9 @@
#include <KConfig> #include <KConfig>
#include "device.h" #include "device.h"
#include "packageinterfaces/packagereceiver.h" #include "packageinterfaces/packageinterface.h"
#include "devicelinks/devicelink.h" #include "devicelinks/devicelink.h"
#include "announcers/announcer.h" #include "linkproviders/linkprovider.h"
class QUdpSocket; class QUdpSocket;
...@@ -75,13 +75,13 @@ private: ...@@ -75,13 +75,13 @@ private:
//Every known device //Every known device
QMap<QString, Device*> m_devices; QMap<QString, Device*> mDevices;
//Different ways to find devices and connect to them, ordered by priority //Different ways to find devices and connect to them
QSet<Announcer*> announcers; QSet<LinkProvider*> mLinkProviders;
//Everybody who wants to be notified about a new package //The classes that send and receive the packages
QVector<PackageReceiver*> packageReceivers; QVector<PackageInterface*> mPackageInterfaces;
}; };
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#include <ksharedptr.h> #include <ksharedptr.h>
#include <ksharedconfig.h> #include <ksharedconfig.h>
#include "devicelinks/devicelink.h" #include "devicelinks/devicelink.h"
#include "announcers/announcer.h" #include "linkproviders/linkprovider.h"
#include <KConfigGroup> #include <KConfigGroup>
#include <QDebug> #include <QDebug>
...@@ -59,12 +59,12 @@ void Device::setPair(bool b) ...@@ -59,12 +59,12 @@ void Device::setPair(bool b)
static bool lessThan(DeviceLink* p1, DeviceLink* p2) static bool lessThan(DeviceLink* p1, DeviceLink* p2)
{ {
return p1->announcer()->priority() > p2->announcer()->priority(); return p1->provider()->priority() > p2->provider()->priority();
} }
void Device::addLink(DeviceLink* link) void Device::addLink(DeviceLink* link)
{ {
qDebug() << "Adding link to " << id() << "via" << link->announcer(); qDebug() << "Adding link to " << id() << "via" << link->provider();
connect(link,SIGNAL(destroyed(QObject*)),this,SLOT(linkDestroyed(QObject*))); connect(link,SIGNAL(destroyed(QObject*)),this,SLOT(linkDestroyed(QObject*)));
...@@ -111,7 +111,7 @@ QStringList Device::availableLinks() const ...@@ -111,7 +111,7 @@ QStringList Device::availableLinks() const
{ {
QStringList sl; QStringList sl;
Q_FOREACH(DeviceLink* dl, m_deviceLinks) { Q_FOREACH(DeviceLink* dl, m_deviceLinks) {
sl.append(dl->announcer()->name()); sl.append(dl->provider()->name());
} }
return sl; return sl;
} }
......
...@@ -19,11 +19,12 @@ ...@@ -19,11 +19,12 @@
*/ */
#include "devicelink.h" #include "devicelink.h"
#include "linkproviders/linkprovider.h"
DeviceLink::DeviceLink(const QString& deviceId, Announcer* parent) DeviceLink::DeviceLink(const QString& deviceId, LinkProvider* parent)
: QObject(parent) : QObject(parent)
, mDeviceId(deviceId) , mDeviceId(deviceId)
, mAnnouncer(parent) , mLinkProvider(parent)
{ {
//gcc complains if we don't add something to compile on a class with virtual functions //gcc complains if we don't add something to compile on a class with virtual functions
} }
\ No newline at end of file
...@@ -24,10 +24,9 @@ ...@@ -24,10 +24,9 @@
#include <QObject> #include <QObject>
#include "networkpackage.h" #include "networkpackage.h"
#include <announcers/announcer.h>
class Device; class Device;
class Announcer; class LinkProvider;
class DeviceLink class DeviceLink
: public QObject : public QObject
...@@ -35,10 +34,10 @@ class DeviceLink ...@@ -35,10 +34,10 @@ class DeviceLink
Q_OBJECT Q_OBJECT
public: public:
DeviceLink(const QString& deviceId, Announcer* parent); DeviceLink(const QString& deviceId, LinkProvider* parent);
const QString& deviceId() { return mDeviceId; } const QString& deviceId() { return mDeviceId; }
Announcer* announcer() { return mAnnouncer; } LinkProvider* provider() { return mLinkProvider; }
virtual bool sendPackage(const NetworkPackage& np) = 0; virtual bool sendPackage(const NetworkPackage& np) = 0;
...@@ -47,7 +46,7 @@ signals: ...@@ -47,7 +46,7 @@ signals:
private: private:
QString mDeviceId; QString mDeviceId;
Announcer* mAnnouncer; LinkProvider* mLinkProvider;
}; };
......
...@@ -20,9 +20,9 @@ ...@@ -20,9 +20,9 @@
#include "echodevicelink.h" #include "echodevicelink.h"
#include "announcers/fakeannouncer.h" #include "linkproviders/loopbacklinkprovider.h"
EchoDeviceLink::EchoDeviceLink(const QString& d, LoopbackAnnouncer* a) EchoDeviceLink::EchoDeviceLink(const QString& d, LoopbackLinkProvider* a)
: DeviceLink(d, a) : DeviceLink(d, a)
{ {
......
...@@ -22,13 +22,14 @@ ...@@ -22,13 +22,14 @@
#define ECHODEVICELINK_H #define ECHODEVICELINK_H
#include "devicelink.h" #include "devicelink.h"
class LoopbackAnnouncer; class LoopbackLinkProvider;
class EchoDeviceLink : public DeviceLink class EchoDeviceLink
: public DeviceLink
{ {
Q_OBJECT Q_OBJECT
public: public:
EchoDeviceLink(const QString& d, LoopbackAnnouncer* a); EchoDeviceLink(const QString& d, LoopbackLinkProvider* a);
bool sendPackage(const NetworkPackage& np) { bool sendPackage(const NetworkPackage& np) {
emit receivedPackage(np); emit receivedPackage(np);
......
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
*/ */
#include "tcpdevicelink.h" #include "tcpdevicelink.h"
#include "announcers/avahitcpannouncer.h" #include "linkproviders/avahitcplinkprovider.h"
TcpDeviceLink::TcpDeviceLink(const QString& d, AvahiTcpAnnouncer* a, QTcpSocket* socket) TcpDeviceLink::TcpDeviceLink(const QString& d, AvahiTcpLinkProvider* a, QTcpSocket* socket)
: DeviceLink(d, a) : DeviceLink(d, a)
{ {
mSocket = socket; mSocket = socket;
...@@ -29,6 +29,12 @@ TcpDeviceLink::TcpDeviceLink(const QString& d, AvahiTcpAnnouncer* a, QTcpSocket* ...@@ -29,6 +29,12 @@ TcpDeviceLink::TcpDeviceLink(const QString& d, AvahiTcpAnnouncer* a, QTcpSocket*
connect(mSocket, SIGNAL(readyRead()), this, SLOT(dataReceived())); connect(mSocket, SIGNAL(readyRead()), this, SLOT(dataReceived()));
} }
bool TcpDeviceLink::sendPackage(const NetworkPackage& np)
{
int written = mSocket->write(np.serialize());
return written != -1;
}
void TcpDeviceLink::dataReceived() void TcpDeviceLink::dataReceived()
{ {
qDebug() << "TcpDeviceLink dataReceived"; qDebug() << "TcpDeviceLink dataReceived";
......
...@@ -27,21 +27,18 @@ ...@@ -27,21 +27,18 @@
#include "devicelink.h" #include "devicelink.h"
#include <QTcpSocket> #include <QTcpSocket>
#include <QTcpServer>
class AvahiTcpAnnouncer; class AvahiTcpLinkProvider;
class TcpDeviceLink : public DeviceLink class TcpDeviceLink
: public DeviceLink
{ {
Q_OBJECT Q_OBJECT
public: public:
TcpDeviceLink(const QString& d, AvahiTcpAnnouncer* a, QTcpSocket* socket); TcpDeviceLink(const QString& d, AvahiTcpLinkProvider* a, QTcpSocket* socket);
bool sendPackage(const NetworkPackage& np) { bool sendPackage(const NetworkPackage& np);
mSocket->write(np.serialize());
return true;
}
private Q_SLOTS: private Q_SLOTS:
void dataReceived(); void dataReceived();
......
/**
* Copyright 2013 Albert Vaca <albertvaka@gmail.com>
*
* 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/>.
*/
#include "udpdevicelink.h"
#include "announcers/avahiannouncer.h"
UdpDeviceLink::UdpDeviceLink(const QString& d, AvahiAnnouncer* a, QHostAddress ip)
: DeviceLink(d, a)
{
mIp = ip;
mSocket = new QUdpSocket();
mSocket->bind(mPort);
connect(mSocket, SIGNAL(readyRead()), this, SLOT(dataReceived()));
}
void UdpDeviceLink::dataReceived()
{
qDebug() << "UdpDeviceLink dataReceived";
while (mSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(mSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
mSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
//log.write(datagram);
qDebug() << datagram;
NetworkPackage np;
NetworkPackage::unserialize(datagram,&np);
emit receivedPackage(np);
}
}
/**
* Copyright 2013 Albert Vaca <albertvaka@gmail.com>
*
* 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/>.