diff options
Diffstat (limited to 'rcm-server-main.c')
-rw-r--r-- | rcm-server-main.c | 390 |
1 files changed, 262 insertions, 128 deletions
diff --git a/rcm-server-main.c b/rcm-server-main.c index 4d23f89..d4b41fe 100644 --- a/rcm-server-main.c +++ b/rcm-server-main.c @@ -61,6 +61,261 @@ property_get(sd_bus *bus, const char *path, const char *interface, return -EINVAL; } +static int +sdbus_get_psk_triplet(sd_bus_message *m, unsigned *ret_protocol, + uint64_t *ret_scancode, struct linux_input_keycode **ret_keycode) +{ + const char *protocol = NULL; + unsigned protocol_numeric; + uint64_t scancode; + bool scancode_found = false; + struct linux_input_keycode *lik = NULL; + const char *keycode = NULL; + unsigned i; + int r; + + r = sd_bus_message_enter_container(m, 'a', "{sv}"); + if (r < 1) + return r; + + while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { + const char *name; + const char *contents; + char type; + + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name); + if (r < 0) + return r; + + r = sd_bus_message_peek_type(m, NULL, &contents); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); + if (r < 0) + return r; + + r = sd_bus_message_peek_type(m, &type, &contents); + if (r < 0) + return r; + + if (!strcmp(name, "protocol")) { + if (type != SD_BUS_TYPE_STRING) { + printf("Invalid type for protocol (%c)\n", type); + return -EINVAL; + } + + if (protocol) { + printf("Protocol specified more than once\n"); + return -EINVAL; + } + + r = sd_bus_message_read_basic(m, type, &protocol); + if (r < 0) + return r; + + for (i = 0; rc_protocols[i]; i++) { + if (!strcmp(rc_protocols[i], protocol)) + break; + } + + if (!rc_protocols[i]) { + printf("Invalid protocol name (%s)\n", protocol); + return -EINVAL; + } + + protocol_numeric = i; + + } else if (!strcmp(name, "scancode")) { + if (type != SD_BUS_TYPE_UINT64) { + printf("Invalid type for scancode (%c)\n", type); + return -EINVAL; + } + + if (scancode_found) { + printf("Scancode specified more than once\n"); + return -EINVAL; + } + + r = sd_bus_message_read_basic(m, type, &scancode); + if (r < 0) + return r; + + scancode_found = true; + + } else if (!strcmp(name, "keycode")) { + if (type != SD_BUS_TYPE_STRING) { + printf("Invalid type for keycode (%c)\n", type); + return -EINVAL; + } + + if (keycode) { + printf("Keycode specified more than once\n"); + return -EINVAL; + } + + r = sd_bus_message_read_basic(m, type, &keycode); + if (r < 0) + return r; + + if (strcmp(keycode, "KEY_RESERVED")) { + lik = get_linux_keycode_by_name(keycode); + if (!lik) { + printf("Invalid keycode name (%s)\n", keycode); + return -EINVAL; + } + } + + } else { + r = sd_bus_message_skip(m, contents); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + } + + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + if (!protocol) { + printf("Protocol missing\n"); + return -EINVAL; + } + + if (!scancode_found) { + printf("Scancode missing\n"); + return -EINVAL; + } + + if (!keycode) { + printf("Keycode missing\n"); + return -EINVAL; + } + + *ret_protocol = protocol_numeric; + *ret_scancode = scancode; + *ret_keycode = lik; + return 1; +} + +static int +method_getkernelmappings(sd_bus_message *m, void *userdata, sd_bus_error *error) +{ + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + struct manager *mgr = userdata; + struct device *dev; + unsigned protocol_numeric; + uint64_t scancode; + struct linux_input_keycode *lik; + unsigned i = 0; + int r; + + dev = find_device_by_path(mgr, sd_bus_message_get_path(m)); + if (!dev) { + sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); + return -EINVAL; + } + + if (dev->evdev_fd < 0) { + sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.EvdevError", "Evdev device not available"); + r = -EINVAL; + goto out; + } + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) + goto out; + + r = sd_bus_message_open_container(reply, 'a', "a{sv}"); + if (r < 0) + goto out; + + while ((r = evdev_get_mapping(dev, i, &protocol_numeric, &scancode, &lik)) > 0) { + r = sd_bus_message_append(reply, "a{sv}", 3, + "protocol", "s", rc_protocols[protocol_numeric], + "scancode", "t", scancode, + "keycode", "s", lik->name); + if (r < 0) + goto out; + + i++; + } + + if (r < 0) + goto out; + + r = sd_bus_message_close_container(reply); + if (r < 0) + goto out; + + r = sd_bus_send(NULL, reply, NULL); + if (r < 0) + goto out; + + return 1; + +out: + return sd_bus_error_set_errno(error, r); +} + +static int +method_setkernelmappings(sd_bus_message *m, void *userdata, sd_bus_error *error) +{ + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + struct manager *mgr = userdata; + struct device *dev; + unsigned protocol; + uint64_t scancode; + struct linux_input_keycode *keycode; + int r; + + dev = find_device_by_path(mgr, sd_bus_message_get_path(m)); + if (!dev) { + sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); + r = -EINVAL; + goto out; + } + + if (dev->evdev_fd < 0) { + sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.EvdevError", "Evdev device not available"); + r = -EINVAL; + goto out; + } + + r = sd_bus_message_enter_container(m, 'a', "a{sv}"); + if (r < 0) + goto out; + + while ((r = sdbus_get_psk_triplet(m, &protocol, &scancode, &keycode)) > 0) { + printf("%s kernel mapping %s:0x%08lx:%s\n", + keycode ? "Setting" : "Unsetting", rc_protocols[protocol], + scancode, keycode ? keycode->name : "<na>"); + evdev_set_mapping(dev, protocol, scancode, keycode); + } + + if (r < 0) + goto out; + + r = sd_bus_message_exit_container(m); + if (r < 0) + goto out; + + return sd_bus_reply_method_return(m, NULL); + +out: + return sd_bus_error_set_errno(error, r); +} static int method_listkeymaps(sd_bus_message *m, void *userdata, sd_bus_error *error) @@ -212,6 +467,9 @@ method_setkeymap_parse_dbus_msg(sd_bus_message *m, struct keymap *keymap, const char *id; const char *name; const char *description; + unsigned protocol; + uint64_t scancode; + struct linux_input_keycode *lik; uint16_t cols, rows; unsigned keycode_count = 0; unsigned layout_count = 0; @@ -268,145 +526,19 @@ method_setkeymap_parse_dbus_msg(sd_bus_message *m, struct keymap *keymap, if (r < 0) return r; - while ((r = sd_bus_message_enter_container(m, 'a', "{sv}")) > 0) { - const char *protocol = NULL; - unsigned protocol_numeric; - uint64_t scancode; - bool scancode_found = false; - struct linux_input_keycode *lik = NULL; - const char *keycode; - unsigned i; - - while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { - const char *name; - const char *contents; - char type; - - r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name); - if (r < 0) - return r; - - r = sd_bus_message_peek_type(m, NULL, &contents); - if (r < 0) - return r; - - r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); - if (r < 0) - return r; - - r = sd_bus_message_peek_type(m, &type, &contents); - if (r < 0) - return r; - - if (!strcmp(name, "protocol")) { - if (type != SD_BUS_TYPE_STRING) { - printf("Invalid type for protocol (%c)\n", type); - return -EINVAL; - } - - if (protocol) { - printf("Protocol specified more than once\n"); - return -EINVAL; - } - - r = sd_bus_message_read_basic(m, type, &protocol); - if (r < 0) - return r; - - for (i = 0; rc_protocols[i]; i++) { - if (!strcmp(rc_protocols[i], protocol)) - break; - } - - if (!rc_protocols[i]) { - printf("Invalid protocol name (%s)\n", protocol); - return -EINVAL; - } - - protocol_numeric = i; - - } else if (!strcmp(name, "scancode")) { - if (type != SD_BUS_TYPE_UINT64) { - printf("Invalid type for scancode (%c)\n", type); - return -EINVAL; - } - - if (scancode_found) { - printf("Scancode specified more than once\n"); - return -EINVAL; - } - - r = sd_bus_message_read_basic(m, type, &scancode); - if (r < 0) - return r; - - scancode_found = true; - - } else if (!strcmp(name, "keycode")) { - if (type != SD_BUS_TYPE_STRING) { - printf("Invalid type for keycode (%c)\n", type); - return -EINVAL; - } - - if (lik) { - printf("Keycode specified more than once\n"); - return -EINVAL; - } - - r = sd_bus_message_read_basic(m, type, &keycode); - if (r < 0) - return r; - - lik = get_linux_keycode_by_name(keycode); - if (!lik) { - printf("Invalid keycode name (%s)\n", keycode); - return -EINVAL; - } - - } else { - r = sd_bus_message_skip(m, contents); - if (r < 0) - return r; - } - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - } - - if (r < 0) - return r; - - if (!protocol) { - printf("Keycode entry without protocol\n"); - return -EINVAL; - } - - if (!scancode_found) { - printf("Keycode entry without scancode\n"); - return -EINVAL; - } - + while ((r = sdbus_get_psk_triplet(m, &protocol, &scancode, &lik)) > 0) { if (!lik) { printf("Keycode entry without keycode\n"); return -EINVAL; } if (keymap) { - keymap->keycodes[keycode_count].protocol = protocol_numeric; + keymap->keycodes[keycode_count].protocol = protocol; keymap->keycodes[keycode_count].scancode = scancode; keymap->keycodes[keycode_count].lik = lik; } keycode_count++; - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; } if (r < 0) @@ -709,6 +841,8 @@ static const sd_bus_vtable device_vtable[] = { SD_BUS_PROPERTY("KernelKeymapName", "s", property_get, 0, 0), SD_BUS_PROPERTY("HardwareType", "s", property_get, 0, 0), SD_BUS_PROPERTY("Error", "s", property_get, 0, 0), + SD_BUS_METHOD("GetKernelMappings", NULL, "aa{sv}", method_getkernelmappings, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetKernelMappings", "aa{sv}", NULL, method_setkernelmappings, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ListKeymaps", NULL, "as", method_listkeymaps, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetKeymap", "s", "ssqqaa{sv}aa{sv}", method_getkeymap, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetKeymap", "sssqqaa{sv}aa{sv}", NULL, method_setkeymap, SD_BUS_VTABLE_UNPRIVILEGED), |