From bdff4999654cd45093acdfde5be41894cdd79c2b Mon Sep 17 00:00:00 2001 From: Aleix Pol Date: Sun, 12 Jun 2016 20:15:40 +0200 Subject: [PATCH] Remote Commands plugin Allows executing remote plugins from this client Reviewed by Albert Vaca --- cli/kdeconnect-cli.cpp | 16 ++++ interfaces/CMakeLists.txt | 1 + interfaces/dbusinterfaces.cpp | 5 ++ interfaces/dbusinterfaces.h | 10 +++ plugins/CMakeLists.txt | 1 + plugins/remotecommands/CMakeLists.txt | 8 ++ .../kdeconnect_remotecommands.json | 21 +++++ .../remotecommands/remotecommandsplugin.cpp | 89 +++++++++++++++++++ plugins/remotecommands/remotecommandsplugin.h | 60 +++++++++++++ 9 files changed, 211 insertions(+) create mode 100644 plugins/remotecommands/CMakeLists.txt create mode 100644 plugins/remotecommands/kdeconnect_remotecommands.json create mode 100644 plugins/remotecommands/remotecommandsplugin.cpp create mode 100644 plugins/remotecommands/remotecommandsplugin.h diff --git a/cli/kdeconnect-cli.cpp b/cli/kdeconnect-cli.cpp index 776ff138d..6f386b6e6 100644 --- a/cli/kdeconnect-cli.cpp +++ b/cli/kdeconnect-cli.cpp @@ -62,6 +62,8 @@ int main(int argc, char** argv) parser.addOption(QCommandLineOption(QStringList("device") << "d", i18n("Device ID"), "dev")); parser.addOption(QCommandLineOption(QStringList("name") << "n", i18n("Device Name"), "name")); parser.addOption(QCommandLineOption("encryption-info", i18n("Get encryption info about said device"))); + parser.addOption(QCommandLineOption("list-commands", i18n("Lists remote commands and their ids"))); + parser.addOption(QCommandLineOption("execute-command", i18n("Executes a remote command by id"), "id")); about.setupCommandLine(&parser); parser.addHelpOption(); @@ -190,6 +192,20 @@ int main(int argc, char** argv) QTextStream(stdout) << "- " << idx.data(NotificationsModel::AppNameModelRole).toString() << ": " << idx.data(NotificationsModel::NameModelRole).toString() << endl; } + } else if(parser.isSet("list-commands")) { + RemoteCommandsDbusInterface iface(device); + const auto cmds = QJsonDocument::fromJson(iface.commands()).object(); + for (auto it = cmds.constBegin(), itEnd = cmds.constEnd(); it!=itEnd; ++it) { + const QJsonObject cont = it->toObject(); + QTextStream(stdout) << it.key() << ": " << cont.value("name").toString() << ": " << cont.value("command").toString() << endl; + } + const auto err = iface.lastError(); + if (err.isValid()) { + QTextStream(stderr) << err.message() << endl; + } + } else if(parser.isSet("execute-command")) { + RemoteCommandsDbusInterface iface(device); + iface.triggerCommand(parser.value("execute-command")); } else if(parser.isSet("encryption-info")) { DeviceDbusInterface dev(device); QDBusPendingReply devReply = dev.encryptionInfo(); // QSsl::Der = 1 diff --git a/interfaces/CMakeLists.txt b/interfaces/CMakeLists.txt index 2fa6c8b7a..01f9fd4be 100644 --- a/interfaces/CMakeLists.txt +++ b/interfaces/CMakeLists.txt @@ -43,6 +43,7 @@ geninterface(${CMAKE_SOURCE_DIR}/plugins/notifications/notification.h notificati geninterface(${CMAKE_SOURCE_DIR}/plugins/mprisremote/mprisremoteplugin.h mprisremoteinterface) geninterface(${CMAKE_SOURCE_DIR}/plugins/remotecontrol/remotecontrolplugin.h remotecontrolinterface) geninterface(${CMAKE_SOURCE_DIR}/plugins/lockdevice/lockdeviceplugin.h lockdeviceinterface) +geninterface(${CMAKE_SOURCE_DIR}/plugins/remotecommands/remotecommandsplugin.h remotecommandsinterface) add_library(kdeconnectinterfaces SHARED ${libkdeconnect_SRC}) diff --git a/interfaces/dbusinterfaces.cpp b/interfaces/dbusinterfaces.cpp index 10f051c4e..ff2f81577 100644 --- a/interfaces/dbusinterfaces.cpp +++ b/interfaces/dbusinterfaces.cpp @@ -147,6 +147,11 @@ FindMyPhoneDeviceDbusInterface::~FindMyPhoneDeviceDbusInterface() { } +RemoteCommandsDbusInterface::RemoteCommandsDbusInterface(const QString& deviceId, QObject* parent): + OrgKdeKdeconnectDeviceRemotecommandsInterface(DaemonDbusInterface::activatedService(), "/modules/kdeconnect/devices/" + deviceId + "/remotecommands", QDBusConnection::sessionBus(), parent) +{ +} +RemoteCommandsDbusInterface::~RemoteCommandsDbusInterface() = default; #include "dbusinterfaces.moc" diff --git a/interfaces/dbusinterfaces.h b/interfaces/dbusinterfaces.h index ffc22f49e..e1baefd89 100644 --- a/interfaces/dbusinterfaces.h +++ b/interfaces/dbusinterfaces.h @@ -33,6 +33,7 @@ #include "interfaces/mprisremoteinterface.h" #include "interfaces/remotecontrolinterface.h" #include "interfaces/lockdeviceinterface.h" +#include "interfaces/remotecommandsinterface.h" /** * Using these "proxy" classes just in case we need to rename the @@ -166,4 +167,13 @@ public: virtual ~FindMyPhoneDeviceDbusInterface(); }; +class KDECONNECTINTERFACES_EXPORT RemoteCommandsDbusInterface + : public OrgKdeKdeconnectDeviceRemotecommandsInterface +{ + Q_OBJECT +public: + explicit RemoteCommandsDbusInterface(const QString& deviceId, QObject* parent = nullptr); + ~RemoteCommandsDbusInterface() override; +}; + #endif diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 2a49306f4..3d644705d 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -10,6 +10,7 @@ add_subdirectory(notifications) add_subdirectory(sendnotifications) add_subdirectory(battery) add_subdirectory(runcommand) +add_subdirectory(remotecommands) if(NOT WIN32) add_subdirectory(pausemusic) add_subdirectory(mpriscontrol) diff --git a/plugins/remotecommands/CMakeLists.txt b/plugins/remotecommands/CMakeLists.txt new file mode 100644 index 000000000..334cf445d --- /dev/null +++ b/plugins/remotecommands/CMakeLists.txt @@ -0,0 +1,8 @@ +kdeconnect_add_plugin(kdeconnect_remotecommands JSON kdeconnect_remotecommands.json + SOURCES remotecommandsplugin.cpp +) + +target_link_libraries(kdeconnect_remotecommands + kdeconnectcore + Qt5::DBus + KF5::I18n) diff --git a/plugins/remotecommands/kdeconnect_remotecommands.json b/plugins/remotecommands/kdeconnect_remotecommands.json new file mode 100644 index 000000000..67710ec1e --- /dev/null +++ b/plugins/remotecommands/kdeconnect_remotecommands.json @@ -0,0 +1,21 @@ +{ + "Encoding": "UTF-8", + "KPlugin": { + "Authors": [ + { + "Email": "aleixpol@kde.org", + "Name": "Aleix Pol" + } + ], + "Name": "Execute remote commands", + "Description": "Trigger commands predefined on the remote device", + "EnabledByDefault": true, + "Icon": "system-run", + "Id": "kdeconnect_remotecommands", + "License": "GPL", + "ServiceTypes": [ "KdeConnect/Plugin" ], + "Version": "0.1" + }, + "X-KdeConnect-OutgoingPackageType": [ "kdeconnect.runcommand.request" ], + "X-KdeConnect-SupportedPackageType": [ "kdeconnect.runcommand" ] +} diff --git a/plugins/remotecommands/remotecommandsplugin.cpp b/plugins/remotecommands/remotecommandsplugin.cpp new file mode 100644 index 000000000..95d528585 --- /dev/null +++ b/plugins/remotecommands/remotecommandsplugin.cpp @@ -0,0 +1,89 @@ +/** + * Copyright 2016 Aleix Pol Gonzalez + * + * 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 . + */ + +#include "remotecommandsplugin.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define PACKAGE_TYPE_RUNCOMMAND_REQUEST QLatin1String("kdeconnect.runcommand.request") + +K_PLUGIN_FACTORY_WITH_JSON( KdeConnectPluginFactory, "kdeconnect_remotecommands.json", registerPlugin< RemoteCommandsPlugin >(); ) + +Q_LOGGING_CATEGORY(KDECONNECT_PLUGIN_REMOTECOMMANDS, "kdeconnect.plugin.remotecommands") + +RemoteCommandsPlugin::RemoteCommandsPlugin(QObject* parent, const QVariantList& args) + : KdeConnectPlugin(parent, args) + , m_commands("{}") +{ +} + +RemoteCommandsPlugin::~RemoteCommandsPlugin() = default; + +bool RemoteCommandsPlugin::receivePackage(const NetworkPackage& np) +{ + if (np.has("commandList")) { + setCommands(np.get("commandList")); + return true; + } + + return false; +} + +void RemoteCommandsPlugin::connected() +{ + QDBusConnection::sessionBus().registerObject(dbusPath(), this, QDBusConnection::ExportAllContents); + + NetworkPackage np(PACKAGE_TYPE_RUNCOMMAND_REQUEST); + np.set("requestCommandList", true); + sendPackage(np); +} + +QString RemoteCommandsPlugin::dbusPath() const +{ + return "/modules/kdeconnect/devices/" + device()->id() + "/remotecommands"; +} + +void RemoteCommandsPlugin::setCommands(const QByteArray &cmds) +{ + if (m_commands != cmds) { + m_commands = cmds; + Q_EMIT commandsChanged(m_commands); + } +} + +void RemoteCommandsPlugin::triggerCommand(const QString &key) +{ + NetworkPackage np(PACKAGE_TYPE_RUNCOMMAND_REQUEST); + np.set("key", key); + sendPackage(np); +} + +#include "remotecommandsplugin.moc" diff --git a/plugins/remotecommands/remotecommandsplugin.h b/plugins/remotecommands/remotecommandsplugin.h new file mode 100644 index 000000000..cc9563d78 --- /dev/null +++ b/plugins/remotecommands/remotecommandsplugin.h @@ -0,0 +1,60 @@ +/** + * Copyright 2016 Aleix Pol Gonzalez + * + * 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 . + */ + +#ifndef REMOTECOMMANDSPLUGIN_H +#define REMOTECOMMANDSPLUGIN_H + +#include + +#include +#include +#include +#include +#include +#include + +class Q_DECL_EXPORT RemoteCommandsPlugin + : public KdeConnectPlugin +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.device.remotecommands") + Q_PROPERTY(QByteArray commands READ commands NOTIFY commandsChanged) + +public: + explicit RemoteCommandsPlugin(QObject *parent, const QVariantList &args); + ~RemoteCommandsPlugin() override; + + Q_INVOKABLE void triggerCommand(const QString &key); + QByteArray commands() const { return m_commands; } + +Q_SIGNALS: + void commandsChanged(const QByteArray& commands); + +private: + bool receivePackage(const NetworkPackage& np) override; + void connected() override; + + QString dbusPath() const; + void setCommands(const QByteArray &commands); + + QByteArray m_commands; +}; + +#endif