summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rcm-server-keymap.c3
-rw-r--r--rcm-server-main.c322
-rw-r--r--utils.h9
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:
diff --git a/utils.h b/utils.h
index 9cb775b..fd9db77 100644
--- a/utils.h
+++ b/utils.h
@@ -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;