File indexing completed on 2024-12-08 12:15:36
0001 /* 0002 * BluezQt - Asynchronous Bluez wrapper library 0003 * 0004 * SPDX-FileCopyrightText: 2014-2015 David Rosca <nowrep@gmail.com> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #include "obexmanager_p.h" 0010 #include "debug.h" 0011 #include "obexmanager.h" 0012 #include "obexsession.h" 0013 #include "obexsession_p.h" 0014 #include "utils.h" 0015 0016 #include <QDBusServiceWatcher> 0017 0018 namespace BluezQt 0019 { 0020 typedef org::freedesktop::DBus::ObjectManager DBusObjectManager; 0021 0022 ObexManagerPrivate::ObexManagerPrivate(ObexManager *qq) 0023 : QObject(qq) 0024 , q(qq) 0025 , m_obexClient(nullptr) 0026 , m_obexAgentManager(nullptr) 0027 , m_dbusObjectManager(nullptr) 0028 , m_initialized(false) 0029 , m_obexRunning(false) 0030 , m_loaded(false) 0031 { 0032 qDBusRegisterMetaType<DBusManagerStruct>(); 0033 qDBusRegisterMetaType<QVariantMapMap>(); 0034 0035 m_timer.setSingleShot(true); 0036 connect(&m_timer, &QTimer::timeout, this, &ObexManagerPrivate::load); 0037 } 0038 0039 void ObexManagerPrivate::init() 0040 { 0041 // Keep an eye on org.bluez.obex service 0042 QDBusServiceWatcher *serviceWatcher = new QDBusServiceWatcher(Strings::orgBluezObex(), 0043 DBusConnection::orgBluezObex(), 0044 QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration, 0045 this); 0046 0047 connect(serviceWatcher, &QDBusServiceWatcher::serviceRegistered, this, &ObexManagerPrivate::serviceRegistered); 0048 connect(serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &ObexManagerPrivate::serviceUnregistered); 0049 0050 // Update the current state of org.bluez.obex service 0051 if (!DBusConnection::orgBluezObex().isConnected()) { 0052 Q_EMIT initError(QStringLiteral("DBus session bus is not connected!")); 0053 return; 0054 } 0055 0056 QDBusMessage call = 0057 QDBusMessage::createMethodCall(Strings::orgFreedesktopDBus(), QStringLiteral("/"), Strings::orgFreedesktopDBus(), QStringLiteral("NameHasOwner")); 0058 0059 call << Strings::orgBluezObex(); 0060 0061 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(DBusConnection::orgBluezObex().asyncCall(call)); 0062 connect(watcher, &QDBusPendingCallWatcher::finished, this, &ObexManagerPrivate::nameHasOwnerFinished); 0063 } 0064 0065 void ObexManagerPrivate::nameHasOwnerFinished(QDBusPendingCallWatcher *watcher) 0066 { 0067 const QDBusPendingReply<bool> &reply = *watcher; 0068 watcher->deleteLater(); 0069 0070 if (reply.isError()) { 0071 Q_EMIT initError(reply.error().message()); 0072 return; 0073 } 0074 0075 m_obexRunning = reply.value(); 0076 0077 if (m_obexRunning) { 0078 load(); 0079 } else { 0080 m_initialized = true; 0081 Q_EMIT initFinished(); 0082 } 0083 } 0084 0085 void ObexManagerPrivate::load() 0086 { 0087 if (!m_obexRunning || m_loaded) { 0088 return; 0089 } 0090 0091 // Force QDBus to cache owner of org.bluez.obex - this will be the only blocking call on session connection 0092 DBusConnection::orgBluezObex() 0093 .connect(Strings::orgBluezObex(), QStringLiteral("/"), Strings::orgFreedesktopDBus(), QStringLiteral("Dummy"), this, SLOT(dummy())); 0094 0095 m_dbusObjectManager = new DBusObjectManager(Strings::orgBluezObex(), QStringLiteral("/"), DBusConnection::orgBluezObex(), this); 0096 0097 connect(m_dbusObjectManager, &DBusObjectManager::InterfacesAdded, this, &ObexManagerPrivate::interfacesAdded); 0098 connect(m_dbusObjectManager, &DBusObjectManager::InterfacesRemoved, this, &ObexManagerPrivate::interfacesRemoved); 0099 0100 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(m_dbusObjectManager->GetManagedObjects(), this); 0101 connect(watcher, &QDBusPendingCallWatcher::finished, this, &ObexManagerPrivate::getManagedObjectsFinished); 0102 } 0103 0104 void ObexManagerPrivate::getManagedObjectsFinished(QDBusPendingCallWatcher *watcher) 0105 { 0106 const QDBusPendingReply<DBusManagerStruct> &reply = *watcher; 0107 watcher->deleteLater(); 0108 0109 if (reply.isError()) { 0110 Q_EMIT initError(reply.error().message()); 0111 return; 0112 } 0113 0114 DBusManagerStruct::const_iterator it; 0115 const DBusManagerStruct &managedObjects = reply.value(); 0116 0117 for (it = managedObjects.constBegin(); it != managedObjects.constEnd(); ++it) { 0118 const QString &path = it.key().path(); 0119 const QVariantMapMap &interfaces = it.value(); 0120 0121 if (interfaces.contains(Strings::orgBluezObexSession1())) { 0122 addSession(path, interfaces.value(Strings::orgBluezObexSession1())); 0123 } else if (interfaces.contains(Strings::orgBluezObexClient1()) && interfaces.contains(Strings::orgBluezObexAgentManager1())) { 0124 m_obexClient = new ObexClient(Strings::orgBluezObex(), path, DBusConnection::orgBluezObex(), this); 0125 m_obexAgentManager = new ObexAgentManager(Strings::orgBluezObex(), path, DBusConnection::orgBluezObex(), this); 0126 } 0127 } 0128 0129 if (!m_obexClient) { 0130 Q_EMIT initError(QStringLiteral("Cannot find org.bluez.obex.Client1 object!")); 0131 return; 0132 } 0133 0134 if (!m_obexAgentManager) { 0135 Q_EMIT initError(QStringLiteral("Cannot find org.bluez.obex.AgentManager1 object!")); 0136 return; 0137 } 0138 0139 m_loaded = true; 0140 m_initialized = true; 0141 0142 Q_EMIT q->operationalChanged(true); 0143 Q_EMIT initFinished(); 0144 } 0145 0146 void ObexManagerPrivate::clear() 0147 { 0148 m_loaded = false; 0149 0150 // Delete all sessions 0151 while (!m_sessions.isEmpty()) { 0152 ObexSessionPtr session = m_sessions.begin().value(); 0153 m_sessions.remove(m_sessions.begin().key()); 0154 Q_EMIT q->sessionRemoved(session); 0155 } 0156 0157 // Delete all other objects 0158 if (m_obexClient) { 0159 m_obexClient->deleteLater(); 0160 m_obexClient = nullptr; 0161 } 0162 0163 if (m_obexAgentManager) { 0164 m_obexAgentManager->deleteLater(); 0165 m_obexAgentManager = nullptr; 0166 } 0167 0168 if (m_dbusObjectManager) { 0169 m_dbusObjectManager->deleteLater(); 0170 m_dbusObjectManager = nullptr; 0171 } 0172 } 0173 0174 void ObexManagerPrivate::serviceRegistered() 0175 { 0176 qCDebug(BLUEZQT) << "Obex service registered"; 0177 m_obexRunning = true; 0178 0179 // Client1 and AgentManager1 objects are not ready by the time org.bluez.obex is registered 0180 // nor will the ObjectManager emits interfacesAdded for adding them... 0181 // So we delay the call to load() by 0.5s 0182 m_timer.start(500); 0183 } 0184 0185 void ObexManagerPrivate::serviceUnregistered() 0186 { 0187 qCDebug(BLUEZQT) << "Obex service unregistered"; 0188 m_obexRunning = false; 0189 0190 clear(); 0191 Q_EMIT q->operationalChanged(false); 0192 } 0193 0194 void ObexManagerPrivate::interfacesAdded(const QDBusObjectPath &objectPath, const QVariantMapMap &interfaces) 0195 { 0196 const QString &path = objectPath.path(); 0197 QVariantMapMap::const_iterator it; 0198 0199 for (it = interfaces.constBegin(); it != interfaces.constEnd(); ++it) { 0200 if (it.key() == Strings::orgBluezObexSession1()) { 0201 addSession(path, it.value()); 0202 } 0203 } 0204 } 0205 0206 void ObexManagerPrivate::interfacesRemoved(const QDBusObjectPath &objectPath, const QStringList &interfaces) 0207 { 0208 const QString &path = objectPath.path(); 0209 0210 for (const QString &interface : interfaces) { 0211 if (interface == Strings::orgBluezObexSession1()) { 0212 removeSession(path); 0213 } 0214 } 0215 } 0216 0217 void ObexManagerPrivate::addSession(const QString &sessionPath, const QVariantMap &properties) 0218 { 0219 ObexSessionPtr session = ObexSessionPtr(new ObexSession(sessionPath, properties)); 0220 session->d->q = session.toWeakRef(); 0221 m_sessions.insert(sessionPath, session); 0222 0223 Q_EMIT q->sessionAdded(session); 0224 } 0225 0226 void ObexManagerPrivate::removeSession(const QString &sessionPath) 0227 { 0228 ObexSessionPtr session = m_sessions.take(sessionPath); 0229 if (!session) { 0230 return; 0231 } 0232 0233 Q_EMIT q->sessionRemoved(session); 0234 } 0235 0236 void ObexManagerPrivate::dummy() 0237 { 0238 } 0239 0240 } // namespace BluezQt 0241 0242 #include "moc_obexmanager_p.cpp"