1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
/*
SPDX-FileCopyrightText: 2017 Kai Uwe Broulik <kde@privat.broulik.de>
SPDX-FileCopyrightText: 2017 David Edmundson <davidedmundson@kde.org>
SPDX-License-Identifier: MIT
*/
#include "kdeconnectplugin.h"
#include "connection.h"
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusPendingReply>
static const QString s_kdeConnectServiceName = QStringLiteral("org.kde.kdeconnect");
static const QString s_kdeConnectObjectPath = QStringLiteral("/modules/kdeconnect");
static const QString s_kdeConnectDaemon = QStringLiteral("org.kde.kdeconnect.daemon");
KDEConnectPlugin::KDEConnectPlugin(QObject *parent)
: AbstractBrowserPlugin(QStringLiteral("kdeconnect"), 1, parent)
{
}
bool KDEConnectPlugin::onLoad()
{
QDBusConnection bus = QDBusConnection::sessionBus();
bus.connect(s_kdeConnectServiceName, s_kdeConnectObjectPath, s_kdeConnectDaemon, QStringLiteral("deviceAdded"), this, SLOT(onDeviceAdded(QString)));
bus.connect(s_kdeConnectServiceName, s_kdeConnectObjectPath, s_kdeConnectDaemon, QStringLiteral("deviceRemoved"), this, SLOT(onDeviceRemoved(QString)));
bus.connect(s_kdeConnectServiceName,
s_kdeConnectObjectPath,
s_kdeConnectDaemon,
QStringLiteral("deviceVisibilityChanged"),
this,
SLOT(onDeviceVisibilityChanged(QString, bool)));
QDBusMessage msg = QDBusMessage::createMethodCall(s_kdeConnectServiceName, s_kdeConnectObjectPath, s_kdeConnectDaemon, QStringLiteral("devices"));
msg.setArguments({true /* only reachable */, true /* only paired */});
QDBusPendingReply<QStringList> reply = bus.asyncCall(msg);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
QDBusPendingReply<QStringList> reply = *watcher;
watcher->deleteLater();
if (reply.isError()) {
debug() << "kdeconnect discovery failed:" << reply.error().name();
return;
}
const QStringList devices = reply.value();
for (const QString &deviceId : devices) {
onDeviceAdded(deviceId);
}
});
return true;
}
bool KDEConnectPlugin::onUnload()
{
QDBusConnection bus = QDBusConnection::sessionBus();
bus.disconnect(s_kdeConnectServiceName, s_kdeConnectObjectPath, s_kdeConnectDaemon, QStringLiteral("deviceAdded"), this, SLOT(onDeviceAdded(QString)));
bus.disconnect(s_kdeConnectServiceName, s_kdeConnectObjectPath, s_kdeConnectDaemon, QStringLiteral("deviceRemoved"), this, SLOT(onDeviceRemoved(QString)));
bus.disconnect(s_kdeConnectServiceName,
s_kdeConnectObjectPath,
s_kdeConnectDaemon,
QStringLiteral("deviceVisibilityChanged"),
this,
SLOT(onDeviceVisibilityChanged(QString, bool)));
const QStringList devices = m_devices;
for (const QString &deviceId : devices) {
onDeviceRemoved(deviceId);
}
return true;
}
void KDEConnectPlugin::onDeviceAdded(const QString &deviceId)
{
if (m_devices.contains(deviceId)) {
return;
}
QDBusMessage msg = QDBusMessage::createMethodCall(s_kdeConnectServiceName,
QStringLiteral("/modules/kdeconnect/devices/") + deviceId,
QStringLiteral("org.freedesktop.DBus.Properties"),
QStringLiteral("GetAll"));
msg.setArguments({QStringLiteral("org.kde.kdeconnect.device")});
QDBusPendingReply<QVariantMap> reply = QDBusConnection::sessionBus().asyncCall(msg);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, deviceId](QDBusPendingCallWatcher *watcher) {
QDBusPendingReply<QVariantMap> reply = *watcher;
watcher->deleteLater();
if (reply.isError()) {
debug() << "getting device for properties for" << deviceId << "failed:" << reply.error().message();
return;
}
// We might have gotten a second deviceAdded signal, check again.
if (m_devices.contains(deviceId)) {
return;
}
QVariantMap props = reply.value();
// Also check isTrusted for compatibility with older KDEConnect
const bool paired = props.value(QStringLiteral("isPaired")).toBool() || props.value(QStringLiteral("isTrusted")).toBool();
if (!props.value(QStringLiteral("isReachable")).toBool() || !paired) {
return;
}
props.insert(QStringLiteral("id"), deviceId);
m_devices.append(deviceId);
sendData(QStringLiteral("deviceAdded"), QJsonObject::fromVariantMap(props));
});
}
void KDEConnectPlugin::onDeviceRemoved(const QString &deviceId)
{
if (m_devices.removeOne(deviceId)) {
sendData(QStringLiteral("deviceRemoved"), {{QStringLiteral("id"), deviceId}});
}
}
void KDEConnectPlugin::onDeviceVisibilityChanged(const QString &deviceId, bool visible)
{
if (visible) {
onDeviceAdded(deviceId);
} else {
onDeviceRemoved(deviceId);
}
}
void KDEConnectPlugin::handleData(const QString &event, const QJsonObject &json)
{
if (event == QLatin1String("shareUrl")) {
const QString deviceId = json.value(QStringLiteral("deviceId")).toString();
const QString url = json.value(QStringLiteral("url")).toString();
debug() << "sending kde connect url" << url << "to device" << deviceId;
QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kdeconnect"),
QStringLiteral("/modules/kdeconnect/devices/") + deviceId + QStringLiteral("/share"),
QStringLiteral("org.kde.kdeconnect.device.share"),
QStringLiteral("shareUrl"));
msg.setArguments({url});
QDBusConnection::sessionBus().call(msg, QDBus::NoBlock);
}
}
#include "moc_kdeconnectplugin.cpp"
|