You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebluez/src/libtdebluez/objectmanagerImpl.cpp

608 lines
22 KiB

/*
*
* Object Manager implementation of bluez5
*
* Copyright (C) 2018 Emanoil Kotsev <deloptes@gmail.com>
*
*
* 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