diff options
Diffstat (limited to 'tdecore/tdehw/hwlibdaemons/dbus/tde_dbus_hardwarecontrol.cpp')
-rw-r--r-- | tdecore/tdehw/hwlibdaemons/dbus/tde_dbus_hardwarecontrol.cpp | 982 |
1 files changed, 982 insertions, 0 deletions
diff --git a/tdecore/tdehw/hwlibdaemons/dbus/tde_dbus_hardwarecontrol.cpp b/tdecore/tdehw/hwlibdaemons/dbus/tde_dbus_hardwarecontrol.cpp new file mode 100644 index 000000000..8ba765c34 --- /dev/null +++ b/tdecore/tdehw/hwlibdaemons/dbus/tde_dbus_hardwarecontrol.cpp @@ -0,0 +1,982 @@ +#define DBUS_API_SUBJECT_TO_CHANGE +#include <dbus/dbus.h> +#include <stdbool.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> + +#include <tqdbusconnection.h> +#include <tqdbusdata.h> +#include <tqdbusdatamap.h> +#include <tqdbuserror.h> +#include <tqdbusmessage.h> +#include <tqdbusproxy.h> +#include <tqdbusvariant.h> + +// Input devices +#include <linux/input.h> + +#define BITS_PER_LONG (sizeof(long) * 8) +#define NUM_BITS(x) ((((x) - 1) / BITS_PER_LONG) + 1) + +bool checkPolKitAuthorization(DBusMessage* msg, const TQString &action_id) +{ + if (!msg) { + return false; + } + TQT_DBusConnection dbusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus); + if (!dbusConn.isConnected()) { + return false; + } + TQT_DBusProxy polkitProxy("org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority", + "org.freedesktop.PolicyKit1.Authority", dbusConn); + if (polkitProxy.canSend()) { + // Check whether the requested action is authorized + TQString sender(dbus_message_get_sender(msg)); + TQT_DBusVariant sysname; + sysname.value = TQT_DBusData::fromString(sender); + sysname.signature = sysname.value.buildDBusSignature(); + TQT_DBusDataMap<TQString> subjectMap = TQT_DBusDataMap<TQString>(); + subjectMap.insert(TQString("name"), TQT_DBusData::fromVariant(sysname)); + TQValueList<TQT_DBusData> subjectStruct; + subjectStruct << TQT_DBusData::fromString("system-bus-name"); + subjectStruct << TQT_DBusData::fromStringKeyMap(subjectMap); + + TQMap<TQString, TQString> detailsMap; + detailsMap.insert(TQString(""), TQString("")); + TQT_DBusDataMap<TQString> dbusDetailsMap(detailsMap); + + TQValueList<TQT_DBusData> params; + params << TQT_DBusData::fromStruct(subjectStruct); + params << TQT_DBusData::fromString(action_id); + params << TQT_DBusData::fromStringKeyMap(dbusDetailsMap); + params << TQT_DBusData::fromUInt32(0); // No user interaction + params << TQT_DBusData::fromString(""); // No cancellation + + TQT_DBusMessage reply = polkitProxy.sendWithReply("CheckAuthorization", params); + if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1) { + return (reply[0].toStruct())[0].toBool(); + } + } + + return false; +} + +void reply_Bool(DBusMessage* msg, DBusConnection* conn, int value) { + DBusMessage* reply; + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + dbus_uint32_t serial = 0; + + // create a reply from the message + reply = dbus_message_new_method_return(msg); + + // add the arguments to the reply + dbus_message_iter_init_append(reply, &args); + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &value)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_message_iter_append_basic failed\n", member); + return; + } + + // send the reply && flush the connection + if (!dbus_connection_send(conn, reply, &serial)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_connection_send failed\n", member); + return; + } + dbus_connection_flush(conn); + + // free the reply + dbus_message_unref(reply); +} + +void reply_CanSetGivenPath(DBusMessage* msg, DBusConnection* conn, const char* param) { + DBusMessage* reply; + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + dbus_uint32_t serial = 0; + int writable = false; + + // check if path is writable + int rval = access (param, W_OK); + if (rval == 0) { + writable = true; + } + + // create a reply from the message + reply = dbus_message_new_method_return(msg); + + // add the arguments to the reply + dbus_message_iter_init_append(reply, &args); + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &writable)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_message_iter_append_basic failed\n", member); + return; + } + + // send the reply && flush the connection + if (!dbus_connection_send(conn, reply, &serial)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_connection_send failed\n", member); + return; + } + dbus_connection_flush(conn); + + // free the reply + dbus_message_unref(reply); +} + +void reply_SetGivenPath(DBusMessage* msg, DBusConnection* conn, const char* param, const char* contents) { + DBusMessage* reply; + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + dbus_uint32_t serial = 0; + int writable = false; + int written = false; + + // check if path is writable + int rval = access (param, W_OK); + if (rval == 0) { + writable = true; + } + + if (writable) { + FILE *node = fopen(param, "w"); + if (node != NULL) { + if (fputs(contents, node) != EOF) { + written = true; + } + if (fclose(node) == EOF) { + // Error! + } + } + } + + // create a reply from the message + reply = dbus_message_new_method_return(msg); + + // add the arguments to the reply + dbus_message_iter_init_append(reply, &args); + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &written)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_message_iter_append_basic failed\n", member); + return; + } + + // send the reply && flush the connection + if (!dbus_connection_send(conn, reply, &serial)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_connection_send failed\n", member); + return; + } + dbus_connection_flush(conn); + + // free the reply + dbus_message_unref(reply); +} + +void reply_CanSetCPUGovernor(DBusMessage* msg, DBusConnection* conn) { + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + dbus_int32_t cpunum; + char path[256]; + + // read the arguments + if (!dbus_message_iter_init(msg, &args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: no argument supplied\n", member); + } + else if (DBUS_TYPE_INT32 != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: argument not 32-bit integer\n", member); + } + else { + dbus_message_iter_get_basic(&args, &cpunum); + } + + snprintf(path, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpunum); + reply_CanSetGivenPath(msg, conn, path); +} + +void reply_SetCPUGovernor(DBusMessage* msg, DBusConnection* conn) { + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + dbus_int32_t cpunum = -1; + char* governor = NULL; + char path[256]; + + // read the arguments + if (!dbus_message_iter_init(msg, &args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: no arguments supplied\n", member); + } + else if (DBUS_TYPE_INT32 != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: first argument not 32-bit integer\n", member); + } + else { + dbus_message_iter_get_basic(&args, &cpunum); + } + + if (!dbus_message_iter_next(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: second argument not supplied\n", member); + } + else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: second argument not string\n", member); + } + else { + dbus_message_iter_get_basic(&args, &governor); + } + + snprintf(path, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpunum); + if ((cpunum>-1) && governor) { + reply_SetGivenPath(msg, conn, path, governor); + } + else { + reply_Bool(msg, conn, false); + } +} + +void reply_CanSetBrightness(DBusMessage* msg, DBusConnection* conn) { + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + char* rawpath; + char* safepath; + + // read the arguments + if (!dbus_message_iter_init(msg, &args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: no argument supplied\n", member); + } + else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: argument not string\n", member); + } + else { + dbus_message_iter_get_basic(&args, &rawpath); + } + + safepath = realpath(rawpath, NULL); + + if (safepath && + (strstr(safepath, "/sys/devices") == safepath) && + (strstr(safepath, "/brightness") == (safepath+strlen(safepath)-strlen("/brightness"))) + ) { + reply_CanSetGivenPath(msg, conn, safepath); + } + else { + reply_Bool(msg, conn, false); + } + + free(safepath); +} + +void reply_SetBrightness(DBusMessage* msg, DBusConnection* conn) { + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + char* rawpath; + char* safepath; + char* brightness; + + // read the arguments + if (!dbus_message_iter_init(msg, &args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: no arguments supplied\n", member); + } + else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: first argument not string\n", member); + } + else { + dbus_message_iter_get_basic(&args, &rawpath); + } + + if (!dbus_message_iter_next(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: second argument not supplied\n", member); + } + else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: second argument not string\n", member); + } + else { + dbus_message_iter_get_basic(&args, &brightness); + } + + safepath = realpath(rawpath, NULL); + + if (safepath && brightness && + (strstr(safepath, "/sys/devices") == safepath) && + (strstr(safepath, "/brightness") == (safepath+strlen(safepath)-strlen("/brightness"))) + ) { + reply_SetGivenPath(msg, conn, safepath, brightness); + } + else { + reply_Bool(msg, conn, false); + } + + free(safepath); +} + +bool CanSetPowerState(const char* state, const char* disk, const char* mem) { + // check if required files are writable + bool files_writable = (access("/sys/power/state", W_OK) == 0); + if (disk) + { + files_writable &= (access("/sys/power/disk", W_OK) == 0); + } + if (mem) + { + files_writable &= (access("/sys/power/mem_sleep", W_OK) == 0); + } + if (!files_writable) + { + return false; + } + + // check if method is supported + bool result = false; + // state + FILE *state_node = fopen("/sys/power/state", "r"); + if (state_node) { + char *line = NULL; + size_t len = 0; + ssize_t read = getline(&line, &len, state_node); + if (read > 0 && line) { + result = (strstr(line, state) != NULL); + free(line); + } + fclose(state_node); + } + if (!result) + { + return false; + } + + // disk + if (disk) + { + FILE *disk_node = fopen("/sys/power/disk", "r"); + if (disk_node) { + char *line = NULL; + size_t len = 0; + ssize_t read = getline(&line, &len, disk_node); + if (read > 0 && line) { + result &= (strstr(line, disk) != NULL); + free(line); + } + fclose(disk_node); + } + } + if (!result) + { + return false; + } + + // mem_sleep + if (mem) + { + FILE *mem_node = fopen("/sys/power/mem_sleep", "r"); + if (mem_node) { + char *line = NULL; + size_t len = 0; + ssize_t read = getline(&line, &len, mem_node); + if (read > 0 && line) { + result &= (strstr(line, mem) != NULL); + free(line); + } + fclose(mem_node); + } + } + return result; +} + +bool SetPowerState(const char* state, const char* disk, const char* mem) { + // check if required files are writable + bool files_writable = (access("/sys/power/state", W_OK) == 0); + if (disk) + { + files_writable &= (access("/sys/power/disk", W_OK) == 0); + } + if (mem) + { + files_writable &= (access("/sys/power/mem_sleep", W_OK) == 0); + } + + // set suspend mode + bool result = files_writable; + if (files_writable) + { + // disk + if (disk) + { + FILE *disk_node = fopen("/sys/power/disk", "w"); + if (disk_node) { + result &= (fputs(disk, disk_node) != EOF); + fclose(disk_node); + } + } + + // mem_sleep + if (mem) + { + FILE *mem_node = fopen("/sys/power/mem_sleep", "w"); + if (mem_node) { + result &= (fputs(mem, mem_node) != EOF); + fclose(mem_node); + } + } + + // state + FILE *state_node = fopen("/sys/power/state", "w"); + if (state_node) { + result &= (fputs(state, state_node) != EOF); + fclose(state_node); + } + } + return result; +} + +void reply_CanSetHibernationMethod(DBusMessage* msg, DBusConnection* conn) { + // check if path is writable + reply_CanSetGivenPath(msg, conn, "/sys/power/disk"); +} + +void reply_SetHibernationMethod(DBusMessage* msg, DBusConnection* conn) { + DBusMessageIter args; + const char* member = dbus_message_get_member(msg); + char* method = NULL; + + // read the arguments + if (!dbus_message_iter_init(msg, &args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: no arguments supplied\n", member); + } + else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: argument not string\n", member); + } + else { + dbus_message_iter_get_basic(&args, &method); + } + + // set hibernation method + if (method) { + reply_SetGivenPath(msg, conn, "/sys/power/disk", method); + } + else { + reply_Bool(msg, conn, false); + } +} + +void reply_InputEventsGetSwitches(DBusMessage* msg, DBusConnection* conn, bool active) { + DBusMessage* reply; + DBusMessageIter args, arrayIter; + const char* member = dbus_message_get_member(msg); + dbus_uint32_t serial = 0; + char* rawpath; + char* safepath; + int fd, r; + unsigned long switches[NUM_BITS(EV_CNT)]; + + // read the arguments + if (!dbus_message_iter_init(msg, &args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: no argument supplied\n", member); + } + else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: argument not string\n", member); + } + else { + dbus_message_iter_get_basic(&args, &rawpath); + } + + safepath = realpath(rawpath, NULL); + + if (safepath && + (strstr(safepath, "/dev/input/event") == safepath) + ) { + + fd = open(safepath, O_RDONLY); + if( active ) { + r = ioctl(fd, EVIOCGSW(sizeof(switches)), switches); + } + else { + r = ioctl(fd, EVIOCGBIT(EV_SW, EV_CNT), switches); + } + if( r > 0 ) { + dbus_uint32_t dSwitches[NUM_BITS(EV_CNT)]; + dbus_uint32_t *dSwitchesP = dSwitches; + int i; + + // create a reply from the message + reply = dbus_message_new_method_return(msg); + + // add the arguments to the reply + for( i = 0; i < sizeof(switches)/sizeof(switches[0]); i++ ) { + dSwitches[i] = switches[i]; + } + dbus_message_iter_init_append(reply, &args); + if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "u", &arrayIter)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_message_iter_open_container failed\n", member); + return; + } + if( !dbus_message_iter_append_fixed_array(&arrayIter, DBUS_TYPE_UINT32, + &dSwitchesP, sizeof(switches)/sizeof(switches[0])) ) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_message_iter_append_fixed_array failed\n", member); + return; + } + if (!dbus_message_iter_close_container(&args, &arrayIter)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_message_iter_close_container failed\n", member); + return; + } + } + else { + // create a reply from the message + reply = dbus_message_new_error_printf(msg, + "org.freedesktop.DBus.Error.NotSupported", + "Event device \"%s\" not support EV_SW ioctl", + safepath); + } + close(fd); + } + else { + // create a reply from the message + reply = dbus_message_new_error_printf(msg, + "org.freedesktop.DBus.Error.InvalidArgs", + "Event device \"%s\" is invalid", + rawpath); + } + + // send the reply && flush the connection + if (!dbus_connection_send(conn, reply, &serial)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_connection_send failed\n", member); + return; + } + dbus_connection_flush(conn); + + // free the reply + dbus_message_unref(reply); + + // free safepath + free(safepath); +} + +void signal_NameAcquired(DBusMessage* msg) { + DBusMessageIter args; + char *name = NULL; + if(dbus_message_iter_init(msg, &args)) { + if(DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&args)) { + dbus_message_iter_get_basic(&args, &name); + } + } + fprintf(stderr, "[tde_dbus_hardwarecontrol] Name acquired: %s\n", name); +} + +void reply_Introspect(DBusMessage* msg, DBusConnection* conn) { + DBusMessage* reply; + DBusMessageIter args; + dbus_uint32_t serial = 0; + size_t size = 4096; + const char* member = dbus_message_get_member(msg); + const char *path = dbus_message_get_path(msg); + char *data = new char[size]; + + // compose reply + strncpy(data, + "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" + " \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n", + size); + strncat(data, "<node>\n", size-strlen(data)); + if(strcmp("/", path) == 0) { + strncat(data, " <node name=\"org\" />\n", size-strlen(data)); + } + else if(strcmp("/org", path) == 0) { + strncat(data, " <node name=\"trinitydesktop\" />\n", size-strlen(data)); + } + else if(strcmp("/org/trinitydesktop", path) == 0) { + strncat(data, " <node name=\"hardwarecontrol\" />\n", size-strlen(data)); + } + else if(strcmp("/org/trinitydesktop/hardwarecontrol", path) == 0) { + strncat(data, + " <interface name=\"org.trinitydesktop.hardwarecontrol.Brightness\">\n" + " <method name=\"CanSetBrightness\">\n" + " <arg name=\"device\" direction=\"in\" type=\"s\" />\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"SetBrightness\">\n" + " <arg name=\"device\" direction=\"in\" type=\"s\" />\n" + " <arg name=\"brightness\" direction=\"in\" type=\"s\" />\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " </interface>\n", + size-strlen(data)); + strncat(data, + " <interface name=\"org.trinitydesktop.hardwarecontrol.CPUGovernor\">\n" + " <method name=\"CanSetCPUGovernor\">\n" + " <arg name=\"cpu\" direction=\"in\" type=\"i\" />\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"SetCPUGovernor\">\n" + " <arg name=\"cpu\" direction=\"in\" type=\"i\" />\n" + " <arg name=\"governor\" direction=\"in\" type=\"s\" />\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " </interface>\n", + size-strlen(data)); + strncat(data, + " <interface name=\"org.trinitydesktop.hardwarecontrol.InputEvents\">\n" + " <method name=\"GetProvidedSwitches\">\n" + " <arg name=\"device\" direction=\"in\" type=\"s\" />\n" + " <arg name=\"value\" direction=\"out\" type=\"au\" />\n" + " </method>\n" + " <method name=\"GetActiveSwitches\">\n" + " <arg name=\"device\" direction=\"in\" type=\"s\" />\n" + " <arg name=\"value\" direction=\"out\" type=\"au\" />\n" + " </method>\n" + " </interface>\n", + size-strlen(data)); + strncat(data, + " <interface name=\"org.trinitydesktop.hardwarecontrol.Power\">\n" + " <method name=\"CanStandby\">\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"Standby\">\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"CanFreeze\">\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"Freeze\">\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"CanSuspend\">\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"Suspend\">\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"CanHibernate\">\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"Hibernate\">\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"CanHybridSuspend\">\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"HybridSuspend\">\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"CanSetHibernationMethod\">\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"SetHibernationMethod\">\n" + " <arg name=\"method\" direction=\"in\" type=\"s\" />\n" + " <arg name=\"value\" direction=\"out\" type=\"b\" />\n" + " </method>\n" + " </interface>\n", + size-strlen(data)); + } + strncat(data, "</node>\n", size-strlen(data)); + + // create a reply from the message + reply = dbus_message_new_method_return(msg); + + // add the arguments to the reply + dbus_message_iter_init_append(reply, &args); + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &data)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_message_iter_append_basic failed\n", member); + return; + } + + // send the reply && flush the connection + if (!dbus_connection_send(conn, reply, &serial)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_connection_send failed\n", member); + return; + } + dbus_connection_flush(conn); + + // free the reply + dbus_message_unref(reply); + delete[] data; +} + +void reply_PropertiesGetAll(DBusMessage* msg, DBusConnection* conn) { + DBusMessage* reply; + DBusMessageIter args, arrayIter; + const char* member = dbus_message_get_member(msg); + dbus_uint32_t serial = 0; + + // create a reply from the message + reply = dbus_message_new_method_return(msg); + + // add the arguments to the reply + dbus_message_iter_init_append(reply, &args); + if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "sv", &arrayIter)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_message_iter_open_container failed\n", member); + return; + } + if (!dbus_message_iter_close_container(&args, &arrayIter)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_message_iter_close_container failed\n", member); + return; + } + + // send the reply && flush the connection + if (!dbus_connection_send(conn, reply, &serial)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_connection_send failed\n", member); + return; + } + dbus_connection_flush(conn); + + // free the reply + dbus_message_unref(reply); +} + +void error_UnknownMessage(DBusMessage* msg, DBusConnection* conn) { + const char* member = dbus_message_get_member(msg); + const char* interface = dbus_message_get_interface(msg); + // print message + fprintf(stderr, "[tde_dbus_hardwarecontrol] Unknown method '%s' called on interface '%s', ignoring\n", member, interface); + if (DBUS_MESSAGE_TYPE_METHOD_CALL != dbus_message_get_type(msg)) { + return; + } + + // create a reply from the message + DBusMessage* reply = dbus_message_new_error_printf(msg, + "org.freedesktop.DBus.Error.UnknownMethod", + "Method \"%s\" on interface \"%s\" doesn't exist", + member, interface); + + // send the reply && flush the connection + dbus_uint32_t serial = 0; + if (!dbus_connection_send(conn, reply, &serial)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] %s: dbus_connection_send failed\n", member); + return; + } + dbus_connection_flush(conn); + + // free the reply + dbus_message_unref(reply); +} + +void error_PolkitAccessDenied(DBusMessage* msg, DBusConnection* conn) { + // create a reply from the message + DBusMessage* reply = dbus_message_new_error(msg, + "org.freedesktop.DBus.Error.AccessDenied", "Permission denied."); + + // send the reply && flush the connection + dbus_uint32_t serial = 0; + if (!dbus_connection_send(conn, reply, &serial)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] error_PolkitAccessDenied: dbus_connection_send failed\n"); + return; + } + dbus_connection_flush(conn); + + // free the reply + dbus_message_unref(reply); +} + +void listen() { + DBusMessage* msg; + DBusConnection* conn; + DBusError err; + int ret; + + fprintf(stderr, "[tde_dbus_hardwarecontrol] Listening...\n"); + + // initialise the error structure + dbus_error_init(&err); + + // connect to the bus and check for errors + conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] Connection failed with error '%s'\n", err.message); + dbus_error_free(&err); + } + if (NULL == conn) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] No connection, exiting!\n"); + exit(1); + } + + // request our name on the bus and check for errors + ret = dbus_bus_request_name(conn, "org.trinitydesktop.hardwarecontrol", DBUS_NAME_FLAG_REPLACE_EXISTING , &err); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] Name request failed with error '%s'\n", err.message); + dbus_error_free(&err); + } + if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { + fprintf(stderr, "[tde_dbus_hardwarecontrol] Not primary owner (%d), exiting!\n", ret); + exit(1); + } + + // loop, testing for new messages + // block for up to 1 second, exit in case the connection was lost + while (dbus_connection_read_write(conn, 1000)) { + // non blocking read of the next available message + msg = dbus_connection_pop_message(conn); + + // loop again if we haven't got a message + if (NULL == msg) { + continue; + } + + // check this is a method call for the right interface & method + if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.CPUGovernor", "CanSetCPUGovernor")) { + reply_CanSetCPUGovernor(msg, conn); + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.CPUGovernor", "SetCPUGovernor")) { + reply_SetCPUGovernor(msg, conn); + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Brightness", "CanSetBrightness")) { + reply_CanSetBrightness(msg, conn); + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Brightness", "SetBrightness")) { + reply_SetBrightness(msg, conn); + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Power", "CanFreeze")) { + bool result = checkPolKitAuthorization(msg, "org.trinitydesktop.hardwarecontrol.power.freeze"); + if (!result) { + error_PolkitAccessDenied(msg, conn); + } + else { + result = CanSetPowerState("freeze", NULL, NULL) || CanSetPowerState("mem", NULL, "s2idle"); + reply_Bool(msg, conn, result); + } + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Power", "Freeze")) { + bool result = checkPolKitAuthorization(msg, "org.trinitydesktop.hardwarecontrol.power.freeze"); + if (!result) { + error_PolkitAccessDenied(msg, conn); + } + else { + result = false; + if (CanSetPowerState("freeze", NULL, NULL)) { + result = SetPowerState("freeze", NULL, NULL); + } + else if (CanSetPowerState("mem", NULL, "s2idle")) { + result = SetPowerState("mem", NULL, "s2idle"); + } + reply_Bool(msg, conn, result); + } + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Power", "CanStandby")) { + bool result = checkPolKitAuthorization(msg, "org.trinitydesktop.hardwarecontrol.power.standby"); + if (!result) { + error_PolkitAccessDenied(msg, conn); + } + else { + result = CanSetPowerState("standby", NULL, NULL) || CanSetPowerState("mem", NULL, "shallow"); + reply_Bool(msg, conn, result); + } + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Power", "Standby")) { + bool result = checkPolKitAuthorization(msg, "org.trinitydesktop.hardwarecontrol.power.standby"); + if (!result) { + error_PolkitAccessDenied(msg, conn); + } + else { + result = false; + if (CanSetPowerState("standby", NULL, NULL)) { + result = SetPowerState("standby", NULL, NULL); + } + else if (CanSetPowerState("mem", NULL, "shallow")) { + result = SetPowerState("mem", NULL, "shallow"); + } + reply_Bool(msg, conn, result); + } + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Power", "CanSuspend")) { + bool result = checkPolKitAuthorization(msg, "org.trinitydesktop.hardwarecontrol.power.suspend"); + if (!result) { + error_PolkitAccessDenied(msg, conn); + } + else { + result = (CanSetPowerState("mem", NULL, NULL) && access("/sys/power/mem_sleep", R_OK) != 0) || + CanSetPowerState("mem", NULL, "deep"); + reply_Bool(msg, conn, result); + } + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Power", "Suspend")) { + bool result = checkPolKitAuthorization(msg, "org.trinitydesktop.hardwarecontrol.power.suspend"); + if (!result) { + error_PolkitAccessDenied(msg, conn); + } + else { + result = false; + if (CanSetPowerState("mem", NULL, NULL) && access("/sys/power/mem_sleep", R_OK) != 0) { + result = SetPowerState("mem", NULL, NULL); + } + else if (CanSetPowerState("mem", NULL, "deep")) { + result = SetPowerState("mem", NULL, "deep"); + } + reply_Bool(msg, conn, result); + } + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Power", "CanHybridSuspend")) { + bool result = checkPolKitAuthorization(msg, "org.trinitydesktop.hardwarecontrol.power.hybridsuspend"); + if (!result) { + error_PolkitAccessDenied(msg, conn); + } + else { + result = CanSetPowerState("disk", "suspend", NULL); + reply_Bool(msg, conn, result); + } + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Power", "HybridSuspend")) { + bool result = checkPolKitAuthorization(msg, "org.trinitydesktop.hardwarecontrol.power.hybridsuspend"); + if (!result) { + error_PolkitAccessDenied(msg, conn); + } + else { + result = SetPowerState("disk", "suspend", NULL); + reply_Bool(msg, conn, result); + } + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Power", "CanHibernate")) { + bool result = checkPolKitAuthorization(msg, "org.trinitydesktop.hardwarecontrol.power.hibernate"); + if (!result) { + error_PolkitAccessDenied(msg, conn); + } + else { + result = CanSetPowerState("disk", "shutdown", NULL) || CanSetPowerState("disk", "platform", NULL); + reply_Bool(msg, conn, result); + } + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Power", "Hibernate")) { + bool result = checkPolKitAuthorization(msg, "org.trinitydesktop.hardwarecontrol.power.hibernate"); + if (!result) { + error_PolkitAccessDenied(msg, conn); + } + else { + result = false; + if (CanSetPowerState("disk", "shutdown", NULL)) { + result = SetPowerState("disk", "shutdown", NULL); + } + else if (CanSetPowerState("disk", "platform", NULL)) { + result = SetPowerState("disk", "platform", NULL); + } + reply_Bool(msg, conn, result); + } + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Power", "CanSetHibernationMethod")) { + reply_CanSetHibernationMethod(msg, conn); + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.Power", "SetHibernationMethod")) { + reply_SetHibernationMethod(msg, conn); + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.InputEvents", "GetProvidedSwitches")) { + reply_InputEventsGetSwitches(msg, conn, false); + } + else if (dbus_message_is_method_call(msg, "org.trinitydesktop.hardwarecontrol.InputEvents", "GetActiveSwitches")) { + reply_InputEventsGetSwitches(msg, conn, true); + } + else if (dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameAcquired")) { + signal_NameAcquired(msg); + } + else if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Introspectable", "Introspect")) { + reply_Introspect(msg, conn); + } + else if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Properties", "GetAll")) { + reply_PropertiesGetAll(msg, conn); + } + else { + error_UnknownMessage(msg, conn); + } + + // free the message + dbus_message_unref(msg); + } + + // close the connection + dbus_connection_unref(conn); +} + +int main(int argc, char** argv) { + listen(); + return 0; +} |