Improved package dispatch to the different plugins
Before this patch, all plugins had to discard received packages that were not for themselves. This could be a security problem (a plugin could sniff other plugin's packages) and also adds some complexity and processing. This patch makes the device instance aware of what services are required by the different plugins and when a package is received the corresponding plugins will get the package. These services will be listed on the plugin's desktop file, so the user can decide whether to enable a plugin. Note that this only works for receiving, not sending. REVIEW: 113210
This commit is contained in:
parent
63488781b9
commit
5e151d185e
22 changed files with 68 additions and 65 deletions
|
@ -1,12 +1,10 @@
|
|||
#include "device.h"
|
||||
|
||||
#include <KSharedPtr>
|
||||
#include <KSharedConfig>
|
||||
#include <KConfigGroup>
|
||||
#include <KStandardDirs>
|
||||
#include <KPluginSelector>
|
||||
#include <KServiceTypeTrader>
|
||||
#include <KPluginInfo>
|
||||
#include <KNotification>
|
||||
#include <KIcon>
|
||||
|
||||
|
@ -66,7 +64,8 @@ QStringList Device::loadedPlugins() const
|
|||
|
||||
void Device::reloadPlugins()
|
||||
{
|
||||
QMap< QString, KdeConnectPlugin* > newPluginMap;
|
||||
QMap<QString, KdeConnectPlugin*> newPluginMap;
|
||||
QMultiMap<QString, KdeConnectPlugin*> newPluginsByInterface;
|
||||
|
||||
if (isPaired() && isReachable()) { //Do not load any plugin for unpaired devices, nor useless loading them for unreachable devices
|
||||
|
||||
|
@ -83,18 +82,19 @@ void Device::reloadPlugins()
|
|||
: loader->getPluginInfo(pluginName).isPluginEnabledByDefault());
|
||||
|
||||
if (isPluginEnabled) {
|
||||
KdeConnectPlugin* reusedPluginInstance = m_plugins.take(pluginName);
|
||||
if (reusedPluginInstance) {
|
||||
//Already loaded, reuse it
|
||||
newPluginMap[pluginName] = reusedPluginInstance;
|
||||
KdeConnectPlugin* plugin = m_plugins.take(pluginName);
|
||||
QStringList interfaces;
|
||||
if (plugin) {
|
||||
interfaces = m_pluginsByinterface.keys(plugin);
|
||||
} else {
|
||||
KdeConnectPlugin* plugin = loader->instantiatePluginForDevice(pluginName, this);
|
||||
|
||||
connect(this, SIGNAL(receivedPackage(NetworkPackage)),
|
||||
plugin, SLOT(receivePackage(NetworkPackage)));
|
||||
|
||||
newPluginMap[pluginName] = plugin;
|
||||
PluginData data = loader->instantiatePluginForDevice(pluginName, this);
|
||||
plugin = data.plugin;
|
||||
interfaces = data.interfaces;
|
||||
}
|
||||
foreach(const QString& interface, interfaces) {
|
||||
newPluginsByInterface.insert(interface, plugin);
|
||||
}
|
||||
newPluginMap[pluginName] = plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +103,7 @@ void Device::reloadPlugins()
|
|||
//them anymore, otherwise they would have been moved to the newPluginMap)
|
||||
qDeleteAll(m_plugins);
|
||||
m_plugins = newPluginMap;
|
||||
m_pluginsByinterface = newPluginsByInterface;
|
||||
|
||||
Q_FOREACH(KdeConnectPlugin* plugin, m_plugins) {
|
||||
plugin->connected();
|
||||
|
@ -346,16 +347,14 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
|
|||
|
||||
}
|
||||
|
||||
} else if (!isPaired()) {
|
||||
|
||||
} else if (isPaired()) {
|
||||
QList<KdeConnectPlugin*> plugins = m_pluginsByinterface.values(np.type());
|
||||
foreach(KdeConnectPlugin* plugin, plugins) {
|
||||
plugin->receivePackage(np);
|
||||
}
|
||||
} else {
|
||||
//TODO: Notify the other side that we don't trust them
|
||||
qDebug() << "device" << name() << "not paired, ignoring package" << np.type();
|
||||
|
||||
} else {
|
||||
|
||||
//Forward package
|
||||
Q_EMIT receivedPackage(np);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -415,7 +414,7 @@ QStringList Device::availableLinks() const
|
|||
|
||||
void Device::sendPing()
|
||||
{
|
||||
NetworkPackage np("kdeconnect.ping");
|
||||
NetworkPackage np(PACKAGE_TYPE_PING);
|
||||
bool success = sendPackage(np);
|
||||
qDebug() << "sendPing:" << success;
|
||||
}
|
||||
|
|
|
@ -82,10 +82,6 @@ public:
|
|||
Q_SCRIPTABLE QStringList loadedPlugins() const;
|
||||
Q_SCRIPTABLE bool hasPlugin(const QString& name) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
///notifies about a @p np package that has just been received from the device
|
||||
void receivedPackage(const NetworkPackage& np) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
///sends a @p np package to the device
|
||||
virtual bool sendPackage(NetworkPackage& np);
|
||||
|
@ -121,6 +117,7 @@ private:
|
|||
|
||||
QList<DeviceLink*> m_deviceLinks;
|
||||
QMap<QString, KdeConnectPlugin*> m_plugins;
|
||||
QMultiMap<QString, KdeConnectPlugin*> m_pluginsByinterface;
|
||||
|
||||
QTimer pairingTimer;
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#define PACKAGE_TYPE_IDENTITY QLatin1String("kdeconnect.identity")
|
||||
#define PACKAGE_TYPE_PAIR QLatin1String("kdeconnect.pair")
|
||||
#define PACKAGE_TYPE_ENCRYPTED QLatin1String("kdeconnect.encrypted")
|
||||
#define PACKAGE_TYPE_TELEPHONY QLatin1String("kdeconnect.telephony")
|
||||
#define PACKAGE_TYPE_PING QLatin1String("kdeconnect.ping")
|
||||
|
||||
#endif // NETWORKPACKAGETYPES_H
|
||||
|
|
|
@ -58,9 +58,6 @@ BatteryPlugin::~BatteryPlugin()
|
|||
|
||||
bool BatteryPlugin::receivePackage(const NetworkPackage& np)
|
||||
{
|
||||
|
||||
if (np.type() != PACKAGE_TYPE_BATTERY) return false;
|
||||
|
||||
bool isCharging = np.get<bool>("isCharging");
|
||||
int currentCharge = np.get<int>("currentCharge");
|
||||
|
||||
|
|
|
@ -37,3 +37,5 @@ Comment[ru]=Показывать значок батареи устройств
|
|||
Comment[sv]=Visa telefonens batteri intill datorbatteriet
|
||||
Comment[uk]=Показ даних щодо рівня заряду акумулятора на телефоні поряд з даними щодо рівня заряду акумулятора комп’ютера
|
||||
Comment[x-test]=xxShow your phone battery next to your computer batteryxx
|
||||
|
||||
X-KdeConnect-SupportedPackageType=kdeconnect.battery
|
||||
|
|
|
@ -29,8 +29,8 @@ K_EXPORT_PLUGIN( KdeConnectPluginFactory("kdeconnect_clipboard", "kdeconnect_cli
|
|||
|
||||
ClipboardPlugin::ClipboardPlugin(QObject *parent, const QVariantList &args)
|
||||
: KdeConnectPlugin(parent, args)
|
||||
, clipboard(QApplication::clipboard())
|
||||
, ignore_next_clipboard_change(false)
|
||||
, clipboard(QApplication::clipboard())
|
||||
{
|
||||
connect(clipboard, SIGNAL(changed(QClipboard::Mode)), this, SLOT(clipboardChanged(QClipboard::Mode)));
|
||||
}
|
||||
|
@ -51,10 +51,7 @@ void ClipboardPlugin::clipboardChanged(QClipboard::Mode mode)
|
|||
|
||||
bool ClipboardPlugin::receivePackage(const NetworkPackage& np)
|
||||
{
|
||||
if (np.type() == PACKAGE_TYPE_CLIPBOARD) {
|
||||
ignore_next_clipboard_change = true;
|
||||
clipboard->setText(np.get<QString>("content"));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -37,3 +37,5 @@ Comment[ru]=Общий буфер обмена для всех устройст
|
|||
Comment[sv]=Dela klippbordet mellan apparater
|
||||
Comment[uk]=Спільне використання буфера обміну даними на пристроях
|
||||
Comment[x-test]=xxShare the clipboard between devicesxx
|
||||
|
||||
X-KdeConnect-SupportedPackageType=kdeconnect.clipboard
|
||||
|
|
|
@ -15,3 +15,7 @@ Name[sk]=Plugin KDEConnect
|
|||
Name[sv]=KDE anslutningsinsticksprogram
|
||||
Name[uk]=Додаток KDEConnect
|
||||
Name[x-test]=xxKDEConnect Pluginxx
|
||||
|
||||
# mandatory, list of all the package types supported
|
||||
[PropertyDef::X-KdeConnect-SupportedPackageType]
|
||||
Type=QStringList
|
||||
|
|
|
@ -34,3 +34,5 @@ Comment[ru]=Дистанционное управление музыкой и в
|
|||
Comment[sv]=Fjärrstyr musik och videor
|
||||
Comment[uk]=Віддалене керування відтворенням музики та відео
|
||||
Comment[x-test]=xxRemote control your music and videosxx
|
||||
|
||||
X-KdeConnect-SupportedPackageType=kdeconnect.mpris
|
||||
|
|
|
@ -137,11 +137,6 @@ void MprisControlPlugin::removePlayer(const QString& ifaceName)
|
|||
|
||||
bool MprisControlPlugin::receivePackage (const NetworkPackage& np)
|
||||
{
|
||||
|
||||
if (np.type() != PACKAGE_TYPE_MPRIS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (np.has("playerList")) {
|
||||
return false; //Whoever sent this is an mpris client and not an mpris control!
|
||||
}
|
||||
|
|
|
@ -35,3 +35,5 @@ Comment[ru]=Показывать телефонные уведомления в
|
|||
Comment[sv]=Visa telefonunderrättelser i KDE och håll dem synkroniserade
|
||||
Comment[uk]=Показ сповіщень з телефону у KDE та підтримання синхронізації даних сповіщень
|
||||
Comment[x-test]=xxShow phone notifications in KDE and keep them in syncxx
|
||||
|
||||
X-KdeConnect-SupportedPackageType=kdeconnect.notifications
|
||||
|
|
|
@ -56,7 +56,6 @@ 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);
|
||||
|
|
|
@ -33,3 +33,5 @@ Comment[ru]=Приостанавливать музыку/видео во вре
|
|||
Comment[sv]=Pausa musik eller videor under ett telefonsamtal
|
||||
Comment[uk]=Призупинка відтворення музики і відео на час телефонних дзвінків
|
||||
Comment[x-test]=xxPause music/videos during a phone callxx
|
||||
|
||||
X-KdeConnect-SupportedPackageType=kdeconnect.telephony
|
||||
|
|
|
@ -38,11 +38,6 @@ PauseMusicPlugin::PauseMusicPlugin(QObject* parent, const QVariantList& args)
|
|||
|
||||
bool PauseMusicPlugin::receivePackage(const NetworkPackage& np)
|
||||
{
|
||||
|
||||
if (np.type() != PACKAGE_TYPE_TELEPHONY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(pauseWhen) {
|
||||
case PauseWhenRinging:
|
||||
if (np.get<QString>("event") != "ringing" && np.get<QString>("event") != "talking") {
|
||||
|
@ -54,6 +49,8 @@ bool PauseMusicPlugin::receivePackage(const NetworkPackage& np)
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
case NeverPause:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pauseConditionFulfilled = !np.get<bool>("isCancel");
|
||||
|
@ -76,7 +73,7 @@ bool PauseMusicPlugin::receivePackage(const NetworkPackage& np)
|
|||
} else {
|
||||
Q_FOREACH (const QString& iface, pausedSources) {
|
||||
QDBusInterface mprisInterface(iface, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player");
|
||||
//Calling play does not work in spotify
|
||||
//Calling play does not work for Spotify
|
||||
//mprisInterface->call(QDBus::Block,"Play");
|
||||
//Workaround: Using playpause instead (checking first if it is already playing)
|
||||
QString status = mprisInterface.property("PlaybackStatus").toString();
|
||||
|
|
|
@ -39,3 +39,5 @@ Comment[sk]=Poslať a prijať pingy
|
|||
Comment[sv]=Skicka och ta emot ping
|
||||
Comment[uk]=Надсилання і отримання сигналів підтримання зв’язку
|
||||
Comment[x-test]=xxSend and receive pingsxx
|
||||
|
||||
X-KdeConnect-SupportedPackageType=kdeconnect.ping
|
||||
|
|
|
@ -42,9 +42,6 @@ PingPlugin::~PingPlugin()
|
|||
|
||||
bool PingPlugin::receivePackage(const NetworkPackage& np)
|
||||
{
|
||||
|
||||
if (np.type() != PACKAGE_TYPE_PING) return false;
|
||||
|
||||
KNotification* notification = new KNotification("pingReceived"); //KNotification::Persistent
|
||||
notification->setPixmap(KIcon("dialog-ok").pixmap(48, 48));
|
||||
notification->setComponentData(KComponentData("kdeconnect", "kdeconnect"));
|
||||
|
|
|
@ -59,30 +59,33 @@ KPluginInfo PluginLoader::getPluginInfo(const QString& name) const
|
|||
return KPluginInfo(service);
|
||||
}
|
||||
|
||||
KdeConnectPlugin* PluginLoader::instantiatePluginForDevice(const QString& name, Device* device) const
|
||||
PluginData PluginLoader::instantiatePluginForDevice(const QString& name, Device* device) const
|
||||
{
|
||||
PluginData ret;
|
||||
|
||||
KService::Ptr service = plugins[name];
|
||||
if (!service) {
|
||||
qDebug() << "Plugin unknown" << name;
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
KPluginFactory *factory = KPluginLoader(service->library()).factory();
|
||||
if (!factory) {
|
||||
qDebug() << "KPluginFactory could not load the plugin:" << service->library();
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret.interfaces = service->property("X-KdeConnect-SupportedPackageType", QVariant::StringList).toStringList();
|
||||
|
||||
QVariant deviceVariant = QVariant::fromValue<Device*>(device);
|
||||
|
||||
//FIXME: create<KdeConnectPlugin> return NULL
|
||||
QObject *plugin = factory->create<QObject>(device, QVariantList() << deviceVariant);
|
||||
if (!plugin) {
|
||||
ret.plugin = (KdeConnectPlugin*) factory->create<QObject>(device, QVariantList() << deviceVariant);
|
||||
if (!ret.plugin) {
|
||||
qDebug() << "Error loading plugin";
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
qDebug() << "Loaded plugin:" << service->name();
|
||||
return (KdeConnectPlugin*)plugin;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,13 @@
|
|||
class Device;
|
||||
class KdeConnectPlugin;
|
||||
|
||||
struct PluginData
|
||||
{
|
||||
PluginData() : plugin(0) {}
|
||||
KdeConnectPlugin* plugin;
|
||||
QStringList interfaces;
|
||||
};
|
||||
|
||||
class PluginLoader
|
||||
{
|
||||
|
||||
|
@ -40,7 +47,7 @@ public:
|
|||
|
||||
QStringList getPluginList() const;
|
||||
KPluginInfo getPluginInfo(const QString& name) const;
|
||||
KdeConnectPlugin* instantiatePluginForDevice(const QString& name, Device* device) const;
|
||||
PluginData instantiatePluginForDevice(const QString& name, Device* device) const;
|
||||
|
||||
private:
|
||||
PluginLoader();
|
||||
|
|
|
@ -29,3 +29,5 @@ Comment[ru]=Получать общие файлы и адреса URL с тел
|
|||
Comment[sv]=Ta emot filer och webbadresser att dela från din telefon
|
||||
Comment[uk]=Отримання файлів та адрес, наданих у спільне користування з вашого телефону
|
||||
Comment[x-test]=xxReceive files and URLs shared from your phonexx
|
||||
|
||||
X-KdeConnect-SupportedPackageType=kdeconnect.share
|
||||
|
|
|
@ -66,7 +66,6 @@ bool ShareReceiverPlugin::receivePackage(const NetworkPackage& np)
|
|||
}
|
||||
*/
|
||||
|
||||
if (np.type() != PACKAGE_TYPE_SHARE) return false;
|
||||
qDebug() << "File transfer";
|
||||
|
||||
if (np.hasPayload()) {
|
||||
|
|
|
@ -80,9 +80,6 @@ KNotification* TelephonyPlugin::createNotification(const NetworkPackage& np)
|
|||
|
||||
bool TelephonyPlugin::receivePackage(const NetworkPackage& np)
|
||||
{
|
||||
|
||||
if (np.type() != PACKAGE_TYPE_TELEPHONY) return false;
|
||||
|
||||
if (np.get<bool>("isCancel")) {
|
||||
|
||||
//It would be awesome to remove the old notification from the system tray here, but there is no way to do it :(
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
#include <KStatusNotifierItem>
|
||||
|
||||
#define PACKAGE_TYPE_TELEPHONY QLatin1String("kdeconnect.telephony")
|
||||
|
||||
class TelephonyPlugin
|
||||
: public KdeConnectPlugin
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue