File indexing completed on 2024-04-28 08:49:02

0001 /**
0002  * SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include "pluginloader.h"
0008 
0009 #include <KPluginFactory>
0010 #include <KPluginMetaData>
0011 #include <QPluginLoader>
0012 #include <QStaticPlugin>
0013 #include <QVector>
0014 
0015 #include "core_debug.h"
0016 #include "device.h"
0017 #include "kdeconnectconfig.h"
0018 #include "kdeconnectplugin.h"
0019 
0020 PluginLoader *PluginLoader::instance()
0021 {
0022     static PluginLoader *instance = new PluginLoader();
0023     return instance;
0024 }
0025 
0026 PluginLoader::PluginLoader()
0027 {
0028     const QVector<KPluginMetaData> data = KPluginMetaData::findPlugins(QStringLiteral("kdeconnect"));
0029     for (const KPluginMetaData &metadata : data) {
0030         plugins[metadata.pluginId()] = metadata;
0031     }
0032 }
0033 
0034 QStringList PluginLoader::getPluginList() const
0035 {
0036     return plugins.keys();
0037 }
0038 
0039 bool PluginLoader::doesPluginExist(const QString &name) const
0040 {
0041     return plugins.contains(name);
0042 }
0043 
0044 KPluginMetaData PluginLoader::getPluginInfo(const QString &name) const
0045 {
0046     return plugins.value(name);
0047 }
0048 
0049 KdeConnectPlugin *PluginLoader::instantiatePluginForDevice(const QString &pluginName, Device *device) const
0050 {
0051     const KPluginMetaData data = plugins.value(pluginName);
0052     if (!data.isValid()) {
0053         qCDebug(KDECONNECT_CORE) << "Plugin unknown" << pluginName;
0054         return nullptr;
0055     }
0056 
0057     const QStringList outgoingInterfaces = data.value(QStringLiteral("X-KdeConnect-OutgoingPacketType"), QStringList());
0058     const QVariantList args{QVariant::fromValue<Device *>(device), pluginName, outgoingInterfaces, data.iconName()};
0059 
0060     if (auto result = KPluginFactory::instantiatePlugin<KdeConnectPlugin>(data, device, args)) {
0061         qCDebug(KDECONNECT_CORE) << "Loaded plugin:" << data.pluginId();
0062         return result.plugin;
0063     } else {
0064         qCDebug(KDECONNECT_CORE) << "Error loading plugin" << result.errorText;
0065         return nullptr;
0066     }
0067 }
0068 
0069 QStringList PluginLoader::incomingCapabilities() const
0070 {
0071     QSet<QString> ret;
0072     for (const KPluginMetaData &service : plugins) {
0073         QStringList rawValues = service.value(QStringLiteral("X-KdeConnect-SupportedPacketType"), QStringList());
0074         ret += QSet<QString>(rawValues.begin(), rawValues.end());
0075     }
0076     return ret.values();
0077 }
0078 
0079 QStringList PluginLoader::outgoingCapabilities() const
0080 {
0081     QSet<QString> ret;
0082     for (const KPluginMetaData &service : plugins) {
0083         QStringList rawValues = service.value(QStringLiteral("X-KdeConnect-OutgoingPacketType"), QStringList());
0084         ret += QSet<QString>(rawValues.begin(), rawValues.end());
0085     }
0086     return ret.values();
0087 }
0088 
0089 QSet<QString> PluginLoader::pluginsForCapabilities(const QSet<QString> &incoming, const QSet<QString> &outgoing) const
0090 {
0091     QSet<QString> ret;
0092 
0093     QString myDeviceType = KdeConnectConfig::instance().deviceType().toString();
0094 
0095     for (const KPluginMetaData &service : plugins) {
0096         // Check if the plugin support this device type
0097         const QStringList supportedDeviceTypes = service.rawData().value(QStringLiteral("X-KdeConnect-SupportedDeviceTypes")).toVariant().toStringList();
0098         if (!supportedDeviceTypes.isEmpty()) {
0099             if (!supportedDeviceTypes.contains(myDeviceType)) {
0100                 qCDebug(KDECONNECT_CORE) << "Not loading plugin" << service.pluginId() << "because this device of type" << myDeviceType
0101                                          << "is not supported. Supports:" << supportedDeviceTypes.join(QStringLiteral(", "));
0102                 continue;
0103             }
0104         }
0105 
0106         // Check if capbilites intersect with the remote device
0107         const QStringList pluginIncomingCapabilities = service.rawData().value(QStringLiteral("X-KdeConnect-SupportedPacketType")).toVariant().toStringList();
0108         const QStringList pluginOutgoingCapabilities = service.rawData().value(QStringLiteral("X-KdeConnect-OutgoingPacketType")).toVariant().toStringList();
0109 
0110         bool capabilitiesEmpty = (pluginIncomingCapabilities.isEmpty() && pluginOutgoingCapabilities.isEmpty());
0111         if (!capabilitiesEmpty) {
0112             bool capabilitiesIntersect = (outgoing.intersects(QSet(pluginIncomingCapabilities.begin(), pluginIncomingCapabilities.end()))
0113                                           || incoming.intersects(QSet(pluginOutgoingCapabilities.begin(), pluginOutgoingCapabilities.end())));
0114 
0115             if (!capabilitiesIntersect) {
0116                 qCDebug(KDECONNECT_CORE) << "Not loading plugin" << service.pluginId() << "because device doesn't support it";
0117                 continue;
0118             }
0119         }
0120 
0121         // If we get here, the plugin can be loaded
0122         ret += service.pluginId();
0123     }
0124 
0125     return ret;
0126 }