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"