[SCM] kdeconnect packaging branch, master, updated. debian/0.9g-1-1183-g9d69498

Maximiliano Curia maxy at moszumanska.debian.org
Fri Oct 14 14:26:51 UTC 2016


Gitweb-URL: http://git.debian.org/?p=pkg-kde/kde-extras/kdeconnect.git;a=commitdiff;h=1604309

The following commit has been merged in the master branch:
commit 1604309aceb22f9baaf4e606522df402b51423a6
Author: Albert Vaca <albertvaka at gmail.com>
Date:   Fri Aug 30 19:10:43 2013 +0200

    Added symmetric pairing
    
    A KNotification asks to accept the pairing when the other ends requests it
---
 daemon/daemon.cpp                                  |  68 +++++-
 daemon/default_args.h                              |   8 +
 daemon/device.cpp                                  | 232 ++++++++++++++++++---
 daemon/device.h                                    |  33 ++-
 daemon/networkpackage.h                            |   3 -
 daemon/networkpackagetypes.h                       |   1 +
 .../plugins/notifications/notificationsplugin.cpp  |   1 +
 kcm/kcm.cpp                                        | 103 +++++++--
 kcm/kcm.h                                          |   8 +-
 kcm/kcm.ui                                         | 186 +++++++++++------
 libkdeconnect/devicesmodel.cpp                     |   6 +-
 11 files changed, 497 insertions(+), 152 deletions(-)

diff --git a/daemon/daemon.cpp b/daemon/daemon.cpp
index 0004d53..98de7f2 100644
--- a/daemon/daemon.cpp
+++ b/daemon/daemon.cpp
@@ -29,6 +29,7 @@
 #include <QDBusConnection>
 #include <QNetworkSession>
 #include <QNetworkConfigurationManager>
+#include <QSslKey>
 
 #include <KIcon>
 #include <KConfigGroup>
@@ -50,6 +51,58 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&)
         qDebug() << "My id:" << uuid;
     }
 
+    if (!config->group("myself").hasKey("privateKey")) {
+
+        //TODO: Generate
+
+        QByteArray key = QByteArray(
+                                "-----BEGIN RSA PRIVATE KEY-----
"
+                                "MIICXAIBAAKBgQCnKxy6aZrABVvbxuWqMPbohH4KRDBGqyO/OwxvUD1qHpqZ9cJT
"
+                                "bgttiIaXzdQny5esf6brI6Di/ssIp9awdLBlMT+eR6zR7g446tbxaCFuUiL0QIei
"
+                                "izEveTDNRbson/8DPJrn8/81doTeXsuV7YbqmtUGwdZ5kiocAW92ZZukdQIDAQAB
"
+                                "AoGBAI18yuLoMQdnQblBne8vZDumsDsmPaoCfc4EP2ETi/d+kaHPxTryABAkJq7j
"
+                                "kjZgdi6VGIUacbjOqK/Zxrcw/H460EwOUzh97Z4t9CDtDhz6t3ddT8CfbG2TUgbx
"
+                                "Vv3mSYSUDBdNBV6YY4fyLtZl6oI2V+rBaFIT48+vAK9doKlhAkEA2ZKm9dc80IjU
"
+                                "c/Wwn8ij+6ALs4Mpa0dPYivgZ2QhXiX5TfMymal2dDufkOH4wIUO+8vV8CSmmTRU
"
+                                "8Lv/B3pY7QJBAMSxeJtTSFwBcGRaZKRMIqeuZ/yMMT4EqqIh1DjBpujCRKApVpkO
"
+                                "kVx3Yu7xyOfniXBwujiYNSL6LrWdKykEsKkCQEr2UDgbtIRU4H4jhHtI8dbcSavL
"
+                                "4RVpOFymqWZ2BVke1EqbJC/1Ry687DlK4h3Sulre3BMlTZEziqB25WN6L/ECQBJv
"
+                                "B3yXG4rz35KoHhJ/yCeq4rf6c4r6aPt07Cy9iWT6/+96sFD72oet8KmwI0IIowrU
"
+                                "pb80FJbIl6QRrL/VXrECQBDdeCAG6J3Cwm4ozQiDQyiNd1qJqWc4co9savJxLtEU
"
+                                "s5L4Qwfrexm16oCJimGmsa5q6Y0n4f5gY+MRh3n+nQo=
"
+                                "-----END RSA PRIVATE KEY-----
"
+                             );
+
+        //Test for validity
+        //QSslKey privateKey(key.toAscii(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
+        //qDebug() << "Valid private key:" << !privateKey.isNull();
+
+        config->group("myself").writeEntry("privateKey", key);
+
+    }
+
+    if (!config->group("myself").hasKey("publicKey")) {
+
+        //TODO: Generate
+
+        QByteArray key = QByteArray(
+                                "-----BEGIN PUBLIC KEY-----
"
+                                "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnKxy6aZrABVvbxuWqMPbohH4K
"
+                                "RDBGqyO/OwxvUD1qHpqZ9cJTbgttiIaXzdQny5esf6brI6Di/ssIp9awdLBlMT+e
"
+                                "R6zR7g446tbxaCFuUiL0QIeiizEveTDNRbson/8DPJrn8/81doTeXsuV7YbqmtUG
"
+                                "wdZ5kiocAW92ZZukdQIDAQAB
"
+                                "-----END PUBLIC KEY-----
"
+
+                             );
+
+        //Test for validity
+        //QSslKey publicKey(key.toAscii(), QSsl::Rsa, QSsl::Pem, QSsl::PublicKey);
+        //qDebug() << "Valid public key:" << !publicKey.isNull();
+
+        config->group("myself").writeEntry("publicKey", key);
+
+    }
+
     //Debugging
     qDebug() << "Starting KdeConnect daemon";
 
@@ -58,13 +111,10 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&)
     mLinkProviders.insert(new LoopbackLinkProvider());
 
     //Read remebered paired devices
-    const KConfigGroup& known = config->group("devices").group("paired");
+    const KConfigGroup& known = config->group("devices");
     const QStringList& list = known.groupList();
-    const QString defaultName("unnamed");
     Q_FOREACH(const QString& id, list) {
-        const KConfigGroup& data = known.group(id);
-        const QString& name = data.readEntry<QString>("name", defaultName);
-        Device* device = new Device(id, name);
+        Device* device = new Device(id);
         connect(device, SIGNAL(reachableStatusChanged()), this, SLOT(onDeviceReachableStatusChanged()));
         mDevices[id] = device;
         Q_EMIT deviceAdded(id);
@@ -127,16 +177,12 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink*
 
     if (mDevices.contains(id)) {
         qDebug() << "It is a known device";
-
         Device* device = mDevices[id];
         device->addLink(dl);
-
     } else {
         qDebug() << "It is a new device";
 
-        const QString& name = identityPackage.get<QString>("deviceName");
-
-        Device* device = new Device(id, name, dl);
+        Device* device = new Device(identityPackage, dl);
         connect(device, SIGNAL(reachableStatusChanged()), this, SLOT(onDeviceReachableStatusChanged()));
         mDevices[id] = device;
 
@@ -157,7 +203,7 @@ void Daemon::onDeviceReachableStatusChanged()
 
     if (!device->reachable()) {
 
-        if (!device->paired()) {
+        if (!device->isPaired()) {
             qDebug() << "Destroying device";
             Q_EMIT deviceRemoved(id);
             mDevices.remove(id);
diff --git a/daemon/default_args.h b/daemon/default_args.h
index 4cf0fce..ff1b7f7 100644
--- a/daemon/default_args.h
+++ b/daemon/default_args.h
@@ -41,11 +41,19 @@ struct default_arg<int> {
 };
 
 //Pointer types -> NULL (partial specialization)
+//NOTE: Comented because it doesn't makeno sense to send a pointer over the network, but I just left it here for reference --albertvaka
 /*template<class T*>
 struct default_arg<T*> {
     static T* get() { NULL; }
 };
 */
+
+//QByteArray-> empty qbytearray
+template<>
+struct default_arg<QByteArray> {
+    static QByteArray get() { return QByteArray(); }
+};
+
 //QStrings -> empty string
 template<>
 struct default_arg<QString> {
diff --git a/daemon/device.cpp b/daemon/device.cpp
index 827f757..5f6876a 100644
--- a/daemon/device.cpp
+++ b/daemon/device.cpp
@@ -7,7 +7,10 @@
 #include <KPluginSelector>
 #include <KServiceTypeTrader>
 #include <KPluginInfo>
+#include <KNotification>
+#include <KIcon>
 
+#include <QSslKey>
 #include <QDebug>
 
 #include "plugins/kdeconnectplugin.h"
@@ -16,36 +19,38 @@
 #include "linkproviders/linkprovider.h"
 #include "networkpackage.h"
 
-Device::Device(const QString& id, const QString& name)
+Device::Device(const QString& id)
 {
 
     m_deviceId = id;
+
+    KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
+    const KConfigGroup& data = config->group("devices").group(id);
+
+    const QString& name = data.readEntry<QString>("name", QString("unnamed"));
     m_deviceName = name;
-    m_paired = true;
-    m_knownIdentiy = true;
 
-    reloadPlugins();
+    const QByteArray& key = data.readEntry<QByteArray>("publicKey",QByteArray());
+    m_publicKey = QSslKey(key, QSsl::Rsa, QSsl::Pem, QSsl::PublicKey);
+
+    m_pairingRequested = false;
 
     //Register in bus
     QDBusConnection::sessionBus().registerObject(dbusPath(), this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportAdaptors);
 
 }
 
-Device::Device(const QString& id, const QString& name, DeviceLink* link)
+Device::Device(const NetworkPackage& identityPackage, DeviceLink* dl)
 {
+    m_deviceId = identityPackage.get<QString>("deviceId");
+    m_deviceName = identityPackage.get<QString>("deviceName");
 
-    m_deviceId = id;
-    m_deviceName = name;
-    m_paired = false;
-    m_knownIdentiy = true;
+    addLink(dl);
 
-    addLink(link);
-
-    reloadPlugins();
+    m_pairingRequested = false;
 
     //Register in bus
     QDBusConnection::sessionBus().registerObject(dbusPath(), this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportAdaptors);
-
 }
 
 Device::~Device()
@@ -67,7 +72,7 @@ void Device::reloadPlugins()
 {
     QMap< QString, KdeConnectPlugin* > newPluginMap;
 
-    if (paired() && reachable()) { //Do not load any plugin for unpaired devices, nor useless loading them for unreachable devices
+    if (isPaired() && reachable()) { //Do not load any plugin for unpaired devices, nor useless loading them for unreachable devices
 
         QString path = KStandardDirs().resourceDirs("config").first()+"kdeconnect/";
         QMap<QString,QString> pluginStates = KSharedConfig::openConfig(path + id())->group("Plugins").entryMap();
@@ -114,21 +119,75 @@ void Device::reloadPlugins()
 
 }
 
+//TODO
+QSslKey myPrivateKey() {
+
+    KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
+    const QString& key = config->group("myself").readEntry<QString>("privateKey",QString());
+
+    QSslKey privateKey(key.toAscii(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
+    qDebug() << "Valid public key:" << !privateKey.isNull();
 
-void Device::setPair(bool b)
+    return privateKey;
+
+}
+
+void Device::requestPair()
 {
-    m_paired = b;
+    if (isPaired() || m_pairingRequested) {
+        Q_EMIT pairingFailed(i18n("Already paired"));
+        return;
+    }
+    if (!reachable()) {
+        Q_EMIT pairingFailed(i18n("Device not reachable"));
+        return;
+    }
+
+    //Send our own public key
+    NetworkPackage np(PACKAGE_TYPE_PAIR);
+    np.set("pair", true);
     KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
-    if (b) {
-        qDebug() << name() << "paired";
-        config->group("devices").group("paired").group(id()).writeEntry("name",name());
-        Q_EMIT reachableStatusChanged();
-    } else {
-        qDebug() << name() << "unpaired";
-        config->group("devices").group("paired").deleteGroup(id());
-        //Do not Q_EMIT reachableStatusChanged() because we do not want it to suddenly disappear from device list
+    const QByteArray& key = config->group("myself").readEntry<QByteArray>("publicKey",QByteArray());
+    np.set("publicKey",key);
+    bool success = sendPackage(np);
+
+    if (!success) {
+        Q_EMIT pairingFailed(i18n("Error contacting device"));
+        return;
     }
-    reloadPlugins();
+
+    m_pairingRequested = true;
+    pairingTimer.start(20 * 1000);
+    connect(&pairingTimer, SIGNAL(timeout()),
+            this, SLOT(pairingTimeout()));
+
+}
+
+void Device::unpair()
+{
+    if (!isPaired()) return;
+
+    m_publicKey = QSslKey();
+    m_pairingRequested = false;
+    pairingTimer.stop();
+
+    KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
+    config->group("devices").deleteGroup(id());
+
+    if (reachable()) {
+        NetworkPackage np(PACKAGE_TYPE_PAIR);
+        np.set("pair", false);
+        sendPackage(np);
+    }
+
+    reloadPlugins(); //Will unload the plugins
+
+}
+
+void Device::pairingTimeout()
+{
+    m_pairingRequested = false;
+    Q_EMIT Q_EMIT pairingFailed("Timed out");
 }
 
 static bool lessThan(DeviceLink* p1, DeviceLink* p2)
@@ -182,9 +241,10 @@ void Device::removeLink(DeviceLink* link)
 
 bool Device::sendPackage(const NetworkPackage& np) const
 {
-    if (!m_paired) {
-        //qDebug() << "sendpackage disabled on untrusted device" << name();
-        return false;
+    //Maybe we could block here any package that is not an identity or a pairing package
+
+    if (isPaired()) {
+
     }
 
     Q_FOREACH(DeviceLink* dl, m_deviceLinks) {
@@ -198,14 +258,118 @@ bool Device::sendPackage(const NetworkPackage& np) const
 
 void Device::privateReceivedPackage(const NetworkPackage& np)
 {
-    if (np.type() == "kdeconnect.identity" && !m_knownIdentiy) {
-        m_deviceName = np.get<QString>("deviceName");
-    } else if (m_paired) {
-        //qDebug() << "package received from trusted device" << name();
-        Q_EMIT receivedPackage(np);
+
+    if (np.type() == PACKAGE_TYPE_PAIR) {
+
+        qDebug() << "Pair package";
+
+        bool pair = np.get<bool>("pair");
+        if (pair == isPaired()) {
+            qDebug() << "Already" << (pair? "paired":"unpaired");
+            return;
+        }
+
+        KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
+
+        if (pair) {
+
+            if (m_pairingRequested)  { //We started pairing
+
+                qDebug() << "Pair answer";
+
+                m_pairingRequested = false;
+                pairingTimer.stop();
+
+                //Store as trusted device
+                const QByteArray& key = np.get<QByteArray>("publicKey");
+                config->group("devices").group(id()).writeEntry("publicKey",key);
+                config->group("devices").group(id()).writeEntry("name",name());
+                m_publicKey = QSslKey(key, QSsl::Rsa, QSsl::Pem, QSsl::PublicKey);
+
+                Q_EMIT pairingSuccesful();
+
+            } else {
+
+                qDebug() << "Pair request";
+
+                const QString& key = np.get<QString>("publicKey");
+                m_tempPublicKey = QSslKey(key.toAscii(), QSsl::Rsa, QSsl::Pem, QSsl::PublicKey);
+
+                KNotification* notification = new KNotification("pingReceived"); //KNotification::Persistent
+                notification->setPixmap(KIcon("dialog-information").pixmap(48, 48));
+                notification->setComponentData(KComponentData("kdeconnect", "kdeconnect"));
+                notification->setTitle("KDE Connect");
+                notification->setText(i18n("Pairing request from %1", m_deviceName));
+                notification->setActions(QStringList() << i18n("Accept") << i18n("Reject"));
+                connect(notification, SIGNAL(action1Activated()), this, SLOT(acceptPairing()));
+                connect(notification, SIGNAL(action2Activated()), this, SLOT(rejectPairing()));
+                notification->sendEvent();
+
+            }
+
+        } else {
+
+            qDebug() << "Unpair request";
+            if (m_pairingRequested) {
+                pairingTimer.stop();
+                Q_EMIT pairingFailed(i18n("Canceled by other peer"));
+            }
+            unpair();
+
+        }
+
+    } else if (!isPaired()) {
+
+        //TODO: Alert the other side that we don't trust them
+        qDebug() << "device" << name() << "not paired, ignoring package" << np.type();
+
     } else {
-        qDebug() << "device" << name() << "not trusted, ignoring package" << np.type();
+
+        //Forward signal
+        Q_EMIT receivedPackage(np);
+
     }
+
+}
+
+void Device::acceptPairing()
+{
+    qDebug() << "Accepted pairing";
+
+    KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
+
+    //Send our own public key
+    NetworkPackage np(PACKAGE_TYPE_PAIR);
+    np.set("pair", true);
+    const QByteArray& key = config->group("myself").readEntry<QByteArray>("publicKey",QByteArray());
+    np.set("publicKey",key);
+    bool success = sendPackage(np);
+
+    if (!success) {
+        return;
+    }
+
+    //Store as trusted device
+    m_publicKey = m_tempPublicKey;
+    config->group("devices").group(id()).writeEntry("publicKey", m_tempPublicKey.toPem());
+    config->group("devices").group(id()).writeEntry("name", name());
+
+    reloadPlugins(); //This will load plugins
+}
+
+void Device::rejectPairing()
+{
+    qDebug() << "Rejected pairing";
+
+    NetworkPackage np(PACKAGE_TYPE_PAIR);
+    np.set("pair", false);
+    sendPackage(np);
+
+    KNotification* notification = (KNotification*)sender();
+    notification->setActions(QStringList());
+    notification->setText(i18n("Pairing rejected"));
+    notification->update();
+
 }
 
 QStringList Device::availableLinks() const
diff --git a/daemon/device.h b/daemon/device.h
index aaeee3d..edcaadf 100644
--- a/daemon/device.h
+++ b/daemon/device.h
@@ -25,6 +25,8 @@
 #include <QDBusConnection>
 #include <QString>
 #include <QMap>
+#include <QSslKey>
+#include <QTimer>
 
 #include "networkpackage.h"
 
@@ -40,11 +42,11 @@ class Device
     Q_PROPERTY(QString name READ name)
 
 public:
-    //Device known from KConfig, we trust it but we need to wait for a incoming devicelink to communicate
-    Device(const QString& id, const QString& name);
+    //Read device from KConfig, we already know it but we need to wait for a incoming devicelink to communicate
+    Device(const QString& id);
 
     //Device known via an incoming connection sent to us via a devicelink, we know everything but we don't trust it yet
-    Device(const QString& id, const QString& name, DeviceLink* dl);
+    Device(const NetworkPackage& np, DeviceLink* dl);
 
     virtual ~Device();
 
@@ -57,8 +59,8 @@ public:
     void removeLink(DeviceLink*);
 
     Q_SCRIPTABLE QStringList availableLinks() const;
-    Q_SCRIPTABLE bool trusted() const { return m_paired; }
-    Q_SCRIPTABLE bool paired() const { return m_paired; }
+    Q_SCRIPTABLE bool isPaired() const { return !m_publicKey.isNull(); }
+    Q_SCRIPTABLE bool pairRequested() const { return m_pairingRequested; }
     Q_SCRIPTABLE bool reachable() const { return !m_deviceLinks.empty(); }
     Q_SCRIPTABLE bool hasPlugin(const QString& name);
     Q_SCRIPTABLE QStringList loadedPlugins();
@@ -69,28 +71,37 @@ Q_SIGNALS:
 public Q_SLOTS:
     virtual bool sendPackage(const NetworkPackage& np) const;
 
-    //Dbus operations called from kcm
+    //Dbus operations
 public Q_SLOTS:
-    Q_SCRIPTABLE void setPair(bool b);
-    Q_SCRIPTABLE void reloadPlugins(); //From settings
+    Q_SCRIPTABLE void requestPair();
+    Q_SCRIPTABLE void unpair();
+    Q_SCRIPTABLE void reloadPlugins(); //From kconf
     Q_SCRIPTABLE void sendPing();
+    void acceptPairing();
+    void rejectPairing();
 
 private Q_SLOTS:
+    void privateReceivedPackage(const NetworkPackage& np);
     void linkDestroyed(QObject* o = 0);
-    virtual void privateReceivedPackage(const NetworkPackage& np);
+    void pairingTimeout();
 
 Q_SIGNALS:
     Q_SCRIPTABLE void reachableStatusChanged();
     Q_SCRIPTABLE void pluginsChanged();
+    Q_SCRIPTABLE void pairingSuccesful();
+    Q_SCRIPTABLE void pairingFailed(const QString& error);
 
 private:
-    bool m_paired;
     QString m_deviceId;
     QString m_deviceName;
+    QSslKey m_publicKey;
+    QSslKey m_tempPublicKey;
+    bool m_pairingRequested;
+
     QList<DeviceLink*> m_deviceLinks;
     QMap<QString, KdeConnectPlugin*> m_plugins;
-    bool m_knownIdentiy;
 
+    QTimer pairingTimer;
 };
 
 Q_DECLARE_METATYPE(Device*)
diff --git a/daemon/networkpackage.h b/daemon/networkpackage.h
index 92c8d69..a2db3b5 100644
--- a/daemon/networkpackage.h
+++ b/daemon/networkpackage.h
@@ -48,9 +48,6 @@ public:
     static void unserialize(const QByteArray&, NetworkPackage*);
     QByteArray serialize() const;
 
-    static void rsaUnserialize(const QByteArray&, NetworkPackage*, Qssl );
-    QByteArray rsaSerialize() const;
-
     static void createIdentityPackage(NetworkPackage*);
 
     long id() const { return mId; }
diff --git a/daemon/networkpackagetypes.h b/daemon/networkpackagetypes.h
index 96ccaab..618a9bf 100644
--- a/daemon/networkpackagetypes.h
+++ b/daemon/networkpackagetypes.h
@@ -22,6 +22,7 @@
 #define NETWORKPACKAGETYPES_H
 
 #define PACKAGE_TYPE_IDENTITY QString("kdeconnect.identity")
+#define PACKAGE_TYPE_PAIR QString("kdeconnect.pair")
 #define PACKAGE_TYPE_PING QString("kdeconnect.ping")
 #define PACKAGE_TYPE_NOTIFICATION QString("kdeconnect.notification")
 #define PACKAGE_TYPE_BATTERY QString("kdeconnect.battery")
diff --git a/daemon/plugins/notifications/notificationsplugin.cpp b/daemon/plugins/notifications/notificationsplugin.cpp
index 691677a..4df6dc5 100644
--- a/daemon/plugins/notifications/notificationsplugin.cpp
+++ b/daemon/plugins/notifications/notificationsplugin.cpp
@@ -57,6 +57,7 @@ NotificationsPlugin::~NotificationsPlugin()
 bool NotificationsPlugin::receivePackage(const NetworkPackage& np)
 {
     if (np.type() != PACKAGE_TYPE_NOTIFICATION) return false;
+    if (np.get<bool>("request")) return false;
 
     notificationsDbusInterface->processPackage(np);
 
diff --git a/kcm/kcm.cpp b/kcm/kcm.cpp
index 8d97e0e..3a65cbe 100644
--- a/kcm/kcm.cpp
+++ b/kcm/kcm.cpp
@@ -59,6 +59,8 @@ KdeConnectKcm::KdeConnectKcm(QWidget *parent, const QVariantList&)
     kcmUi->deviceList->setModel(sortProxyModel);
 
     kcmUi->deviceInfo->setVisible(false);
+    kcmUi->progressBar->setVisible(false);
+    kcmUi->messages->setVisible(false);
 
     setButtons(KCModule::NoAdditionalButton);
 
@@ -66,12 +68,12 @@ KdeConnectKcm::KdeConnectKcm(QWidget *parent, const QVariantList&)
             this, SLOT(resetSelection()));
     connect(kcmUi->deviceList, SIGNAL(pressed(QModelIndex)),
             this, SLOT(deviceSelected(QModelIndex)));
+    connect(kcmUi->pair_button, SIGNAL(pressed()),
+            this, SLOT(requestPair()));
+    connect(kcmUi->unpair_button, SIGNAL(pressed()),
+            this, SLOT(unpair()));
     connect(kcmUi->ping_button, SIGNAL(pressed()),
             this, SLOT(sendPing()));
-    connect(kcmUi->trust_checkbox, SIGNAL(toggled(bool)),
-            this, SLOT(trustedStateChanged(bool)));
-
-
 
 }
 
@@ -85,6 +87,7 @@ void KdeConnectKcm::resetSelection()
     kcmUi->deviceList->selectionModel()->setCurrentIndex(sortProxyModel->mapFromSource(currentIndex), QItemSelectionModel::ClearAndSelect);
 }
 
+
 void KdeConnectKcm::deviceSelected(const QModelIndex& current)
 {
 
@@ -105,13 +108,33 @@ void KdeConnectKcm::deviceSelected(const QModelIndex& current)
         return;
     }
 
+    kcmUi->messages->setVisible(false);
+    if (currentDevice->pairRequested()) {
+        kcmUi->progressBar->setVisible(true);
+        kcmUi->unpair_button->setVisible(false);
+        kcmUi->pair_button->setVisible(false);
+        kcmUi->ping_button->setVisible(false);
+    } else {
+        kcmUi->progressBar->setVisible(false);
+        if (currentDevice->isPaired()) {
+            kcmUi->unpair_button->setVisible(true);
+            kcmUi->pair_button->setVisible(false);
+            kcmUi->ping_button->setVisible(true);
+        } else {
+            kcmUi->unpair_button->setVisible(false);
+            kcmUi->pair_button->setVisible(true);
+            kcmUi->ping_button->setVisible(false);
+        }
+    }
+
+
     //FIXME: KPluginSelector has no way to remove a list of plugins and load another, so we need to destroy and recreate it each time
     delete kcmUi->pluginSelector;
     kcmUi->pluginSelector = new KPluginSelector(this);
     kcmUi->verticalLayout_2->addWidget(kcmUi->pluginSelector);
 
-    kcmUi->deviceName->setText(currentDevice->name());
-    kcmUi->trust_checkbox->setChecked(currentDevice->paired());
+    kcmUi->name_label->setText(currentDevice->name());
+    kcmUi->status_label->setText(currentDevice->isPaired()? "paired" : "unpaired");
 
     KService::List offers = KServiceTypeTrader::self()->query("KdeConnect/Plugin");
     QList<KPluginInfo> scriptinfos = KPluginInfo::fromServices(offers);
@@ -124,22 +147,58 @@ void KdeConnectKcm::deviceSelected(const QModelIndex& current)
             this, SLOT(pluginsConfigChanged()));
 }
 
-void KdeConnectKcm::trustedStateChanged(bool b)
+void KdeConnectKcm::requestPair()
 {
     if (!currentDevice) return;
-    QDBusPendingReply<void> pendingReply = currentDevice->setPair(b);
-    pendingReply.waitForFinished();
-    if (pendingReply.isValid()) {
-        //If dbus was down, calling this would make kcm crash
-        devicesModel->deviceStatusChanged(currentDevice->id());
-    } else {
-        //Revert checkbox
-        disconnect(kcmUi->trust_checkbox, SIGNAL(toggled(bool)),
-                   this, SLOT(trustedStateChanged(bool)));
-        kcmUi->trust_checkbox->setCheckState(b? Qt::Unchecked : Qt::Checked);
-        connect(kcmUi->trust_checkbox, SIGNAL(toggled(bool)),
-                this, SLOT(trustedStateChanged(bool)));
-    }
+
+    kcmUi->messages->hide();
+
+    kcmUi->pair_button->setVisible(false);
+    kcmUi->progressBar->setVisible(true);
+
+    connect(currentDevice,SIGNAL(pairingSuccesful()),
+            this, SLOT(pairingSuccesful()));
+    connect(currentDevice,SIGNAL(pairingFailed(QString)),
+            this, SLOT(pairingFailed(QString)));
+
+    currentDevice->requestPair();
+
+}
+
+void KdeConnectKcm::unpair()
+{
+    if (!currentDevice) return;
+
+    kcmUi->pair_button->setVisible(true);
+    kcmUi->unpair_button->setVisible(false);
+    kcmUi->progressBar->setVisible(false);
+    kcmUi->ping_button->setVisible(false);
+
+    currentDevice->unpair();
+
+    kcmUi->status_label->setText("(unpaired)");
+
+    devicesModel->deviceStatusChanged(currentDevice->id());
+}
+
+void KdeConnectKcm::pairingFailed(const QString& error)
+{
+    kcmUi->messages->setText("Error trying to pair: "+error);
+    kcmUi->messages->animatedShow();
+    kcmUi->progressBar->setVisible(false);
+    kcmUi->pair_button->setVisible(true);
+}
+
+void KdeConnectKcm::pairingSuccesful()
+{
+    kcmUi->progressBar->setVisible(false);
+    kcmUi->unpair_button->setVisible(true);
+    kcmUi->pair_button->setVisible(false);
+    kcmUi->ping_button->setVisible(true);
+
+    kcmUi->status_label->setText("(paired)");
+
+    devicesModel->deviceStatusChanged(currentDevice->id());
 }
 
 void KdeConnectKcm::pluginsConfigChanged()
@@ -147,8 +206,8 @@ void KdeConnectKcm::pluginsConfigChanged()
     //Store previous selection
     if (!currentDevice) return;
 
-    DeviceDbusInterface* auxCurrentDevice = currentDevice; //HACK to avoid infinite recursion (for some reason calling save on pluginselector emits changed)
-    currentDevice = 0;
+    DeviceDbusInterface* auxCurrentDevice = currentDevice;
+    currentDevice = 0; //HACK to avoid infinite recursion (for some reason calling save on pluginselector emits changed)
     kcmUi->pluginSelector->save();
     currentDevice = auxCurrentDevice;
 
diff --git a/kcm/kcm.h b/kcm/kcm.h
index 2fc8fd1..6dcbc55 100644
--- a/kcm/kcm.h
+++ b/kcm/kcm.h
@@ -56,10 +56,12 @@ private:
 
 private Q_SLOTS:
     void deviceSelected(const QModelIndex& current);
-    void trustedStateChanged(bool);
+    void requestPair();
     void pluginsConfigChanged();
     void sendPing();
     void resetSelection();
+    void pairingSuccesful();
+    void pairingFailed(const QString& error);
 
 private:
     Ui::KdeConnectKcmUi* kcmUi;
@@ -69,8 +71,8 @@ private:
     DeviceDbusInterface* currentDevice;
     QModelIndex currentIndex;
     //KSharedConfigPtr config;
-
-
+public slots:
+    void unpair();
 };
 
 #endif
diff --git a/kcm/kcm.ui b/kcm/kcm.ui
index b9879b6..8b86b16 100644
--- a/kcm/kcm.ui
+++ b/kcm/kcm.ui
@@ -54,79 +54,129 @@
      </property>
      <layout class="QVBoxLayout" name="deviceInfoBorder">
       <item>
-       <widget class="QGroupBox" name="deviceInfo">
+       <widget class="QWidget" name="deviceInfo" native="true">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
-        <property name="title">
-         <string/>
-        </property>
-        <property name="flat">
-         <bool>true</bool>
-        </property>
-        <property name="checkable">
-         <bool>false</bool>
-        </property>
         <layout class="QVBoxLayout" name="verticalLayout_2">
          <item>
-          <layout class="QHBoxLayout" name="horizontalLayout">
-           <item>
-            <widget class="QLabel" name="deviceName">
-             <property name="font">
-              <font>
-               <pointsize>10</pointsize>
-               <weight>75</weight>
-               <bold>true</bold>
-              </font>
-             </property>
-             <property name="text">
-              <string>Device</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <spacer name="horizontalSpacer">
-             <property name="orientation">
-              <enum>Qt::Horizontal</enum>
-             </property>
-             <property name="sizeHint" stdset="0">
-              <size>
-               <width>40</width>
-               <height>20</height>
-              </size>
-             </property>
-            </spacer>
-           </item>
-           <item>
-            <widget class="QCheckBox" name="trust_checkbox">
-             <property name="sizePolicy">
-              <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
-               <horstretch>0</horstretch>
-               <verstretch>0</verstretch>
-              </sizepolicy>
-             </property>
-             <property name="text">
-              <string>Trust this device</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QPushButton" name="ping_button">
-             <property name="sizePolicy">
-              <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
-               <horstretch>0</horstretch>
-               <verstretch>0</verstretch>
-              </sizepolicy>
-             </property>
-             <property name="text">
-              <string>Send ping</string>
-             </property>
-            </widget>
-           </item>
-          </layout>
+          <widget class="QWidget" name="header_2" native="true">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <layout class="QHBoxLayout" name="header">
+            <property name="sizeConstraint">
+             <enum>QLayout::SetMaximumSize</enum>
+            </property>
+            <item>
+             <widget class="QLabel" name="name_label">
+              <property name="font">
+               <font>
+                <pointsize>10</pointsize>
+                <weight>75</weight>
+                <bold>true</bold>
+               </font>
+              </property>
+              <property name="text">
+               <string>Device</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QLabel" name="status_label">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="text">
+               <string>(status)</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QProgressBar" name="progressBar">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="minimum">
+               <number>0</number>
+              </property>
+              <property name="maximum">
+               <number>0</number>
+              </property>
+              <property name="value">
+               <number>-1</number>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QPushButton" name="pair_button">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="text">
+               <string>Request pair</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QPushButton" name="unpair_button">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="text">
+               <string>Unpair</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QPushButton" name="ping_button">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="text">
+               <string>Send ping</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="KMessageWidget" name="messages" native="true"/>
          </item>
          <item>
           <widget class="KPluginSelector" name="pluginSelector" native="true">
@@ -156,6 +206,12 @@
    <header>kpluginselector.h</header>
    <container>1</container>
   </customwidget>
+  <customwidget>
+   <class>KMessageWidget</class>
+   <extends>QWidget</extends>
+   <header>kmessagewidget.h</header>
+   <container>1</container>
+  </customwidget>
  </customwidgets>
  <resources/>
  <connections/>
diff --git a/libkdeconnect/devicesmodel.cpp b/libkdeconnect/devicesmodel.cpp
index 1fc81ec..ccca795 100644
--- a/libkdeconnect/devicesmodel.cpp
+++ b/libkdeconnect/devicesmodel.cpp
@@ -121,7 +121,7 @@ void DevicesModel::refreshDeviceList()
         DeviceDbusInterface* deviceDbusInterface = new DeviceDbusInterface(id,this);
 
         bool onlyPaired = (m_displayFilter & StatusPaired);
-        if (onlyPaired && !deviceDbusInterface->paired()) continue;
+        if (onlyPaired && !deviceDbusInterface->isPaired()) continue;
         bool onlyReachable = (m_displayFilter & StatusReachable);
         if (onlyReachable && !deviceDbusInterface->reachable()) continue;
 
@@ -154,7 +154,7 @@ QVariant DevicesModel::data(const QModelIndex &index, int role) const
     //FIXME: This function gets called lots of times, producing lots of dbus calls. Add a cache.
     switch (role) {
         case IconModelRole: {
-            bool paired = device->paired();
+            bool paired = device->isPaired();
             bool reachable = device->reachable();
             QString icon = reachable? (paired? "user-online" : "user-busy") : "user-offline";
             return KIcon(icon).pixmap(32, 32);
@@ -169,7 +169,7 @@ QVariant DevicesModel::data(const QModelIndex &index, int role) const
             int status = StatusUnknown;
             if (device->reachable()) {
                 status |= StatusReachable;
-                if (device->paired()) status |= StatusPaired;
+                if (device->isPaired()) status |= StatusPaired;
             }
             return status;
         }

-- 
kdeconnect packaging



More information about the pkg-kde-commits mailing list