diff options
Diffstat (limited to 'src/libtdebluez/objectmanagerImpl.cpp')
-rw-r--r-- | src/libtdebluez/objectmanagerImpl.cpp | 607 |
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 + |