File indexing completed on 2024-04-21 04:56:44

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 "daemon.h"
0008 
0009 #include <QDBusMetaType>
0010 #include <QDebug>
0011 #include <QNetworkAccessManager>
0012 #include <QPointer>
0013 #include <QProcess>
0014 
0015 #include "core_debug.h"
0016 #include "dbushelper.h"
0017 #include "kdeconnectconfig.h"
0018 #include "networkpacket.h"
0019 #include "notificationserverinfo.h"
0020 
0021 #ifdef KDECONNECT_BLUETOOTH
0022 #include "backends/bluetooth/bluetoothlinkprovider.h"
0023 #endif
0024 
0025 #include "backends/devicelink.h"
0026 #include "backends/lan/lanlinkprovider.h"
0027 #include "backends/linkprovider.h"
0028 #include "backends/loopback/loopbacklinkprovider.h"
0029 #include "device.h"
0030 
0031 static Daemon *s_instance = nullptr;
0032 
0033 struct DaemonPrivate {
0034     // Different ways to find devices and connect to them
0035     QSet<LinkProvider *> m_linkProviders;
0036 
0037     // Every known device
0038     QMap<QString, Device *> m_devices;
0039 
0040     bool m_testMode;
0041 };
0042 
0043 Daemon *Daemon::instance()
0044 {
0045     Q_ASSERT(s_instance != nullptr);
0046     return s_instance;
0047 }
0048 
0049 Daemon::Daemon(QObject *parent, bool testMode)
0050     : QObject(parent)
0051     , d(new DaemonPrivate)
0052 {
0053     Q_ASSERT(!s_instance);
0054     s_instance = this;
0055     d->m_testMode = testMode;
0056 
0057     // HACK init may call pure virtual functions from this class so it can't be called directly from the ctor
0058     QTimer::singleShot(0, this, &Daemon::init);
0059 }
0060 
0061 void Daemon::init()
0062 {
0063     qCDebug(KDECONNECT_CORE) << "Daemon starting";
0064 
0065     // Load backends
0066     if (d->m_testMode)
0067         d->m_linkProviders.insert(new LoopbackLinkProvider());
0068     else {
0069         d->m_linkProviders.insert(new LanLinkProvider());
0070 #ifdef KDECONNECT_BLUETOOTH
0071         d->m_linkProviders.insert(new BluetoothLinkProvider());
0072 #endif
0073 #ifdef KDECONNECT_LOOPBACK
0074         d->m_linkProviders.insert(new LoopbackLinkProvider());
0075 #endif
0076     }
0077 
0078     // Register on DBus
0079     qDBusRegisterMetaType<QMap<QString, QString>>();
0080     QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.kdeconnect"));
0081     QDBusConnection::sessionBus().registerObject(QStringLiteral("/modules/kdeconnect"), this, QDBusConnection::ExportScriptableContents);
0082 
0083     // Read remembered paired devices
0084     const QStringList &list = KdeConnectConfig::instance().trustedDevices();
0085     for (const QString &id : list) {
0086         addDevice(new Device(this, id));
0087     }
0088 
0089     // Listen to new devices
0090     for (LinkProvider *a : qAsConst(d->m_linkProviders)) {
0091         connect(a, &LinkProvider::onConnectionReceived, this, &Daemon::onNewDeviceLink);
0092         a->onStart();
0093     }
0094 
0095     NotificationServerInfo::instance().init();
0096 
0097     qCDebug(KDECONNECT_CORE) << "Daemon started";
0098 }
0099 
0100 void Daemon::removeDevice(Device *device)
0101 {
0102     d->m_devices.remove(device->id());
0103     device->deleteLater();
0104     Q_EMIT deviceRemoved(device->id());
0105     Q_EMIT deviceListChanged();
0106 }
0107 
0108 void Daemon::forceOnNetworkChange()
0109 {
0110     qCDebug(KDECONNECT_CORE) << "Sending onNetworkChange to" << d->m_linkProviders.size() << "LinkProviders";
0111     for (LinkProvider *a : qAsConst(d->m_linkProviders)) {
0112         a->onNetworkChange();
0113     }
0114 }
0115 
0116 Device *Daemon::getDevice(const QString &deviceId)
0117 {
0118     for (Device *device : qAsConst(d->m_devices)) {
0119         if (device->id() == deviceId) {
0120             return device;
0121         }
0122     }
0123     return nullptr;
0124 }
0125 
0126 QSet<LinkProvider *> Daemon::getLinkProviders() const
0127 {
0128     return d->m_linkProviders;
0129 }
0130 
0131 QStringList Daemon::devices(bool onlyReachable, bool onlyTrusted) const
0132 {
0133     QStringList ret;
0134     for (Device *device : qAsConst(d->m_devices)) {
0135         if (onlyReachable && !device->isReachable())
0136             continue;
0137         if (onlyTrusted && !device->isPaired())
0138             continue;
0139         ret.append(device->id());
0140     }
0141     return ret;
0142 }
0143 
0144 QMap<QString, QString> Daemon::deviceNames(bool onlyReachable, bool onlyTrusted) const
0145 {
0146     QMap<QString, QString> ret;
0147     for (Device *device : qAsConst(d->m_devices)) {
0148         if (onlyReachable && !device->isReachable())
0149             continue;
0150         if (onlyTrusted && !device->isPaired())
0151             continue;
0152         ret[device->id()] = device->name();
0153     }
0154     return ret;
0155 }
0156 
0157 void Daemon::onNewDeviceLink(DeviceLink *link)
0158 {
0159     QString id = link->deviceId();
0160 
0161     qCDebug(KDECONNECT_CORE) << "Device discovered" << id << "via link with priority" << link->priority();
0162 
0163     if (d->m_devices.contains(id)) {
0164         qCDebug(KDECONNECT_CORE) << "It is a known device" << link->deviceInfo().name;
0165         Device *device = d->m_devices[id];
0166         bool wasReachable = device->isReachable();
0167         device->addLink(link);
0168         if (!wasReachable) {
0169             Q_EMIT deviceVisibilityChanged(id, true);
0170             Q_EMIT deviceListChanged();
0171         }
0172     } else {
0173         qCDebug(KDECONNECT_CORE) << "It is a new device" << link->deviceInfo().name;
0174         Device *device = new Device(this, link);
0175         addDevice(device);
0176     }
0177 }
0178 
0179 void Daemon::onDeviceStatusChanged()
0180 {
0181     Device *device = (Device *)sender();
0182 
0183     // qCDebug(KDECONNECT_CORE) << "Device" << device->name() << "status changed. Reachable:" << device->isReachable() << ". Paired: " << device->isPaired();
0184 
0185     if (!device->isReachable() && !device->isPaired()) {
0186         // qCDebug(KDECONNECT_CORE) << "Destroying device" << device->name();
0187         removeDevice(device);
0188     } else {
0189         Q_EMIT deviceVisibilityChanged(device->id(), device->isReachable());
0190         Q_EMIT deviceListChanged();
0191     }
0192 }
0193 
0194 void Daemon::setAnnouncedName(const QString &name)
0195 {
0196     qCDebug(KDECONNECT_CORE) << "Announcing name";
0197     KdeConnectConfig::instance().setName(name);
0198     forceOnNetworkChange();
0199     Q_EMIT announcedNameChanged(name);
0200 }
0201 
0202 void Daemon::setCustomDevices(const QStringList &addresses)
0203 {
0204     auto &config = KdeConnectConfig::instance();
0205 
0206     auto customDevices = config.customDevices();
0207     if (customDevices != addresses) {
0208         qCDebug(KDECONNECT_CORE) << "Changed list of custom device addresses:" << addresses;
0209         config.setCustomDevices(addresses);
0210         Q_EMIT customDevicesChanged(addresses);
0211 
0212         forceOnNetworkChange();
0213     }
0214 }
0215 
0216 QStringList Daemon::customDevices() const
0217 {
0218     return KdeConnectConfig::instance().customDevices();
0219 }
0220 
0221 QString Daemon::announcedName()
0222 {
0223     return KdeConnectConfig::instance().name();
0224 }
0225 
0226 QNetworkAccessManager *Daemon::networkAccessManager()
0227 {
0228     static QPointer<QNetworkAccessManager> manager;
0229     if (!manager) {
0230         manager = new QNetworkAccessManager(this);
0231     }
0232     return manager;
0233 }
0234 
0235 QList<Device *> Daemon::devicesList() const
0236 {
0237     return d->m_devices.values();
0238 }
0239 
0240 QString Daemon::deviceIdByName(const QString &name) const
0241 {
0242     for (Device *device : qAsConst(d->m_devices)) {
0243         if (device->name() == name && device->isPaired())
0244             return device->id();
0245     }
0246     return {};
0247 }
0248 
0249 void Daemon::addDevice(Device *device)
0250 {
0251     const QString id = device->id();
0252     connect(device, &Device::reachableChanged, this, &Daemon::onDeviceStatusChanged);
0253     connect(device, &Device::pairStateChanged, this, &Daemon::onDeviceStatusChanged);
0254     connect(device, &Device::pairStateChanged, this, &Daemon::pairingRequestsChanged);
0255     connect(device, &Device::pairStateChanged, this, [this, device](int pairStateAsInt) {
0256         PairState pairState = (PairState)pairStateAsInt;
0257         if (pairState == PairState::RequestedByPeer)
0258             askPairingConfirmation(device);
0259     });
0260     d->m_devices[id] = device;
0261 
0262     Q_EMIT deviceAdded(id);
0263     Q_EMIT deviceListChanged();
0264 }
0265 
0266 QStringList Daemon::pairingRequests() const
0267 {
0268     QStringList ret;
0269     for (Device *dev : qAsConst(d->m_devices)) {
0270         if (dev->isPairRequestedByPeer())
0271             ret += dev->id();
0272     }
0273     return ret;
0274 }
0275 
0276 Daemon::~Daemon()
0277 {
0278 }
0279 
0280 QString Daemon::selfId() const
0281 {
0282     return KdeConnectConfig::instance().deviceId();
0283 }
0284 
0285 #include "moc_daemon.cpp"