diff options
-rw-r--r-- | rcm-server-keymap.c | 3 | ||||
-rw-r--r-- | rcm-server-main.c | 322 | ||||
-rw-r--r-- | utils.h | 9 |
3 files changed, 264 insertions, 70 deletions
diff --git a/rcm-server-keymap.c b/rcm-server-keymap.c index b33e262..438b3f3 100644 --- a/rcm-server-keymap.c +++ b/rcm-server-keymap.c @@ -431,6 +431,9 @@ keymaps_load(struct device *device) void keymap_free(struct keymap *keymap) { + if (!keymap) + return; + free(keymap->layout); free(keymap->name); free(keymap->description); diff --git a/rcm-server-main.c b/rcm-server-main.c index 266658f..0623a01 100644 --- a/rcm-server-main.c +++ b/rcm-server-main.c @@ -9,6 +9,7 @@ #include <errno.h> #include "utils.h" +#include "shared.h" #include "rcm-server-main.h" #include "rcm-server-keymap.h" @@ -193,48 +194,74 @@ out: } static int -method_setkeymap(sd_bus_message *m, void *userdata, sd_bus_error *error) +method_setkeymap_parse_dbus_msg(sd_bus_message *m, struct keymap *keymap, + const char **ret_id, unsigned *ret_keycode_count, + uint16_t *ret_cols, uint16_t *ret_rows) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - struct manager *mgr = userdata; - struct device *dev; - struct keymap *keymap; const char *id; const char *name; const char *description; uint16_t cols, rows; + unsigned keycode_count = 0; + unsigned layout_count = 0; + unsigned i; int r; - dev = find_device_by_path(mgr, sd_bus_message_get_path(m)); - if (!dev) - return sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); + r = sd_bus_message_rewind(m, 1); + if (r < 0) + return r; r = sd_bus_message_read(m, "sssqq", &id, &name, &description, &cols, &rows); if (r < 0) { fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r)); - goto out; + return r; } - keymap = find_keymap_by_id(dev, id); - if (!keymap) - return sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidKeymap", "Sorry, unknown keymap"); + if (!id) { + printf("Id missing\n"); + return -EINVAL; + } - printf("Asked to update keymap\n"); - printf("\tID : %s\n", id); - printf("\tName: %s\n", name); - printf("\tDesc: %s\n", description); - printf("\tCols: %u\n", cols); - printf("\tRows: %u\n", rows); + if (!name) { + printf("Name missing\n"); + return -EINVAL; + } + + if (!description) { + printf("Description missing\n"); + return -EINVAL; + } + + if (cols < 1 || cols > REMOTE_LAYOUT_MAX_WIDTH) { + printf("Invalid column size\n"); + return -EINVAL; + } + + if (rows < 1 || rows > REMOTE_LAYOUT_MAX_HEIGHT) { + printf("Invalid row size\n"); + return -EINVAL; + } + + if (keymap) { + keymap->id = strdup(id); + keymap->name = strdup(name); + keymap->description = strdup(description); + keymap->cols = cols; + keymap->rows = rows; + + if (!keymap->id || !keymap->name || !keymap->description) + return -ENOMEM; + } - printf("\tKeymap:\n"); r = sd_bus_message_enter_container(m, 'a', "a{sv}"); if (r < 0) - goto out; + return r; while ((r = sd_bus_message_enter_container(m, 'a', "{sv}")) > 0) { - const char *protocol; + const char *protocol = NULL; uint64_t scancode; - const char *keycode; + bool scancode_found = false; + const char *keycode = NULL; while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { const char *name; @@ -243,89 +270,127 @@ method_setkeymap(sd_bus_message *m, void *userdata, sd_bus_error *error) r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name); if (r < 0) - goto out; + return r; r = sd_bus_message_peek_type(m, NULL, &contents); if (r < 0) - goto out; + return r; r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); if (r < 0) - goto out; + return r; r = sd_bus_message_peek_type(m, &type, &contents); if (r < 0) - goto out; + return r; if (!strcmp(name, "protocol")) { if (type != SD_BUS_TYPE_STRING) { printf("Invalid type for protocol (%c)\n", type); - r = -EINVAL; - goto out; + 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) - goto out; + return r; } else if (!strcmp(name, "scancode")) { if (type != SD_BUS_TYPE_UINT64) { printf("Invalid type for scancode (%c)\n", type); - r = -EINVAL; - goto out; + 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) - goto out; + return r; + + scancode_found = true; } else if (!strcmp(name, "keycode")) { if (type != SD_BUS_TYPE_STRING) { printf("Invalid type for keycode (%c)\n", type); - r = -EINVAL; - goto out; + 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) - goto out; + return r; } else { - r = sd_bus_message_skip(reply, contents); + r = sd_bus_message_skip(m, contents); if (r < 0) - goto out; + return r; } r = sd_bus_message_exit_container(m); if (r < 0) - goto out; + return r; r = sd_bus_message_exit_container(m); if (r < 0) - goto out; + return r; } if (r < 0) - goto out; + return r; + + if (!protocol) { + printf("Keycode entry without protocol\n"); + return -EINVAL; + } + + if (!scancode_found) { + printf("Keycode entry without scancode\n"); + return -EINVAL; + } + + if (!keycode) { + printf("Keycode entry without keycode\n"); + return -EINVAL; + } + + if (keymap) { + keymap->keycodes[keycode_count].protocol = strdup(protocol); + keymap->keycodes[keycode_count].scancode = scancode; + keymap->keycodes[keycode_count].keycode = strdup(keycode); + + if (!keymap->keycodes[keycode_count].protocol || + !keymap->keycodes[keycode_count].keycode) + return -ENOMEM; + } - printf("\t\t%s:%" PRIx64 ":%s\n", protocol, scancode, keycode); + keycode_count++; r = sd_bus_message_exit_container(m); if (r < 0) - goto out; + return r; } if (r < 0) - goto out; + return r; r = sd_bus_message_exit_container(m); if (r < 0) - goto out; + return r; - printf("\tLayout:\n"); r = sd_bus_message_enter_container(m, 'a', "a{sv}"); if (r < 0) - goto out; + return r; while ((r = sd_bus_message_enter_container(m, 'a', "{sv}")) > 0) { bool blank = false; @@ -340,30 +405,34 @@ method_setkeymap(sd_bus_message *m, void *userdata, sd_bus_error *error) r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name); if (r < 0) - goto out; + return r; r = sd_bus_message_peek_type(m, NULL, &contents); if (r < 0) - goto out; + return r; r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); if (r < 0) - goto out; + return r; r = sd_bus_message_peek_type(m, &type, &contents); if (r < 0) - goto out; + return r; if (!strcmp(name, "type")) { if (type != SD_BUS_TYPE_STRING) { printf("Invalid type for type (%c)\n", type); - r = -EINVAL; - goto out; + return -EINVAL; } r = sd_bus_message_read_basic(m, type, &button_type); if (r < 0) - goto out; + return r; + + if (button || blank) { + printf("Multiple types specified in layout\n"); + return -EINVAL; + } if (!strcasecmp(button_type, "button")) button = true; @@ -371,60 +440,173 @@ method_setkeymap(sd_bus_message *m, void *userdata, sd_bus_error *error) blank = true; else { printf("Invalid button type: %s\n", button_type); - r = -EINVAL; - goto out; + return -EINVAL; } } else if (!strcmp(name, "keycode")) { if (type != SD_BUS_TYPE_STRING) { printf("Invalid type for keycode (%c)\n", type); - r = -EINVAL; - goto out; + return -EINVAL; + } + + if (keycode) { + printf("Multiple keycodes specified in layout\n"); + return -EINVAL; } r = sd_bus_message_read_basic(m, type, &keycode); if (r < 0) - goto out; + return r; } else { - r = sd_bus_message_skip(reply, contents); + r = sd_bus_message_skip(m, contents); if (r < 0) - goto out; + return r; } r = sd_bus_message_exit_container(m); if (r < 0) - goto out; + return r; r = sd_bus_message_exit_container(m); if (r < 0) - goto out; + return r; } if (r < 0) - goto out; + return r; - if ((!blank && !button) || (blank && button) || (button && !keycode)) { + if ((!blank && !button) || (blank && button) || + (button && !keycode) || (blank && keycode)) { printf("Invalid layout specification\n"); - r = -EINVAL; - goto out; + return -EINVAL; } - printf("\t\tButton: %s\n", button ? keycode : "blank"); + if (keymap) { + if (blank) + keymap->layout[layout_count] = NULL; + else { + for (i = 0; i < keycode_count; i++) { + if (!strcasecmp(keycode, keymap->keycodes[i].keycode)) + break; + } + + if (i >= keycode_count) { + printf("Invalid keycode in layout: '%s'\n", keycode); + return -EINVAL; + } + + keymap->layout[layout_count] = &keymap->keycodes[i]; + } + } + + layout_count++; r = sd_bus_message_exit_container(m); if (r < 0) - goto out; + return r; } if (r < 0) - goto out; + return r; r = sd_bus_message_exit_container(m); if (r < 0) + return r; + + if (!sd_bus_message_at_end(m, 1)) { + printf("Trailing message parts\n"); + return -EINVAL; + } + + if (keycode_count < 1) { + printf("No keycodes specified\n"); + return -EINVAL; + } + + if (layout_count < 1) { + printf("No layout specified\n"); + return -EINVAL; + } + + if (rows * cols != layout_count) { + fprintf(stderr, "Layout (%u) does not match rows x cols (%ux%u)\n", + layout_count, rows, cols); + return -EINVAL; + } + + if (ret_id) + *ret_id = id; + + if (ret_keycode_count) + *ret_keycode_count = keycode_count; + + if (keymap) + keymap->keycode_count = keycode_count; + + if (ret_cols) + *ret_cols = cols; + + if (ret_rows) + *ret_rows = rows; + + return 0; +} + +static int +method_setkeymap(sd_bus_message *m, void *userdata, sd_bus_error *error) +{ + struct manager *mgr = userdata; + struct device *dev; + struct keymap *old_keymap; + struct keymap *new_keymap; + const char *id; + unsigned keycode_count; + uint16_t cols, rows; + int r; + + dev = find_device_by_path(mgr, sd_bus_message_get_path(m)); + if (!dev) + return sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); + + r = method_setkeymap_parse_dbus_msg(m, NULL, &id, &keycode_count, &cols, &rows); + if (r < 0) + goto out; + + old_keymap = find_keymap_by_id(dev, id); + if (!old_keymap) + return sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidKeymap", "Sorry, unknown keymap"); + + printf("Asked to update keymap '%s'\n", id); + + new_keymap = zmalloc(sizeof(*new_keymap) + sizeof(struct keycode) * keycode_count); + if (!new_keymap) { + r = -ENOMEM; + goto out; + } + + new_keymap->layout = zmalloc(sizeof(struct keycode *) * cols * rows); + if (!new_keymap->layout) { + keymap_free(new_keymap); + r = -ENOMEM; + goto out; + } + + r = method_setkeymap_parse_dbus_msg(m, new_keymap, NULL, NULL, NULL, NULL); + if (r < 0) { + keymap_free(new_keymap); goto out; + } + + printf("\tUpdated keymap: name (%s), desc (%s), keycodes(%u), rows(%u), cols(%u)\n", + new_keymap->name, new_keymap->description, + new_keymap->keycode_count, + new_keymap->rows, new_keymap->cols); + + /* FIXME: Write to disk */ + list_replace(&old_keymap->list, &new_keymap->list); + keymap_free(old_keymap); - /* FIXME: save the result */ return sd_bus_reply_method_return(m, NULL); out: @@ -30,6 +30,15 @@ static inline void list_add(struct list_head *new, struct list_head *list) list->next = new; } +static inline void list_replace(struct list_head *old, struct list_head *new) +{ + old->prev->next = new; + old->next->prev = new; + new->next = old->next; + new->prev = old->prev; + old->next = old->prev = NULL; +} + static inline bool list_empty(struct list_head *list) { return list->next == list; |