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; | 
