summaryrefslogtreecommitdiffstats
path: root/src/libtdebluez/objectmanagerImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libtdebluez/objectmanagerImpl.cpp')
-rw-r--r--src/libtdebluez/objectmanagerImpl.cpp607
1 files changed, 607 insertions, 0 deletions
diff --git a/src/libtdebluez/objectmanagerImpl.cpp b/src/libtdebluez/objectmanagerImpl.cpp
new file mode 100644
index 0000000..789e221
--- /dev/null
+++ b/src/libtdebluez/objectmanagerImpl.cpp
@@ -0,0 +1,607 @@
+/*
+ *
+ * Object Manager implementation of bluez5
+ *
+ * Copyright (C) 2018 Emanoil Kotsev <[email protected]>
+ *
+ *
+ * This file is part of libtdebluez.
+ *
+ * libtdebluez is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libtdebluez is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kbluetooth; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <tqstringlist.h>
+
+#include <tqdbusmessage.h>
+#include <tqdbusobjectpath.h>
+#include <tqdbusdatamap.h>
+#include <tqdbusdata.h>
+#include <tqdbusdatalist.h>
+#include <tqdbusvariant.h>
+
+#include "objectmanagerImpl.h"
+#include "btuuids.h"
+
+namespace TDEBluetooth
+{
+
+ObjectManagerImpl::ObjectManagerImpl(const TQString& service, const TQString& path, TQObject* parent, const char* name) :
+ ObjectManagerProxy(service, path, parent, name)
+{
+ agentManager = 0;
+ profileManager = 0;
+ healthManager = 0;
+ agentRegisteredStatus = false;
+ agentIsDefaultAgent = false;
+ // init connection to dbus
+ initDBUS();
+}
+
+ObjectManagerImpl::~ObjectManagerImpl()
+{
+ // close D-Bus connection
+ close();
+
+ if(agentManager)
+ delete agentManager;
+ if(profileManager)
+ delete profileManager;
+ if(healthManager)
+ delete healthManager;
+}
+
+/*!
+ * This function try a reconnect to D-Bus.
+ * \return boolean with the result of the operation
+ * \retval true if successful reconnected to D-Bus
+ * \retval false if unsuccessful
+ */
+bool ObjectManagerImpl::reconnect()
+{
+ // close D-Bus connection
+ close();
+ // init D-Bus conntection
+ return (initDBUS());
+}
+
+/*!
+ * This function return information about connection status to the DBUS daemon.
+ * \return boolean with the state of the connection to D-Bus
+ * \retval true if connected
+ * \retval false if disconnected
+ */
+bool ObjectManagerImpl::isConnectedToDBUS()
+{
+ return dBusConn.isConnected();
+}
+
+/*!
+ * This function returns pointer to connection of the DBUS.
+ * \return TQT_DBusConnection* of the connection to D-Bus
+ * \retval TQT_DBusConnection*
+ */
+TQT_DBusConnection* ObjectManagerImpl::getConnection()
+{
+ return &dBusConn;
+}
+
+/*!
+ * This function close the connection to manager over the D-Bus daemon.
+ * \return boolean with the result of the operation
+ * \retval true if successful closed the connection
+ * \retval false if any problems
+ */
+bool ObjectManagerImpl::close()
+{
+ disconnect(this, SIGNAL(InterfacesAdded(const TQT_DBusObjectPath&, const TQT_DBusDataMap< TQString >&)),
+ this, SLOT(slotInterfacesAdded(const TQT_DBusObjectPath&, const TQT_DBusDataMap< TQString >& )));
+ disconnect(this, SIGNAL(InterfacesRemoved(const TQT_DBusObjectPath& , const TQStringList& )),
+ this, SLOT(slotInterfacesRemoved(const TQT_DBusObjectPath& , const TQStringList& )));
+
+ for (PropertiesMap::iterator it = adapters.begin(); it != adapters.end();
+ ++it)
+ {
+ org::freedesktop::DBus::PropertiesProxy *p;
+ p = it.data();
+ if (p != NULL)
+ delete p;
+ }
+ for (PropertiesMap::iterator it = devices.begin(); it != devices.end();
+ ++it)
+ {
+ org::freedesktop::DBus::PropertiesProxy *p;
+ p = it.data();
+ if (p != NULL)
+ delete p;
+ }
+ adapters.clear();
+ devices.clear();
+
+ dBusConn.closeConnection(DBUS_CONN_NAME);
+ return true;
+}
+
+/*!
+ * This function initializes the connection to the D-Bus daemon.
+ * \return pointer to AgentManager1Proxy
+ */
+AgentManager1Proxy * ObjectManagerImpl::getAgentManager()
+{
+ return agentManager;
+}
+
+/*!
+ * This function initializes the connection to the D-Bus daemon.
+ * \return pointer to ProfileManager1Proxy
+ */
+ProfileManager1Proxy * ObjectManagerImpl::getProfileManager()
+{
+ return profileManager;
+}
+
+/*!
+ * This function initializes the connection to the D-Bus daemon.
+ * \return pointer to HealthManager1Proxy
+ */
+HealthManager1Proxy * ObjectManagerImpl::getHealthManager()
+{
+ return healthManager;
+}
+
+/*!
+ * This function returns a list of objectpaths
+ * \return TQValueList<TQString>
+ * \retval TQValueList<TQString>
+ */
+ObjectManagerImpl::AdapterList ObjectManagerImpl::getAdapters()
+{
+ return adapters.keys();
+}
+
+/*!
+ * This function returns a list of objectpaths
+ * \return TQValueList<TQString>
+ * \retval TQValueList<TQString>
+ */
+ObjectManagerImpl::DeviceList ObjectManagerImpl::getDevices()
+{
+ return devices.keys();
+}
+
+ObjectManagerImpl::ConnectionList ObjectManagerImpl::listConnections(const TQString &adapter)
+{
+ ConnectionList list;
+ return list;
+}
+
+bool ObjectManagerImpl::registerAgent()
+{
+ if (!agentRegisteredStatus)
+ {
+ TQT_DBusError error;
+ agentManager->RegisterAgent(
+ TQT_DBusObjectPath(TQCString(DBUS_AUTH_SERVICE_PATH)), DEVICE_PIN_CAPABILITY, error);
+ if (error.isValid())
+ {
+ tqDebug("Could not register agent: %s", error.message().local8Bit().data());
+ return false;
+ }
+ agentRegisteredStatus = true;
+ }
+ return true;
+}
+
+bool ObjectManagerImpl::unregisterAgent()
+{
+ kdDebug() << k_funcinfo << endl;
+ if (agentRegisteredStatus)
+ {
+ TQT_DBusError error;
+ getAgentManager()->UnregisterAgent(
+ TQT_DBusObjectPath(TQCString(DBUS_AUTH_SERVICE_PATH)), error);
+ if (error.isValid())
+ {
+ tqDebug("Could not unregister agent");
+ return false;
+ }
+ agentRegisteredStatus = false;
+ agentIsDefaultAgent = false;
+ }
+ return true;
+}
+
+bool ObjectManagerImpl::requestDefaultAgent()
+{
+ TQT_DBusError error;
+ agentManager->RequestDefaultAgent(
+ TQT_DBusObjectPath(TQCString(DBUS_AUTH_SERVICE_PATH)), error);
+ if (error.isValid())
+ {
+ tqDebug("Could not request default agent: %s", error.message().local8Bit().data());
+ return false;
+ }
+ agentIsDefaultAgent = true;
+ return true;
+}
+
+bool ObjectManagerImpl::isAgentRegistered()
+{
+ return agentRegisteredStatus;
+}
+
+bool ObjectManagerImpl::isAgentDefaultAgent()
+{
+ return agentIsDefaultAgent;
+}
+
+/*!
+ * This function initializes the connection to the D-Bus daemon.
+ * \return boolean with the result of the operation
+ * \retval true if successful initialized D-Bus connection
+ * \retval false if unsuccessful
+ */
+bool ObjectManagerImpl::initDBUS()
+{
+ dBusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus, DBUS_CONN_NAME);
+ if (!dBusConn.isConnected())
+ {
+ tqDebug("Failed to open connection to system message bus: %s", dBusConn.lastError().message().local8Bit().data());
+ TQTimer::singleShot(4000, this, TQT_SLOT(reconnect()));
+ return false;
+ }
+ setConnection(dBusConn);
+
+ TQT_DBusDataMap<TQT_DBusObjectPath> objects;
+ TQT_DBusError error;
+ if (!GetManagedObjects(objects, error))
+ {
+ tqDebug("GetManagedObjects(objects,error) FAILED:\n%s\n", error.message().latin1());
+ return false;
+ }
+
+ TQT_DBusDataMap<TQT_DBusObjectPath>::const_iterator it = objects.begin();
+ for (it; it != objects.end(); ++it)
+ {
+ bool ok = false;
+ slotInterfacesAdded(it.key(), it.data().toStringKeyMap(&ok));
+ if (!ok)
+ tqWarning("Failed to convert dbus data to string map: %s", it.key().latin1());
+ }
+
+ connect(this, SIGNAL(InterfacesAdded(const TQT_DBusObjectPath&, const TQT_DBusDataMap< TQString >&)),
+ this, SLOT(slotInterfacesAdded(const TQT_DBusObjectPath&, const TQT_DBusDataMap< TQString >& )));
+ connect(this, SIGNAL(InterfacesRemoved(const TQT_DBusObjectPath& , const TQStringList& )),
+ this, SLOT(slotInterfacesRemoved(const TQT_DBusObjectPath& , const TQStringList& )));
+
+ return true;
+}
+
+void ObjectManagerImpl::adapterPropertiesChanged(TQString path, const TQMap<
+ TQString, TQT_DBusVariant>& changed_properties)
+{
+ TQMap<TQString, TQT_DBusVariant>::const_iterator it;
+ for (it = changed_properties.begin(); it != changed_properties.end(); ++it)
+ {
+ bool ok = false;
+ if (it.key() == "Powered")
+ emit adapterPowerOnChanged(path, it.data().value.toBool(&ok));
+ else if (it.key() == "Class")
+ emit adapterClassChanged(path, it.data().value.toUInt32(&ok));
+ else if (it.key() == "Name")
+ emit adapterNameChanged(path, it.data().value.toString(&ok));
+ else if (it.key() == "Alias")
+ emit adapterAliasChanged(path, it.data().value.toString(&ok));
+ else if (it.key() == "DiscoverableTimeout")
+ emit adapterDiscoverableTimeoutChanged(path, it.data().value.toUInt32(&ok));
+ else if (it.key() == "Discoverable")
+ emit adapterDiscoverableChanged(path, it.data().value.toBool(&ok));
+ else if (it.key() == "Discovering")
+ emit adapterDiscoveringChanged(path, it.data().value.toBool(&ok));
+ else
+ continue;
+ if (!ok)
+ tqDebug("ObjectManagerImpl::adapterPropertiesChanged conversion failed");
+ }
+}
+
+void ObjectManagerImpl::devicePropertiesChanged(TQString path, const TQMap<TQString, TQT_DBusVariant>& changed_properties)
+{
+ // https://github.com/r10r/bluez/blob/master/doc/device-api.txt
+ TQMap<TQString, TQT_DBusVariant>::const_iterator it;
+ for (it = changed_properties.begin(); it != changed_properties.end(); ++it)
+ {
+ bool ok = false;
+ if (it.key() == "Address")
+ emit deviceAddressChanged(path, it.data().value.toString(&ok));
+ else if (it.key() == "Class")
+ emit deviceClassChanged(path, it.data().value.toUInt32(&ok));
+ else if (it.key() == "Name")
+ emit deviceNameChanged(path, it.data().value.toString(&ok));
+ else if (it.key() == "Alias")
+ emit deviceAliasChanged(path, it.data().value.toString(&ok));
+// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml
+ else if (it.key() == "Appearance")
+ emit deviceAppearanceChanged(path, it.data().value.toUInt16(&ok));
+ else if (it.key() == "Icon")
+ emit deviceIconChanged(path, it.data().value.toString(&ok));
+ else if (it.key() == "Paired")
+ emit devicePairedChanged(path, it.data().value.toBool(&ok));
+ else if (it.key() == "Trusted")
+ emit deviceTrustedChanged(path, it.data().value.toBool(&ok));
+ else if (it.key() == "Blocked")
+ emit deviceBlockedChanged(path, it.data().value.toBool(&ok));
+ else if (it.key() == "LegacyPairing")
+ emit deviceLegacyPairingChanged(path, it.data().value.toBool(&ok));
+ else if (it.key() == "RSSI")
+ emit deviceRSSIChanged(path, it.data().value.toInt16(&ok)); //INT16
+ else if (it.key() == "Connected")
+ emit deviceConnectedChanged(path, it.data().value.toBool(&ok));
+ else if (it.key() == "UUIDs")
+ {
+ TQT_DBusDataList vl = TQT_DBusDataList(it.data().value.toTQValueList(&ok));
+ emit deviceUUIDsChanged(path, vl.toStringList(&ok));
+ }
+ else if (it.key() == "Adapter")
+ emit deviceAdapterChanged(path, it.data().value.toObjectPath(&ok));
+ else if (it.key() == "ManufacturerData")
+ emit deviceManufacturerDataChanged(path, it.data().value.toUInt16KeyMap(&ok)); //a{qv}
+ else if (it.key() == "ServiceData")
+ emit deviceServiceDataChanged(path, it.data().value.toStringKeyMap(&ok)); //a{sv}
+ else if (it.key() == "TxPower")
+ emit deviceTxPowerChanged(path, it.data().value.toInt16(&ok)); //INT16
+ else if (it.key() == "ServicesResolved")
+ emit deviceServicesResolvedChanged(path, it.data().value.toBool(&ok));
+ else
+ continue;
+ if (!ok)
+ tqDebug("ObjectManagerImpl::devicePropertiesChanged conversion failed");
+ }
+
+}
+
+void ObjectManagerImpl::mediaControlPropertiesChanged(TQString path, const TQMap<TQString, TQT_DBusVariant>& changed_properties)
+{
+ TQMap<TQString, TQT_DBusVariant>::const_iterator it;
+ for (it = changed_properties.begin(); it != changed_properties.end(); ++it)
+ {
+ bool ok = false;
+ if (it.key() == "Connected")
+ emit mediaControlConnectedChanged(path, it.data().value.toBool(&ok));
+ else if (it.key() == "Player")
+ emit mediaControlPlayerChanged(path, it.data().value.toObjectPath(&ok));
+ else
+ continue;
+ if (!ok)
+ tqDebug("ObjectManagerImpl::mediaControlPropertiesChanged conversion failed");
+ }
+}
+
+void ObjectManagerImpl::slotInterfacesAdded(const TQT_DBusObjectPath& object, const TQT_DBusDataMap<TQString>& interfaces)
+{
+ TQT_DBusDataMap<TQString>::const_iterator it1 = interfaces.begin();
+ for (it1; it1 != interfaces.end(); it1++)
+ {
+ TQString interface = it1.key();
+ if (interface == "org.bluez.AgentManager1")
+ {
+ agentManager = new AgentManager1Proxy("org.bluez", object/*, this, "AgentManager1"*/);
+ if (agentManager)
+ agentManager->setConnection(dBusConn);
+ }
+ else if (interface == "org.bluez.ProfileManager1")
+ {
+ profileManager = new ProfileManager1Proxy("org.bluez", object/*, this, "ProfileManager1"*/);
+ if (profileManager)
+ profileManager->setConnection(dBusConn);
+ }
+ else if (interface == "org.bluez.HealthManager1")
+ {
+ healthManager = new HealthManager1Proxy("org.bluez", object/*, this, "HealthManager1"*/);
+ if (healthManager)
+ healthManager->setConnection(dBusConn);
+ }
+ else if (interface == "org.bluez.Adapter1")
+ {
+ org::freedesktop::DBus::PropertiesProxy *properties;
+ properties = new org::freedesktop::DBus::PropertiesProxy("org.bluez", object);
+ properties->setConnection(dBusConn);
+ connect(properties, SIGNAL(PropertiesChanged ( const TQString&, const TQMap< TQString, TQT_DBusVariant >&, const TQStringList& )), this, SLOT(slotPropertiesChanged ( const TQString& , const TQMap< TQString, TQT_DBusVariant >&, const TQStringList& )));
+ adapters.insert(TQString(object), properties);
+ //notify others
+ emit adapterAdded(TQString(object));
+ }
+ else if (interface == "org.bluez.GattManager1")
+ {
+ kdDebug() << "Interface not implemented: org.bluez.GattManager1" << endl;
+ // TODO: Implement GattManager1
+ }
+ else if (interface == "org.bluez.Media1")
+ {
+ kdDebug() << "Interface not implemented: org.bluez.Media1" << endl;
+ // TODO: Implement Media1
+ }
+ else if (interface == "org.bluez.NetworkServer1")
+ {
+ kdDebug() << "Interface not implemented: org.bluez.NetworkServer1" << endl;
+ // TODO: Implement NetworkServer1
+ }
+ else if (interface == "org.bluez.Device1")
+ {
+ org::freedesktop::DBus::PropertiesProxy *properties;
+ properties = new org::freedesktop::DBus::PropertiesProxy("org.bluez", object);
+ properties->setConnection(dBusConn);
+ connect(properties, SIGNAL(PropertiesChanged ( const TQString&, const TQMap< TQString, TQT_DBusVariant >&, const TQStringList& )), this, SLOT(slotPropertiesChanged ( const TQString& , const TQMap< TQString, TQT_DBusVariant >&, const TQStringList& )));
+ devices.insert(TQString(object), properties);
+ //notify others
+ emit deviceAdded(TQString(object));
+ }
+ else if (interface == "org.bluez.MediaControl1")
+ {
+ kdDebug() << "Interface not implemented: org.bluez.MediaControl1" << endl;
+ kdDebug() << "as the media control is triggered via properties changed." << endl;
+ }
+ else if (interface == "org.bluez.MediaTransport1")
+ {
+ kdDebug() << "Interface not implemented: org.bluez.MediaTransport1" << endl;
+ // TODO: Implement MediaTransport1
+ }
+ else if (interface == "org.freedesktop.DBus.Introspectable")
+ {
+ // do nothing
+ }
+ else if (interface == "org.freedesktop.DBus.Properties")
+ {
+ // do nothing
+ }
+ else
+ {
+ tqWarning("Interface not implemented: %s", interface.local8Bit().data());
+ }
+ }
+}
+
+void ObjectManagerImpl::slotInterfacesRemoved(const TQT_DBusObjectPath& object, const TQStringList& interfaces)
+{
+ // TODO: remove interface
+ for (TQValueListConstIterator<TQString> it = interfaces.begin();
+ it != interfaces.end(); ++it)
+ {
+ if ((*it) == "org.bluez.AgentManager1")
+ {
+ kdDebug() << "Remove org.bluez.AgentManager1" << endl;
+ // TODO: remove AgentManager1
+ }
+ else if ((*it) == "org.bluez.ProfileManager1")
+ {
+ kdDebug() << "Interface not implemented: org.bluez.ProfileManager1" << endl;
+ // TODO: remove ProfileManager1
+ }
+ else if ((*it) == "org.bluez.HealthManager1")
+ {
+ kdDebug() << "Interface not implemented: org.bluez.HealthManager1" << endl;
+ // TODO: remove HealthManager1
+ }
+ else if ((*it) == "org.bluez.Adapter1")
+ {
+ kdDebug() << "Remove org.bluez.Adapter1" << endl;
+ disconnect(adapters[object], SIGNAL(PropertiesChanged ( const TQString&, const TQMap< TQString, TQT_DBusVariant >&, const TQStringList& )), this, SLOT(slotPropertiesChanged ( const TQString& , const TQMap< TQString, TQT_DBusVariant >&, const TQStringList& )));
+ adapters.remove(object);
+ emit adapterRemoved(TQString(object));
+ }
+ else if ((*it) == "org.bluez.GattManager1")
+ {
+ kdDebug() << "Interface not implemented: org.bluez.GattManager1" << endl;
+ // TODO: Implement GattManager1
+ }
+ else if ((*it) == "org.bluez.Media1")
+ {
+ kdDebug() << "Interface not implemented: org.bluez.Media1" << endl;
+ // TODO: Implement Media1
+ }
+ else if ((*it) == "org.bluez.NetworkServer1")
+ {
+ kdDebug() << "Interface not implemented: org.bluez.NetworkServer1" << endl;
+ // TODO: Implement NetworkServer1
+ }
+ else if ((*it) == "org.bluez.Device1")
+ {
+ kdDebug() << "Remove org.bluez.Device1" << endl;
+ disconnect(devices[object], SIGNAL(PropertiesChanged ( const TQString&, const TQMap< TQString, TQT_DBusVariant >&, const TQStringList& )), this, SLOT(slotPropertiesChanged ( const TQString& , const TQMap< TQString, TQT_DBusVariant >&, const TQStringList& )));
+ devices.remove(object);
+ emit deviceRemoved(TQString(object));
+ }
+ else if ((*it) == "org.bluez.MediaControl1")
+ {
+ kdDebug() << "Interface not implemented: org.bluez.MediaControl1" << endl;
+ kdDebug() << "as the media control is triggered via properties changed." << endl;
+ // emit mediaControlRemoved(TQString ( object.data() ));
+ }
+ else if ((*it) == "org.freedesktop.DBus.Introspectable")
+ {
+ // do nothing
+ }
+ else if ((*it) == "org.freedesktop.DBus.Properties")
+ {
+ // do nothing
+ }
+ else
+ {
+ tqWarning("Interface not implemented: %s", (*it).local8Bit().data());
+ }
+ }
+}
+
+void ObjectManagerImpl::slotPropertiesChanged(const TQString& interface, const TQMap<TQString, TQT_DBusVariant>& changed_properties, const TQStringList& invalidated_properties)
+{
+ // who send the signal ?
+ const TQObject * o = TQObject::sender();
+ org::freedesktop::DBus::PropertiesProxy *obj;
+ obj = const_cast<org::freedesktop::DBus::PropertiesProxy*>(reinterpret_cast<const org::freedesktop::DBus::PropertiesProxy*>(o));
+ TQString path;
+
+ if (interface == "org.bluez.Adapter1")
+ {
+ for (PropertiesMap::Iterator it = adapters.begin();
+ it != adapters.end(); ++it)
+ {
+ if (obj == it.data())
+ path = it.key();
+ }
+ if (!path.isEmpty())
+ adapterPropertiesChanged(path, changed_properties);
+ }
+ else if (interface == "org.bluez.Device1")
+ {
+ for (PropertiesMap::Iterator it = devices.begin(); it != devices.end();
+ ++it)
+ {
+ if (obj == it.data())
+ path = it.key();
+ }
+ if (!path.isEmpty())
+ devicePropertiesChanged(path, changed_properties);
+ }
+ else if (interface == "org.bluez.MediaControl1")
+ {
+ for (PropertiesMap::Iterator it = devices.begin(); it != devices.end();
+ ++it)
+ {
+ if (obj == it.data())
+ path = it.key();
+ }
+ if (!path.isEmpty())
+ mediaControlPropertiesChanged(path, changed_properties);
+ }
+
+// TQStringList::const_iterator it1;
+// for ( it1 = invalidated_properties.begin(); it1 != invalidated_properties.end(); ++it1 )
+// {
+// kdDebug() << "Invalidated Key: " << (*it1) << endl;
+//// if ( it.key() == "Powered" )
+//// emit powerOnChanged(TQT_DBusData::fromVariant ( it.data() ).toBool());
+//// if ( it.key() == "DiscoverableTimeout" )
+//// emit discoverableTimeoutChanged(TQT_DBusData::fromVariant ( it.data() ).toUInt32());
+//// if ( it.key() == "Discoverable" )
+//// emit discoverableTimeoutChanged(TQT_DBusData::fromVariant ( it.data() ).toBool());
+// }
+
+}
+
+}; // namespace TDEBluetooth
+
+#include "objectmanagerImpl.moc"
+// End of File
+