/* * * Object Manager implementation of bluez5 * * Copyright (C) 2018 Emanoil Kotsev * * * 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 #include #include #include #include #include #include #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 * \retval TQValueList */ ObjectManagerImpl::AdapterList ObjectManagerImpl::getAdapters() { return adapters.keys(); } /*! * This function returns a list of objectpaths * \return TQValueList * \retval TQValueList */ 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 objects; TQT_DBusError error; if (!GetManagedObjects(objects, error)) { tqDebug("GetManagedObjects(objects,error) FAILED:\n%s\n", error.message().latin1()); return false; } TQT_DBusDataMap::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::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& changed_properties) { // https://github.com/r10r/bluez/blob/master/doc/device-api.txt TQMap::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& changed_properties) { TQMap::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& interfaces) { TQT_DBusDataMap::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 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& changed_properties, const TQStringList& invalidated_properties) { // who send the signal ? const TQObject * o = TQObject::sender(); org::freedesktop::DBus::PropertiesProxy *obj; obj = const_cast(reinterpret_cast(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