summaryrefslogtreecommitdiffstats
path: root/src/dbusHAL.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dbusHAL.cpp')
-rw-r--r--src/dbusHAL.cpp1314
1 files changed, 1314 insertions, 0 deletions
diff --git a/src/dbusHAL.cpp b/src/dbusHAL.cpp
new file mode 100644
index 0000000..3c9a293
--- /dev/null
+++ b/src/dbusHAL.cpp
@@ -0,0 +1,1314 @@
+ /**************************************************************************
+ * Copyright (C) 2006-2007 by Danny Kukawka *
+ * <dkukawka@suse.de>, <danny.kukawka@web.de> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License *
+ * as published by the Free Software Foundation. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+/*!
+ * \file dbusHAL.cpp
+ * \brief In this file can be found the functionality to connect to
+ * the HAL daemon via D-Bus, to handle D-Bus calls/events and to
+ * provide wrapper to HAL lib and functions
+ * \author Danny Kukawka, <dkukawka@suse.de>, <danny.kukawka@web.de>
+ * \date 2006-2007
+ */
+
+ // KDE Header
+#include <klocale.h>
+
+// DBUS - Header
+#include "dbusHAL.h"
+
+// system headers
+#include <iostream>
+
+static void* myInstance = 0;
+
+/*! The default constructor of the class dbusHAL. */
+dbusHAL::dbusHAL(){
+ kdDebugFuncIn(trace);
+
+ dbus_is_connected = false;
+ hal_is_connected = false;
+ aquiredPolicyPower = false;
+ hal_ctx = NULL;
+
+ // add pointer to this for filter_function()
+ myInstance=this;
+ // init connection to dbus
+ if(!initDBUS()) {
+ kdError() << "Can't connect to D-Bus" << endl;
+ m_dBusQtConnection = NULL;
+ }
+ if(!initHAL())
+ kdError() << "Can't connect to HAL" << endl;
+
+ kdDebugFuncOut(trace);
+}
+
+/*! This is the default destructor of class dbusPowersaveConnection. */
+dbusHAL::~dbusHAL(){
+ kdDebugFuncIn(trace);
+
+ close();
+ myInstance = NULL;
+
+ kdDebugFuncOut(trace);
+}
+
+/*!
+ * 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 dbusHAL::isConnectedToDBUS() {
+ return dbus_is_connected;
+}
+
+/*!
+ * This function return information about connection status to the HAL daemon.
+ * \return boolean with the state of the connection to HAL
+ * \retval true if connected
+ * \retval false if disconnected
+ */
+bool dbusHAL::isConnectedToHAL() {
+ return hal_is_connected;
+}
+
+/*!
+ * This function return information if the org.freedesktop.Policy.Power
+ * interface was claimed.
+ * \return boolean with the status of claim the interface
+ * \retval true if aquired
+ * \retval false if not
+ */
+bool dbusHAL::aquiredPolicyPowerInterface() {
+ return aquiredPolicyPower;
+}
+
+/*!
+ * This function try a reconnect to D-Bus and HAL daemon.
+ * \return boolean with the result of the operation
+ * \retval true if successful reconnected to D-Bus and HAL
+ * \retval false if unsuccessful
+ */
+bool dbusHAL::reconnect() {
+ // free HAL context
+ freeHAL();
+ // close D-Bus connection
+ close();
+ // init D-Bus conntection and HAL context
+ return (initDBUS() && initHAL());
+}
+
+/*!
+ * This function close the connection to powersave 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 dbusHAL::close() {
+ if ( m_dBusQtConnection != NULL ) {
+ releasePolicyPowerIface();
+ m_dBusQtConnection->close();
+ m_dBusQtConnection = NULL;
+ }
+ dbus_is_connected = false;
+
+ return true;
+}
+
+/* ----> D-Bus section :: START <---- */
+
+/*!
+ * This function initialise the connection to the D-Bus daemon.
+ * \return boolean with the result of the operation
+ * \retval true if successful initialised D-Bus connection
+ * \retval false if unsuccessful
+ */
+bool dbusHAL::initDBUS(){
+ kdDebugFuncIn(trace);
+
+ dbus_is_connected = false;
+
+ DBusError error;
+ dbus_error_init(&error);
+
+ dbus_connection = dbus_bus_get( DBUS_BUS_SYSTEM, &error );
+
+ if (dbus_connection == NULL){
+ kdError() << "Failed to open connection to system message bus: " << error.message << endl;
+ dbus_error_free (&error);
+ return false;
+ }
+
+ if ( dbus_error_is_set( &error ) ) {
+ kdError() << "Failed to register connection with system message bus: " << error.message << endl;
+ return false;
+ }
+
+ aquirePolicyPowerIface();
+
+ dbus_connection_set_exit_on_disconnect( dbus_connection, false );
+
+ /* add the filter function which should be executed on events on the bus */
+ if ( ! dbus_connection_add_filter( dbus_connection, filterFunction, this, NULL) ) {
+ kdFatal() << "Error: Not enough memory to add filter to dbus connection" << endl;
+ exit(EXIT_FAILURE);
+ }
+
+ /* add a match rule to catch all signals going through the bus with D-Bus interface */
+ dbus_bus_add_match( dbus_connection, "type='signal',"
+ "interface='org.freedesktop.DBus',"
+ "member='NameOwnerChanged'", NULL);
+
+ /* add a match rule to catch all signals going through the bus with HAL interface */
+ dbus_bus_add_match( dbus_connection, "type='signal',"
+ "interface='org.freedesktop.Hal.Manager',"
+ "member='DeviceAdded'", NULL);
+ dbus_bus_add_match( dbus_connection, "type='signal',"
+ "interface='org.freedesktop.Hal.Manager',"
+ "member='DeviceRemoved'", NULL);
+ dbus_bus_add_match( dbus_connection, "type='signal',"
+ "interface='org.freedesktop.Hal.Device',"
+ "member='PropertyModified'", NULL);
+ dbus_bus_add_match( dbus_connection, "type='signal',"
+ "interface='org.freedesktop.Hal.Device',"
+ "member='Condition'", NULL);
+
+ /* add a match rule to catch all signals going through the bus with ConsoleKit Interface */
+ dbus_bus_add_match( dbus_connection, "type='signal',"
+ "interface='org.freedesktop.ConsoleKit.Session',"
+ "member='ActiveChanged'", NULL);
+
+ m_dBusQtConnection = new DBusQt::Connection(this);
+ m_dBusQtConnection->dbus_connection_setup_with_qt_main(dbus_connection);
+
+ dbus_is_connected = true;
+
+ kdDebugFuncOut(trace);
+ return true;
+}
+
+/*!
+ * This function aquire the org.freedesktop.Policy.Power interface
+ * \return boolean with the result of the operation
+ * \retval true if successful aquired the interface
+ * \retval false if unsuccessful
+ */
+bool dbusHAL::aquirePolicyPowerIface(){
+ kdDebugFuncIn(trace);
+
+ if (dbus_connection == NULL) {
+ kdDebugFuncOut(trace);
+ return false;
+ }
+
+ switch (dbus_bus_request_name(dbus_connection, "org.freedesktop.Policy.Power",
+ DBUS_NAME_FLAG_REPLACE_EXISTING, NULL)) {
+ case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
+ kdDebug() << "Acquired org.freedesktop.Policy.Power interface" << endl;
+ aquiredPolicyPower = true;
+ break;
+ case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
+ kdWarning() << "Queued to aquire org.freedesktop.Policy.Power interface" << endl;
+ aquiredPolicyPower = false;
+ break;
+ default:
+ kdWarning() << "Unknown error while aquire org.freedesktop.Policy.Power interface" << endl;
+ aquiredPolicyPower = false;
+ break;
+ }
+
+ kdDebugFuncOut(trace);
+ return aquiredPolicyPower;
+}
+
+/*!
+ * This function release the org.freedesktop.Policy.Power interface
+ * \return boolean with the result of the operation
+ * \retval true if successful aquired the interface
+ * \retval false if unsuccessful
+ */
+bool dbusHAL::releasePolicyPowerIface(){
+ kdDebugFuncIn(trace);
+
+ int result;
+ bool retval = false;
+ DBusError error;
+
+ if (dbus_connection == NULL) {
+ kdDebugFuncOut(trace);
+ return false;
+ }
+
+ dbus_error_init(&error);
+
+ result = dbus_bus_release_name(dbus_connection, "org.freedesktop.Policy.Power", &error);
+
+ if ( dbus_error_is_set( &error ) ) {
+ kdError() << "Failed to release org.freedesktop.Policy.Power: " << error.message << endl;
+ dbus_error_free(&error);
+ } else {
+ switch (result) {
+ case DBUS_RELEASE_NAME_REPLY_RELEASED:
+ kdDebug() << "Released org.freedesktop.Policy.Power interface" << endl;
+ retval = true;
+ aquiredPolicyPower = false;
+ break;
+ case DBUS_RELEASE_NAME_REPLY_NOT_OWNER:
+ kdWarning() << "Couldn't release org.freedesktop.Policy.Power, not the owner" << endl;
+ break;
+ case DBUS_RELEASE_NAME_REPLY_NON_EXISTENT:
+ kdWarning() << "Couldn't release org.freedesktop.Policy.Power, Iface not existing" << endl;
+ break;
+ default:
+ kdWarning() << "Couldn't release org.freedesktop.Policy.Power, unknown error" << endl;
+ break;
+ }
+ }
+
+ return retval;
+ kdDebugFuncOut(trace);
+}
+
+/*!
+ * This function check if the org.freedesktop.Policy.Power
+ * interface is owned by someone
+ * \return boolean with the result of the operation
+ * \retval true if the interface is owned by someone
+ * \retval false if else
+ */
+bool dbusHAL::isPolicyPowerIfaceOwned(){
+ kdDebugFuncIn(trace);
+
+ bool retval = false;
+ DBusError error;
+
+ if (dbus_connection == NULL) {
+ kdDebugFuncOut(trace);
+ return false;
+ }
+
+ dbus_error_init(&error);
+
+ retval = dbus_bus_name_has_owner(dbus_connection, "org.freedesktop.Policy.Power", &error);
+
+ if ( dbus_error_is_set( &error ) ) {
+ kdError() << "Failed to check if org.freedesktop.Policy.Power has an owner: " << error.message << endl;
+ dbus_error_free(&error);
+ }
+
+ kdDebugFuncOut(trace);
+ return retval;
+}
+
+/* ----> DBUS section :: END <---- */
+/* ----> HAL section :: START <---- */
+
+/*!
+ * This function initialise the connection to HAL over the D-Bus daemon.
+ * \return boolean with the result of the operation
+ * \retval true if successful initialised HAL connection and context
+ * \retval false if unsuccessful
+ */
+bool dbusHAL::initHAL(){
+ kdDebugFuncIn(trace);
+
+ if ( !dbus_is_connected ) {
+ freeHAL();
+ return false;
+ } else if ( hal_is_connected && (hal_ctx != NULL)) {
+ return true;
+ }
+
+ // could not connect to HAL, reset all and try again
+ freeHAL();
+
+ DBusError error;
+ dbus_error_init(&error);
+
+ dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+ if (dbus_connection == NULL || dbus_error_is_set(&error)) {
+ kdError() << "could not open connection to system bus: " << error.message << endl;
+ dbus_error_free(&error);
+ return false;
+ }
+
+ bool hal_is_ready = dbus_bus_name_has_owner(dbus_connection, "org.freedesktop.Hal", &error);
+
+ if (!hal_is_ready) {
+ kdWarning() << "HAL is not ready. We will try later... " << endl;
+
+ if ( dbus_error_is_set( &error ) ) {
+ kdError() << "Error checking if hal service exists: " << error.message << endl;
+ dbus_error_free( &error );
+ }
+
+ freeHAL();
+ return false;
+ }
+
+ if((hal_ctx = libhal_ctx_new()) == NULL) {
+ kdError() << "Could not init HAL context" << endl;
+ return false;
+ }
+
+ /* setup dbus connection for hal */
+ if (!libhal_ctx_set_dbus_connection(hal_ctx, dbus_connection)) {
+ kdError() << "Could not set up connection to dbus for hal" << endl;
+ freeHAL();
+ return false;
+ }
+
+ /* init the hal library */
+ if (!libhal_ctx_init(hal_ctx, &error)) {
+ kdError() << "Could not init hal library: " << error.message << endl;
+ freeHAL();
+ return false;
+ }
+
+ hal_is_connected = true;
+
+ kdDebugFuncOut(trace);
+ return hal_is_connected;
+}
+
+/*!
+ * This function free the hal connection/context.
+ */
+void dbusHAL::freeHAL(){
+
+ if ( hal_ctx != NULL ) {
+ libhal_ctx_free( hal_ctx );
+ hal_ctx = NULL;
+ }
+ hal_is_connected = false;
+}
+
+/*!
+ * This function try a reconnect to the HAL daemon only.
+ * \return boolean with the result of the operation
+ * \retval true if successful reconnected to HAL
+ * \retval false if unsuccessful
+ */
+bool dbusHAL::reconnectHAL() {
+ // free HAL context
+ freeHAL();
+ // init HAL context
+ return (initHAL());
+}
+
+/*!
+ * This function query a integer property from HAL for a given device
+ * \param udi QString with the UDI of the device
+ * \param property QString with the property
+ * \param returnval pointer to the return value
+ * \return If the query was successful or not
+ */
+bool dbusHAL::halGetPropertyInt(QString udi, QString property, int *returnval){
+ kdDebugFuncIn(trace);
+
+ bool ret = false;
+
+ if (!initHAL() || udi.isEmpty() || property.isEmpty())
+ goto out;
+
+ DBusError error;
+ dbus_error_init(&error);
+
+ if (!libhal_device_property_exists(hal_ctx, udi, property, &error)) {
+ kdWarning() << "Property: " << property << " for: " << udi << " doesn't exist." << endl;
+ goto out;
+ }
+
+ *returnval = libhal_device_get_property_int(hal_ctx, udi, property, &error);
+
+ if (dbus_error_is_set(&error)) {
+ kdError() << "Fetching property: " << property << " for: " << udi
+ << " failed with: " << error.message << endl;
+ dbus_error_free(&error);
+ goto out;
+ } else {
+ ret = true;
+ }
+
+out:
+ kdDebugFuncOut(trace);
+ return true;
+}
+
+/*!
+ * This function query a boolean property from HAL for a given device
+ * \param udi QString with the UDI of the device
+ * \param property QString with the property
+ * \param returnval pointer to the return value
+ * \return If the query was successful or not
+ */
+bool dbusHAL::halGetPropertyBool(QString udi, QString property, bool *returnval){
+ kdDebugFuncIn(trace);
+
+ bool ret = false;
+
+ if (!initHAL() || udi.isEmpty() || property.isEmpty())
+ goto out;
+
+ DBusError error;
+ dbus_error_init(&error);
+
+ if (!libhal_device_property_exists(hal_ctx, udi, property, &error)) {
+ kdWarning() << "Property: " << property << " for: " << udi << " doesn't exist." << endl;
+ goto out;
+ }
+
+ *returnval = libhal_device_get_property_bool(hal_ctx, udi, property, &error);
+
+ if (dbus_error_is_set(&error)) {
+ kdError() << "Fetching property: " << property << " for: " << udi
+ << " failed with: " << error.message << endl;
+ dbus_error_free(&error);
+ goto out;
+ } else {
+ ret = true;
+ }
+
+out:
+ kdDebugFuncOut(trace);
+ return ret;
+}
+
+
+/*!
+ * This function query a Sting property from HAL for a given device
+ * \param udi QString with the UDI of the device
+ * \param property QString with the property
+ * \param returnval pointer to the return value
+ * \return If the query was successful or not
+ */
+bool dbusHAL::halGetPropertyString(QString udi, QString property, QString *returnval){
+ kdDebugFuncIn(trace);
+
+ bool ret = false;
+
+ if (!initHAL() || udi.isEmpty() || property.isEmpty())
+ goto out;
+
+ DBusError error;
+ dbus_error_init(&error);
+
+ if (!libhal_device_property_exists(hal_ctx, udi, property, &error)) {
+ kdWarning() << "Property: " << property << " for: " << udi << " doesn't exist." << endl;
+ goto out;
+ }
+
+ *returnval = libhal_device_get_property_string(hal_ctx, udi, property, &error);
+
+ if (dbus_error_is_set(&error)) {
+ kdError() << "Fetching property: " << property << " for: " << udi
+ << " failed with: " << error.message << endl;
+ dbus_error_free(&error);
+ goto out;
+ } else {
+ ret = true;
+ }
+
+out:
+ kdDebugFuncOut(trace);
+ return ret;
+}
+
+/*!
+ * This function query a String List property from HAL for a given device
+ * \param udi QString with the udi of the device
+ * \param property QString with the property to query
+ * \param devices QStringList to return the values
+ * \return If the query was successful or not
+ */
+bool dbusHAL::halGetPropertyStringList (QString udi, QString property, QStringList *devices) {
+ kdDebugFuncIn(trace);
+
+ bool ret = false;
+
+ if (!initHAL() || udi.isEmpty() || property.isEmpty())
+ goto out;
+
+ DBusError error;
+ char ** found;
+
+ dbus_error_init(&error);
+
+ if (!libhal_device_property_exists(hal_ctx, udi, property, &error)) {
+ kdWarning() << "Property: " << property << " for: " << udi << " doesn't exist." << endl;
+ goto out;
+ }
+
+ found = libhal_device_get_property_strlist (hal_ctx, udi, property, &error);
+
+ if (dbus_error_is_set(&error)) {
+ kdWarning() << "Error while query existing strlist Property: " << property
+ << " for: " << udi << " error: " << error.message << endl;
+ dbus_error_free(&error);
+ libhal_free_string_array(found);
+ goto out;
+ } else {
+ for (int i = 0; found[i] != NULL ; ++i) {
+ QString _to_add = found[i];
+ if (!_to_add.isEmpty()) *devices += _to_add;
+ }
+ libhal_free_string_array(found);
+ ret = true;
+ }
+
+out:
+ kdDebugFuncOut(trace);
+ return ret;
+}
+
+
+/*!
+ * This function query a capability from HAL for a given device
+ * \param udi QString with the UDI of the device
+ * \param capability QString with the capability to query
+ * \param returnval pointer to the return value as boolean
+ * \return If the query was successful or not
+ */
+bool dbusHAL::halQueryCapability(QString udi, QString capability, bool *returnval) {
+ kdDebugFuncIn(trace);
+
+ bool ret = false;
+
+ if (!initHAL() || udi.isEmpty() || capability.isEmpty())
+ goto out;
+
+ DBusError error;
+ dbus_error_init(&error);
+
+ *returnval = libhal_device_query_capability(hal_ctx, udi, capability, &error);
+
+ if (dbus_error_is_set(&error)) {
+ kdError() << "Fetching capability: " << capability << " for: " << udi
+ << " failed with: " << error.message << endl;
+ dbus_error_free(&error);
+ goto out;
+ } else {
+ ret = true;
+ }
+
+out:
+ kdDebugFuncOut(trace);
+ return ret;
+}
+
+/*!
+ * Use this function to check if a device has a specia property/key.
+ * \param udi QString with the UDI of the device
+ * \param property QString with the property
+ * \return If the query was successful or not
+ */
+bool dbusHAL::halDevicePropertyExist(QString udi, QString property ) {
+ kdDebugFuncIn(trace);
+
+ bool ret = false;
+
+ if (!initHAL() || udi.isEmpty() || property.isEmpty())
+ goto out;
+
+ DBusError error;
+ dbus_error_init(&error);
+
+ if (! libhal_device_property_exists (hal_ctx, udi, property, &error)) {
+ if (dbus_error_is_set(&error)) {
+ kdError() << "Fetching existing property: " << property << " for: " << udi
+ << " failed with: " << error.message << endl;
+ dbus_error_free(&error);
+ }
+ goto out;
+ } else {
+ ret = true;
+ }
+
+out:
+ kdDebugFuncOut(trace);
+ return ret;
+}
+
+/*!
+ * Use this function to search find devices with a give capability
+ * \param capability QString with the capability to query
+ * \param devices QStringList to return the found devices
+ * \return If the query was successful or not
+ */
+bool dbusHAL::halFindDeviceByCapability (QString capability, QStringList *devices) {
+ kdDebugFuncIn(trace);
+
+ DBusError error;
+ char ** found;
+ int num = 0;
+ bool ret = false;
+
+ if (!initHAL() || capability.isEmpty())
+ goto out;
+
+ dbus_error_init(&error);
+
+ found = libhal_find_device_by_capability (hal_ctx, capability, &num, &error);
+
+ if (dbus_error_is_set(&error)) {
+ kdError() << "Could not get list of devices with capability: " << capability
+ << " error: " << error.message << endl;
+ dbus_error_free(&error);
+ libhal_free_string_array(found);
+ goto out;
+ } else {
+ for (int i = 0; i < num; ++i) {
+ QString _to_add = found[i];
+ if (!_to_add.isEmpty()) *devices += _to_add;
+ }
+ libhal_free_string_array(found);
+ ret = true;
+ }
+
+out:
+ kdDebugFuncOut(trace);
+ return ret;
+}
+
+/*!
+ * Use this function to search find devices with a special string property
+ * \param property QString with the name of the property
+ * \param keyval QString with value of the string property
+ * \param devices QStringList to return the found devices
+ * \return If the query was successful or not
+ */
+bool dbusHAL::halFindDeviceByString (QString property, QString keyval, QStringList *devices) {
+ kdDebugFuncIn(trace);
+
+ DBusError error;
+ char ** found;
+ int num = 0;
+ bool ret = false;
+
+ if (!initHAL() || property.isEmpty() || keyval.isEmpty())
+ goto out;
+
+ dbus_error_init(&error);
+
+ found = libhal_manager_find_device_string_match (hal_ctx, property, keyval, &num, &error);
+
+ if (dbus_error_is_set(&error)) {
+ kdError() << "Could not get list of devices with key: " << property
+ << "and string value: " << keyval << " error: " << error.message << endl;
+ dbus_error_free(&error);
+ libhal_free_string_array(found);
+ goto out;
+ } else {
+ for (int i = 0; i < num; ++i) {
+ QString _to_add = found[i];
+ if (!_to_add.isEmpty()) *devices += _to_add;
+ }
+ libhal_free_string_array(found);
+ ret = true;
+ }
+
+out:
+ kdDebugFuncOut(trace);
+ return ret;
+}
+
+/* ----> HAL section :: END <---- */
+/* ----> D-Bus methode calls functions :: START <---- */
+/*!
+ * This function call a D-Bus method
+ * \param interface QString with te dbus interface
+ * \param path QString with the object path
+ * \param object QString with the object name
+ * \param method QString with the name of the methode
+ * \param first_arg_type integer with the dbus type of the first argument
+ * \param ... more arguments
+ * \return If the query was successful or not
+ */
+bool dbusHAL::dbusSystemMethodCall( QString interface, QString path, QString object, QString method,
+ int first_arg_type, ... ) {
+ kdDebugFuncIn(trace);
+
+ bool _ret = false;
+ va_list var_args;
+
+ va_start(var_args, first_arg_type);
+ _ret = dbusMethodCall( interface, path, object, method, DBUS_BUS_SYSTEM,
+ NULL, -1, first_arg_type, var_args);
+ va_end(var_args);
+
+ kdDebugFuncOut(trace);
+ return _ret;
+}
+
+
+/*!
+ * This overloaded function call a D-Bus method on the D-Bus system bus with a return value
+ * \param interface QString with the dbus interface
+ * \param path QString with the object path
+ * \param object QString with the object name
+ * \param method QString with the name of the method
+ * \param retvalue void pointer to arguments, if NULL we make a simple call
+ * \param retval_type Integer with the dbus type of the return value, set to -1 if retvalue is NULL
+ * \param first_arg_type Integer with the dbus type of the first argument followed by the value
+ * \return If the query was successful or not
+ */
+bool dbusHAL::dbusSystemMethodCall( QString interface, QString path, QString object, QString method,
+ void *retvalue, int retval_type, int first_arg_type, ... ) {
+ kdDebugFuncIn(trace);
+
+ bool _ret = false;
+ va_list var_args;
+
+ va_start(var_args, first_arg_type);
+ _ret = dbusMethodCall( interface, path, object, method, DBUS_BUS_SYSTEM,
+ retvalue, retval_type, first_arg_type, var_args);
+ va_end(var_args);
+
+ kdDebugFuncOut(trace);
+ return _ret;
+}
+
+
+/*!
+ * This function call a D-Bus method with a return value
+ * \param interface QString with the dbus interface
+ * \param path QString with the object path
+ * \param object QString with the object name
+ * \param method QString with the name of the method
+ * \param dbus_type DBusBusType with the D-Bus BUS Type
+ * \param retvalue void pointer to arguments, if NULL we make a simple call
+ * \param retval_type Integer with the dbus type of the return value, set to -1 if retvalue is NULL
+ * \param first_arg_type Integer with the dbus type of the first argument followed by the value
+ * \param var_args va_list with more arguments
+ * \return If the query was successful or not
+ */
+bool dbusHAL::dbusMethodCall( QString interface, QString path, QString object, QString method,
+ DBusBusType dbus_type, void *retvalue, int retval_type, int first_arg_type,
+ va_list var_args ) {
+ kdDebugFuncIn(trace);
+
+ DBusMessage *message;
+ DBusMessage *reply;
+ DBusError error;
+ bool ret = false;
+
+ dbus_error_init(&error);
+
+ dbus_connection = dbus_bus_get(dbus_type, &error);
+
+ if (dbus_error_is_set(&error)) {
+ kdError() << "Could not get dbus connection: " << error.message << endl;
+ dbus_error_free(&error);
+ goto out;
+ }
+
+ message = dbus_message_new_method_call( interface, path, object, method );
+ dbus_message_append_args_valist(message, first_arg_type, var_args);
+
+ if (retvalue == NULL) {
+ if (!dbus_connection_send(dbus_connection, message, NULL)) {
+ kdError() << "Could not send method call." << endl;
+ dbus_message_unref( message );
+ goto out;
+ }
+ } else {
+ reply = dbus_connection_send_with_reply_and_block(dbus_connection, message, -1, &error);
+
+ if (dbus_error_is_set(&error)) {
+ kdError() << "Could not send dbus message: " << error.message << endl;
+ dbus_message_unref(message);
+ dbus_error_free(&error);
+ goto out;
+ }
+
+ int type = dbus_message_get_type(reply);
+ if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
+ if (!dbus_message_get_args(reply, &error, retval_type, retvalue, DBUS_TYPE_INVALID)){
+ if (dbus_error_is_set(&error)) {
+ kdError() << "Could not get argument from reply: "
+ << error.message << endl;
+ dbus_error_free(&error);
+ }
+ dbus_message_unref(reply);
+ dbus_message_unref(message);
+ goto out;
+ }
+ } else {
+ kdError() << "Revieved invalid DBUS_MESSAGE_TYPE: " << type
+ << "expected: " << DBUS_MESSAGE_TYPE_METHOD_RETURN << endl;
+ dbus_message_unref(reply);
+ dbus_message_unref(message);
+ goto out;
+ }
+ }
+
+ ret = true; // if we are here, everything should be okay
+ dbus_message_unref(message);
+ dbus_connection_flush(dbus_connection);
+
+out:
+ kdDebugFuncOut(trace);
+ return ret;
+}
+
+/*!
+ * Function to call a suspend and call if resumed \ref callBackSuspend()
+ * to emit a resume signal.
+ * \param suspend a char pointer with the name of the suspend interface
+ * \return If the query was successful or not
+ */
+bool dbusHAL::dbusMethodCallSuspend ( const char *suspend ) {
+ kdDebugFuncIn(trace);
+
+ DBusMessage *message;
+ DBusError error;
+ DBusPendingCall* pcall = NULL;
+ bool ret = false;
+
+ dbus_error_init(&error);
+ dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+
+ if (dbus_error_is_set(&error)) {
+ kdError() << "Could not get dbus connection: " << error.message << endl;
+ dbus_error_free(&error);
+ goto out;
+ }
+
+ message = dbus_message_new_method_call( HAL_SERVICE, HAL_COMPUTER_UDI, HAL_PM_IFACE, suspend);
+ if (strcmp( suspend, "Suspend") == 0) {
+ int wake_up = 0;
+ dbus_message_append_args (message, DBUS_TYPE_INT32, &wake_up, DBUS_TYPE_INVALID);
+ }
+
+ if (message) {
+ // need to set INT_MAX as default and not -1
+ dbus_connection_send_with_reply (dbus_connection, message, &pcall, INT_MAX);
+ if (pcall) {
+ dbus_pending_call_ref (pcall); // really needed?
+ dbus_pending_call_set_notify (pcall, dbusHAL::callBackSuspend, NULL, NULL);
+ }
+ dbus_message_unref (message);
+ ret = true;
+ }
+
+out:
+ kdDebugFuncOut(trace);
+ return ret;
+}
+
+/*!
+ * Slot called by D-Bus as set in \ref dbusMethodCallSuspend()
+ * Here we emit the resume signal.
+ */
+void dbusHAL::callBackSuspend (DBusPendingCall* pcall, void* /*data*/) {
+ kdDebugFuncIn(trace);
+
+ DBusMessage* reply = NULL;
+ DBusError error;
+ int result;
+ bool failed = false;
+
+ if (!pcall) {
+ kdError() << "dbusHAL::callBackSuspend - DBusPendingCall not set, return" << endl;
+ kdDebugFuncOut(trace);
+ return;
+ }
+
+ reply = dbus_pending_call_steal_reply (pcall);
+ if (reply == NULL) {
+ kdError() << "dbusHAL::callBackSuspend - Got no reply, return" << endl;
+ goto out;
+ }
+
+ dbus_error_init(&error);
+
+ if (!dbus_message_get_args (reply, &error, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID)) {
+ if (dbus_error_is_set(&error)) {
+ kdError() << "Could not get argument from reply: " << error.message << endl;
+ dbus_error_free(&error);
+ }
+
+ kdWarning() << "dbusHAL::callBackSuspend dbus_message_get_args failed, maybe timouted" << endl;
+ failed = true;
+ }
+
+ dbus_message_unref (reply);
+
+out:
+ dbus_pending_call_unref (pcall);
+
+ if (failed)
+ emit ((dbusHAL*) myInstance)->backFromSuspend( -1 );
+ else
+ emit ((dbusHAL*) myInstance)->backFromSuspend( result );
+
+ kdDebugFuncOut(trace);
+ return;
+}
+
+
+/* ----> D-Bus methode calls functions :: END <---- */
+/* ---> PolicyKit method call section :: START <--- */
+
+/*!
+ * Check if the user is privileged to a special privilege
+ * \param privilege QString with the name of the requested privilege
+ * \param udi QString with the UDI.
+ * \param ressource QString with the name of the ressource
+ * \param user QString with the name of the user. If empty the current user is used.
+ * \return int with info if the user is allowed or not.
+ * \retval 0 if not allowed
+ * \retval 1 if allowed
+ * \retval -1 if a error occurs or we could not query the interface
+ */
+int dbusHAL::isUserPrivileged(QString privilege, QString udi, QString ressource, QString user) {
+ kdDebugFuncIn(trace);
+
+ const char *_unique_name;
+ const char *_user;
+ const char *_privilege;
+
+ int retval = -1;
+
+ if (user.isEmpty() || user.isNull())
+ _user = getenv("USER");
+ else
+ _user = user.latin1();
+
+ if (_user == NULL || privilege.isEmpty())
+ goto out;
+
+ _unique_name = dbus_bus_get_unique_name(dbus_connection);
+ _privilege = privilege.latin1();
+
+#ifdef USE_LIBHAL_POLICYCHECK
+ DBusError error;
+ char *result;
+
+ if (udi.isEmpty()) {
+ kdError() << "No UDI given ... could not lookup privileges" << endl;
+ goto out;
+ }
+ if (!hal_is_connected) {
+ kdError() << "HAL not running, could not call libhal for lookup privileges" << endl;
+ goto out;
+ }
+
+ dbus_error_init(&error);
+ result = libhal_device_is_caller_privileged ( hal_ctx, udi.latin1(), _privilege, _unique_name, &error);
+
+ if ( dbus_error_is_set( &error ) ) {
+ kdWarning() << "Error while lookup privileges: " << error.message << endl;
+ dbus_error_free( &error );
+ retval = -1;
+ } else {
+ if (!strcmp(result, "yes")) {
+ retval = 1;
+ } else if (!strcmp(result, "no")) {
+ retval = 0;
+ } else {
+ retval = -1;
+ }
+ }
+
+ libhal_free_string(result);
+#else
+ // not sure if we need this, but to avoid problems
+ dbus_bool_t _retval;
+ const char *_ressource;
+ _ressource = ressource.latin1();
+
+ if (!dbusSystemMethodCall( "org.freedesktop.PolicyKit",
+ "/org/freedesktop/PolicyKit/Manager",
+ "org.freedesktop.PolicyKit.Manager",
+ "IsUserPrivileged",
+ &_retval, DBUS_TYPE_BOOLEAN,
+ DBUS_TYPE_STRING, &_unique_name,
+ DBUS_TYPE_STRING, &_user,
+ DBUS_TYPE_STRING, &_privilege,
+ DBUS_TYPE_STRING, &_ressource,
+ DBUS_TYPE_INVALID)) {
+ retval = -1; // only to be sure we have no changes trough the call
+ } else {
+ retval = (int) _retval;
+ }
+#endif
+
+out:
+ kdDebugFuncOut(trace);
+ return retval;
+}
+/* ---> PolicyKit method call section :: END <--- */
+
+/*!
+ * Use this SLOT to emit a reviced messages to the kpowersave.
+ * NOTE: Because of the filter function this need to be a public function.
+ * Don't use this function in any other place than this class.
+ * \param type enum with the type of the message
+ * \param message String with the message
+ * \param string String with additional info
+ */
+void dbusHAL::emitMsgReceived( msg_type type, QString message, QString string ) {
+
+ if (message.startsWith("dbus.terminate"))
+ dbus_is_connected = false;
+
+ if (type == POLICY_POWER_OWNER_CHANGED) {
+ if (message.startsWith("NOW_OWNER"))
+ aquiredPolicyPower = true;
+ else
+ aquiredPolicyPower = false;
+ }
+
+ emit msgReceived_withStringString( type, message, string );
+}
+
+#include "dbusHAL.moc"
+// --> functions which are not member of the class ...
+
+/*!
+ * This function is needed filter function for the D-Bus connection to filter
+ * all needed messages from the bus which are needful for KPowersave.
+ * \param connection existing connection to the D-Bus daemon
+ * \param message the recieved message from the D-Bus daemon
+ * \param data void pointer (see dbus bindings for more information)
+ * \return DBusHandlerResult
+ */
+DBusHandlerResult
+filterFunction (DBusConnection *connection, DBusMessage *message, void */*data*/) {
+ kdDebugFuncIn(trace);
+
+ bool reply_wanted;
+ char *value;
+ QString ifaceType;
+
+ DBusError error;
+ dbus_error_init( &error );
+
+ if (dbus_message_is_signal (message,
+ DBUS_INTERFACE_LOCAL,
+ "Disconnected")){
+ ((dbusHAL*) myInstance)->emitMsgReceived( DBUS_EVENT, "dbus.terminate", 0 );
+ dbus_connection_unref(connection);
+ kdDebugFuncOut(trace);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if ( dbus_message_get_type( message ) != DBUS_MESSAGE_TYPE_SIGNAL ) {
+ if (trace) kdDebug() << "recieved message, but wasn't from type DBUS_MESSAGE_TYPE_SIGNAL" << endl;
+ kdDebugFuncOut(trace);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ ifaceType = dbus_message_get_interface( message );
+ if (ifaceType == NULL) {
+ kdDebug() << "Received message from invalid interface" << endl;
+ kdDebugFuncOut(trace);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ reply_wanted = !dbus_message_get_no_reply( message );
+
+ if (ifaceType.startsWith(DBUS_INTERFACE_DBUS)) {
+ if(trace) kdDebug() << "Received from DBUS_INTERFACE_DBUS" << endl;
+ /* get the name of the signal */
+ const char *signal = dbus_message_get_member( message );
+
+ /* get the first argument. This must be a string at the moment */
+ dbus_message_get_args( message, &error, DBUS_TYPE_STRING, &value, DBUS_TYPE_INVALID );
+
+ if ( dbus_error_is_set( &error ) ) {
+ kdWarning() << "Received signal " << error.message << " but no string argument" << endl;
+ dbus_error_free( &error );
+ kdDebugFuncOut(trace);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (trace) kdDebug() << "filter_function::SIGNAL=" << signal << " VALUE=" << value << endl;
+
+ /* our name is... */
+ if ( ! strcmp( signal, "NameAcquired" ) ) {
+ kdDebugFuncOut(trace);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ else if ( ! strcmp( signal, "NameOwnerChanged" )) {
+ char *service;
+ char *old_owner;
+ char *new_owner;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &service,
+ DBUS_TYPE_STRING, &old_owner,
+ DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID)) {
+ if (!strcmp(service, "org.freedesktop.Hal")) {
+ if (!strcmp(new_owner, "") && strcmp(old_owner, "")) {
+ // Hal service stopped.
+ kdDebug() << "=== org.freedesktop.Hal terminated ===" << endl;
+ ((dbusHAL*) myInstance)->emitMsgReceived( DBUS_EVENT,
+ "hal.terminate",
+ NULL );
+ }
+ else if (!strcmp(old_owner, "") && strcmp(new_owner, "")) {
+ // Hal service started.
+ kdDebug() << "=== org.freedesktop.Hal started ===" << endl;
+ ((dbusHAL*) myInstance)->emitMsgReceived( DBUS_EVENT,
+ "hal.started",
+ NULL );
+ }
+ } else if (!strcmp(service, "org.freedesktop.Policy.Power")) {
+ const char *own_name;
+
+ own_name = dbus_bus_get_unique_name(((dbusHAL*) myInstance)->get_DBUS_connection());
+
+ if (!strcmp(new_owner, own_name)) {
+ kdDebug() << "=== now owner of org.freedesktop.Policy.Power ===" << endl;
+ // we have now again the ower of the name!
+ ((dbusHAL*) myInstance)->emitMsgReceived( POLICY_POWER_OWNER_CHANGED,
+ "NOW_OWNER",
+ NULL );
+ } else {
+ // some other has now the interface
+ kdDebug() << "=== someone owner of org.freedesktop.Policy.Power ===" << endl;
+ ((dbusHAL*) myInstance)->emitMsgReceived( POLICY_POWER_OWNER_CHANGED,
+ "OTHER_OWNER",
+ NULL );
+ }
+ }
+ }
+ }
+ kdDebugFuncOut(trace);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (ifaceType.startsWith("org.freedesktop.Hal.Manager")) {
+ kdDebug() << "Received from org.freedesktop.Hal.Manager" << endl;
+ char *udi;
+
+ const char *signal = dbus_message_get_member( message );
+ /* get the first argument. This must be a string at the moment */
+ dbus_message_get_args( message, &error, DBUS_TYPE_STRING, &value, DBUS_TYPE_INVALID );
+
+ if ( dbus_error_is_set( &error ) ) {
+ kdWarning() << "Received signal, but no string argument: " << error.message << endl;
+ dbus_error_free( &error );
+ kdDebugFuncOut(trace);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (dbus_message_get_args( message, &error, DBUS_TYPE_STRING, &udi, DBUS_TYPE_INVALID )) {
+ if (! strcmp(signal, "DeviceRemoved") || ! strcmp(signal, "DeviceAdded")) {
+ ((dbusHAL*) myInstance)->emitMsgReceived( HAL_DEVICE, signal, udi );
+ kdDebug() << "org.freedesktop.Hal.Manager: uid: " << udi
+ << " signal: " << signal << endl;
+ } else {
+ kdWarning() << "Received unknown signal from org.freedesktop.Hal.Manager: "
+ << signal << endl;
+ }
+ }
+ kdDebugFuncOut(trace);
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+ } else if (ifaceType.startsWith("org.freedesktop.Hal.Device")) {
+ const char *udi = dbus_message_get_path (message);
+ const char *signal = dbus_message_get_member( message );
+
+ /* Code taken from libhal */
+ if (! strcmp(signal, "PropertyModified")) {
+ if (trace) kdDebug() << "-------- PropertyModified ------" << endl;
+ int i, num_modifications;
+ DBusMessageIter iter;
+ DBusMessageIter iter_array;
+
+ dbus_message_iter_init (message, &iter);
+ dbus_message_iter_get_basic (&iter, &num_modifications);
+ dbus_message_iter_next (&iter);
+
+ dbus_message_iter_recurse (&iter, &iter_array);
+
+ for (i = 0; i < num_modifications; i++) {
+ dbus_bool_t removed, added;
+ char *key;
+ DBusMessageIter iter_struct;
+
+ dbus_message_iter_recurse (&iter_array, &iter_struct);
+
+ dbus_message_iter_get_basic (&iter_struct, &key);
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &removed);
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &added);
+
+ /* don't check if we really need this device, check this in an other class */
+ ((dbusHAL*) myInstance)->emitMsgReceived( HAL_PROPERTY_CHANGED, udi, key);
+ kdDebug() << "PropertyModified: uid: " << udi << " key: " << key << endl;
+
+ dbus_message_iter_next (&iter_array);
+ }
+ } else if (! strcmp(signal, "Condition")) {
+ if (trace) kdDebug() << "-------- Condition ------" << endl;
+ char *name, *detail;
+
+ dbus_message_get_args( message, &error, DBUS_TYPE_STRING, &value, DBUS_TYPE_INVALID );
+
+ if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &detail, DBUS_TYPE_INVALID)) {
+ ((dbusHAL*) myInstance)->emitMsgReceived( HAL_CONDITION, name, detail );
+ } else {
+ if (dbus_error_is_set( &error )) dbus_error_free( &error );
+ }
+ } else {
+ kdDebug() << "Received unknown signal from org.freedesktop.Hal.Device: "
+ << signal << endl;
+ }
+ kdDebugFuncOut(trace);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (ifaceType.startsWith("org.freedesktop.ConsoleKit.Session")) {
+ kdDebug() << "Received from org.freedesktop.ConsoleKit.Session" << endl;
+
+ const char *session = dbus_message_get_path (message);
+ const char *signal = dbus_message_get_member( message );
+
+ if (! strcmp(signal, "ActiveChanged")) {
+ dbus_bool_t active;
+
+ if (dbus_message_get_args( message, &error, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID )) {
+ ((dbusHAL*) myInstance)->emitMsgReceived( CONSOLEKIT_SESSION_ACTIVE,
+ session, QString("%1").arg((int)active));
+ } else {
+ if (dbus_error_is_set( &error )) dbus_error_free( &error );
+ }
+ } else {
+ kdDebug() << "Received unknown signal from org.freedesktop.ConsoleKit.Session: "
+ << signal << endl;
+ kdDebugFuncOut(trace);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ kdDebugFuncOut(trace);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else {
+ kdDebugFuncOut(trace);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+}
+
+// --> some functions to get private members
+
+//! to get the current connection to D-Bus
+DBusConnection * dbusHAL::get_DBUS_connection() {
+ return dbus_connection;
+}