1 /**
2 * SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5 */
6
7 #include "pluginloader.h"
8
9 #include <QVector>
10 #include <QPluginLoader>
11 #include <KPluginMetaData>
12 #include <KPluginLoader>
13 #include <KPluginFactory>
14 #include <QStaticPlugin>
15
16 #include "core_debug.h"
17 #include "device.h"
18 #include "kdeconnectplugin.h"
19
20 //In older Qt released, qAsConst isnt available
21 #include "qtcompat_p.h"
22
instance()23 PluginLoader* PluginLoader::instance()
24 {
25 static PluginLoader* instance = new PluginLoader();
26 return instance;
27 }
28
PluginLoader()29 PluginLoader::PluginLoader()
30 {
31 #ifdef SAILFISHOS
32 const QVector<QStaticPlugin> staticPlugins = QPluginLoader::staticPlugins();
33 for (auto& staticPlugin : staticPlugins) {
34 QJsonObject jsonMetadata = staticPlugin.metaData().value(QStringLiteral("MetaData")).toObject();
35 KPluginMetaData metadata(jsonMetadata, QString());
36 if (metadata.serviceTypes().contains(QStringLiteral("KdeConnect/Plugin"))) {
37 plugins.insert(metadata.pluginId(), metadata);
38 pluginsFactories.insert(
39 metadata.pluginId(),
40 qobject_cast<KPluginFactory*>(staticPlugin.instance()));
41 }
42 }
43 #else
44 const QVector<KPluginMetaData> data = KPluginLoader::findPlugins(QStringLiteral("kdeconnect/"));
45 for (const KPluginMetaData& metadata : data) {
46 plugins[metadata.pluginId()] = metadata;
47 }
48 #endif
49 }
50
getPluginList() const51 QStringList PluginLoader::getPluginList() const
52 {
53 return plugins.keys();
54 }
55
getPluginInfo(const QString & name) const56 KPluginMetaData PluginLoader::getPluginInfo(const QString& name) const
57 {
58 return plugins.value(name);
59 }
60
instantiatePluginForDevice(const QString & pluginName,Device * device) const61 KdeConnectPlugin* PluginLoader::instantiatePluginForDevice(const QString& pluginName, Device* device) const
62 {
63 KdeConnectPlugin* ret = nullptr;
64
65 KPluginMetaData service = plugins.value(pluginName);
66 if (!service.isValid()) {
67 qCDebug(KDECONNECT_CORE) << "Plugin unknown" << pluginName;
68 return ret;
69 }
70
71 #ifdef SAILFISHOS
72 KPluginFactory* factory = pluginsFactories.value(pluginName);
73 #else
74 KPluginLoader loader(service.fileName());
75 KPluginFactory* factory = loader.factory();
76 if (!factory) {
77 qCDebug(KDECONNECT_CORE) << "KPluginFactory could not load the plugin:" << service.pluginId() << loader.errorString();
78 return ret;
79 }
80 #endif
81
82 const QStringList outgoingInterfaces = KPluginMetaData::readStringList(service.rawData(), QStringLiteral("X-KdeConnect-OutgoingPacketType"));
83
84 QVariant deviceVariant = QVariant::fromValue<Device*>(device);
85
86 ret = factory->create<KdeConnectPlugin>(device, QVariantList() << deviceVariant << pluginName << outgoingInterfaces << service.iconName());
87 if (!ret) {
88 qCDebug(KDECONNECT_CORE) << "Error loading plugin";
89 return ret;
90 }
91
92 //qCDebug(KDECONNECT_CORE) << "Loaded plugin:" << service.pluginId();
93 return ret;
94 }
95
incomingCapabilities() const96 QStringList PluginLoader::incomingCapabilities() const
97 {
98 QSet<QString> ret;
99 for (const KPluginMetaData& service : qAsConst(plugins)) {
100 ret += KPluginMetaData::readStringList(service.rawData(), QStringLiteral("X-KdeConnect-SupportedPacketType")).toSet();
101 }
102 return ret.values();
103 }
104
outgoingCapabilities() const105 QStringList PluginLoader::outgoingCapabilities() const
106 {
107 QSet<QString> ret;
108 for (const KPluginMetaData& service : qAsConst(plugins)) {
109 ret += KPluginMetaData::readStringList(service.rawData(), QStringLiteral("X-KdeConnect-OutgoingPacketType")).toSet();
110 }
111 return ret.values();
112 }
113
pluginsForCapabilities(const QSet<QString> & incoming,const QSet<QString> & outgoing)114 QSet<QString> PluginLoader::pluginsForCapabilities(const QSet<QString>& incoming, const QSet<QString>& outgoing)
115 {
116 QSet<QString> ret;
117
118 for (const KPluginMetaData& service : qAsConst(plugins)) {
119 const QSet<QString> pluginIncomingCapabilities = KPluginMetaData::readStringList(service.rawData(), QStringLiteral("X-KdeConnect-SupportedPacketType")).toSet();
120 const QSet<QString> pluginOutgoingCapabilities = KPluginMetaData::readStringList(service.rawData(), QStringLiteral("X-KdeConnect-OutgoingPacketType")).toSet();
121
122 bool capabilitiesEmpty = (pluginIncomingCapabilities.isEmpty() && pluginOutgoingCapabilities.isEmpty());
123 #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
124 bool capabilitiesIntersect = (outgoing.intersects(pluginIncomingCapabilities) || incoming.intersects(pluginOutgoingCapabilities));
125 #else
126 QSet<QString> commonIncoming = incoming;
127 commonIncoming.intersect(pluginOutgoingCapabilities);
128 QSet<QString> commonOutgoing = outgoing;
129 commonOutgoing.intersect(pluginIncomingCapabilities);
130 bool capabilitiesIntersect = (!commonIncoming.isEmpty() || !commonOutgoing.isEmpty());
131 #endif
132
133 if (capabilitiesIntersect || capabilitiesEmpty) {
134 ret += service.pluginId();
135 } else {
136 qCDebug(KDECONNECT_CORE) << "Not loading plugin" << service.pluginId() << "because device doesn't support it";
137 }
138 }
139
140 return ret;
141 }
142