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.
tdepowersave/src/dbusInterface.cpp

649 lines
21 KiB

/**************************************************************************
* 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 dbusInterface.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 <tdelocale.h>
// DBUS - Header
#include "dbusInterface.h"
// system headers
#include <iostream>
static void* myInstance = 0;
/*! The default constructor of the class dbusInterface. */
dbusInterface::dbusInterface(){
kdDebugFuncIn(trace);
dbus_is_connected = false;
acquiredPolicyPower = false;
// 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;
}
kdDebugFuncOut(trace);
}
/*! This is the default destructor of class dbusPowersaveConnection. */
dbusInterface::~dbusInterface(){
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 dbusInterface::isConnectedToDBUS() {
return dbus_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 acquired
* \retval false if not
*/
bool dbusInterface::acquiredPolicyPowerInterface() {
return acquiredPolicyPower;
}
/*!
* 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 dbusInterface::reconnect() {
// close D-Bus connection
close();
// init D-Bus conntection and HAL context
return (initDBUS());
}
/*!
* 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 dbusInterface::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 dbusInterface::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;
}
acquirePolicyPowerIface();
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 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 acquire the org.freedesktop.Policy.Power interface
* \return boolean with the result of the operation
* \retval true if successful acquired the interface
* \retval false if unsuccessful
*/
bool dbusInterface::acquirePolicyPowerIface(){
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;
acquiredPolicyPower = true;
break;
case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
kdWarning() << "Queued to acquire org.freedesktop.Policy.Power interface" << endl;
acquiredPolicyPower = false;
break;
default:
kdWarning() << "Unknown error while acquire org.freedesktop.Policy.Power interface" << endl;
acquiredPolicyPower = false;
break;
}
kdDebugFuncOut(trace);
return acquiredPolicyPower;
}
/*!
* This function release the org.freedesktop.Policy.Power interface
* \return boolean with the result of the operation
* \retval true if successful acquired the interface
* \retval false if unsuccessful
*/
bool dbusInterface::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;
acquiredPolicyPower = 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 dbusInterface::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 <---- */
/* ----> D-Bus methode calls functions :: START <---- */
/*!
* This function call a D-Bus method
* \param interface TQString with te dbus interface
* \param path TQString with the object path
* \param object TQString with the object name
* \param method TQString 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 dbusInterface::dbusSystemMethodCall( TQString interface, TQString path, TQString object, TQString 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 TQString with the dbus interface
* \param path TQString with the object path
* \param object TQString with the object name
* \param method TQString 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 dbusInterface::dbusSystemMethodCall( TQString interface, TQString path, TQString object, TQString 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 TQString with the dbus interface
* \param path TQString with the object path
* \param object TQString with the object name
* \param method TQString 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 dbusInterface::dbusMethodCall( TQString interface, TQString path, TQString object, TQString 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.ascii(), path.ascii(), object.ascii(), method.ascii() );
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;
}
/* ----> D-Bus methode calls functions :: END <---- */
/* ---> PolicyKit method call section :: START <--- */
/*!
* Check if the user is privileged to a special privilege
* \param privilege TQString with the name of the requested privilege
* \param udi TQString with the UDI.
* \param ressource TQString with the name of the ressource
* \param user TQString 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 dbusInterface::isUserPrivileged(TQString privilege, TQString udi, TQString ressource, TQString 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();
// 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;
}
out:
kdDebugFuncOut(trace);
return retval;
}
/* ---> PolicyKit method call section :: END <--- */
/*!
* Use this TQT_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 dbusInterface::emitMsgReceived( msg_type type, TQString message, TQString string ) {
if (message.startsWith("dbus.terminate"))
dbus_is_connected = false;
if (type == POLICY_POWER_OWNER_CHANGED) {
if (message.startsWith("NOW_OWNER"))
acquiredPolicyPower = true;
else
acquiredPolicyPower = false;
}
emit msgReceived_withStringString( type, message, string );
}
#include "dbusInterface.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;
TQString ifaceType;
DBusError error;
dbus_error_init( &error );
if (dbus_message_is_signal (message,
DBUS_INTERFACE_LOCAL,
"Disconnected")){
((dbusInterface*) 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.Policy.Power")) {
const char *own_name;
own_name = dbus_bus_get_unique_name(((dbusInterface*) 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!
((dbusInterface*) 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;
((dbusInterface*) myInstance)->emitMsgReceived( POLICY_POWER_OWNER_CHANGED,
"OTHER_OWNER",
NULL );
}
}
}
}
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 )) {
((dbusInterface*) myInstance)->emitMsgReceived( CONSOLEKIT_SESSION_ACTIVE,
session, TQString("%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 * dbusInterface::get_DBUS_connection() {
return dbus_connection;
}