/************************************************************************** * Copyright (C) 2006-2007 by Danny Kukawka * * , * * * * 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, , * \date 2006-2007 */ // KDE Header #include // DBUS - Header #include "dbusHAL.h" // system headers #include static void* myInstance = 0; /*! The default constructor of the class dbusHAL. */ dbusHAL::dbusHAL(){ kdDebugFuncIn(trace); dbus_is_connected = false; aquiredPolicyPower = 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. */ 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 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() { // 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 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 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 <---- */ /* ----> 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 dbusHAL::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 dbusHAL::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 dbusHAL::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 dbusHAL::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 dbusHAL::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")) 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; TQString 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.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.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, 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 * dbusHAL::get_DBUS_connection() { return dbus_connection; }