Simplify DBus notification assembly

This commit is contained in:
Benedikt Heine 2018-12-04 03:25:28 +01:00
parent a8faea725d
commit b10bb292c6
2 changed files with 136 additions and 136 deletions

View File

@ -142,96 +142,84 @@ static void on_get_capabilities(GDBusConnection *connection,
static struct notification *dbus_message_to_notification(const gchar *sender, GVariant *parameters)
{
/* Assert that the parameters' type is actually correct. Albeit usually DBus
* already rejects ill typed parameters, it may not be always the case. */
GVariantType *required_type = g_variant_type_new("(susssasa{sv}i)");
if (!g_variant_is_of_type(parameters, required_type)) {
g_variant_type_free(required_type);
return NULL;
}
struct notification *n = notification_create();
n->dbus_client = g_strdup(sender);
n->dbus_valid = true;
{
GVariantIter *iter = g_variant_iter_new(parameters);
GVariant *content;
GVariant *dict_value;
int idx = 0;
while ((content = g_variant_iter_next_value(iter))) {
GVariant *hints;
gchar **actions;
int timeout;
switch (idx) {
case 0:
if (g_variant_is_of_type(content, G_VARIANT_TYPE_STRING))
n->appname = g_variant_dup_string(content, NULL);
break;
case 1:
if (g_variant_is_of_type(content, G_VARIANT_TYPE_UINT32))
n->id = g_variant_get_uint32(content);
break;
case 2:
if (g_variant_is_of_type(content, G_VARIANT_TYPE_STRING))
n->icon = g_variant_dup_string(content, NULL);
break;
case 3:
if (g_variant_is_of_type(content, G_VARIANT_TYPE_STRING))
n->summary = g_variant_dup_string(content, NULL);
break;
case 4:
if (g_variant_is_of_type(content, G_VARIANT_TYPE_STRING))
n->body = g_variant_dup_string(content, NULL);
break;
case 5:
if (g_variant_is_of_type(content, G_VARIANT_TYPE_STRING_ARRAY)) {
gsize amount;
const gchar **out = g_variant_get_strv(content, &amount);
GVariantIter i;
g_variant_iter_init(&i, parameters);
for(gsize i = 0; i+1 < amount; i+=2)
g_hash_table_insert(n->actions, g_strdup(out[i]), g_strdup(out[i+1]));
g_variant_iter_next(&i, "s", &n->appname);
g_variant_iter_next(&i, "u", &n->id);
g_variant_iter_next(&i, "s", &n->icon);
g_variant_iter_next(&i, "s", &n->summary);
g_variant_iter_next(&i, "s", &n->body);
g_variant_iter_next(&i, "^a&s", &actions);
g_variant_iter_next(&i, "@a{?*}", &hints);
g_variant_iter_next(&i, "i", &timeout);
g_free(out);
gsize num = 0;
while (actions[num]) {
if (actions[num+1]) {
g_hash_table_insert(n->actions,
g_strdup(actions[num]),
g_strdup(actions[num+1]));
num+=2;
} else {
LOG_W("Odd length in actions array. Ignoring element: %s", actions[num]);
break;
}
}
break;
case 6:
if (g_variant_is_of_type(content, G_VARIANT_TYPE_DICTIONARY)) {
dict_value = g_variant_lookup_value(content, "urgency", G_VARIANT_TYPE_BYTE);
if (dict_value) {
GVariant *dict_value;
if ((dict_value = g_variant_lookup_value(hints, "urgency", G_VARIANT_TYPE_BYTE))) {
n->urgency = g_variant_get_byte(dict_value);
g_variant_unref(dict_value);
}
dict_value = g_variant_lookup_value(content, "fgcolor", G_VARIANT_TYPE_STRING);
if (dict_value) {
if ((dict_value = g_variant_lookup_value(hints, "fgcolor", G_VARIANT_TYPE_STRING))) {
n->colors.fg = g_variant_dup_string(dict_value, NULL);
g_variant_unref(dict_value);
}
dict_value = g_variant_lookup_value(content, "bgcolor", G_VARIANT_TYPE_STRING);
if (dict_value) {
if ((dict_value = g_variant_lookup_value(hints, "bgcolor", G_VARIANT_TYPE_STRING))) {
n->colors.bg = g_variant_dup_string(dict_value, NULL);
g_variant_unref(dict_value);
}
dict_value = g_variant_lookup_value(content, "frcolor", G_VARIANT_TYPE_STRING);
if (dict_value) {
if ((dict_value = g_variant_lookup_value(hints, "frcolor", G_VARIANT_TYPE_STRING))) {
n->colors.frame = g_variant_dup_string(dict_value, NULL);
g_variant_unref(dict_value);
}
dict_value = g_variant_lookup_value(content, "category", G_VARIANT_TYPE_STRING);
if (dict_value) {
if ((dict_value = g_variant_lookup_value(hints, "category", G_VARIANT_TYPE_STRING))) {
n->category = g_variant_dup_string(dict_value, NULL);
g_variant_unref(dict_value);
}
dict_value = g_variant_lookup_value(content, "image-path", G_VARIANT_TYPE_STRING);
if (dict_value) {
if ((dict_value = g_variant_lookup_value(hints, "image-path", G_VARIANT_TYPE_STRING))) {
g_free(n->icon);
n->icon = g_variant_dup_string(dict_value, NULL);
g_variant_unref(dict_value);
}
dict_value = g_variant_lookup_value(content, "image-data", G_VARIANT_TYPE("(iiibiiay)"));
dict_value = g_variant_lookup_value(hints, "image-data", G_VARIANT_TYPE("(iiibiiay)"));
if (!dict_value)
dict_value = g_variant_lookup_value(content, "image_data", G_VARIANT_TYPE("(iiibiiay)"));
dict_value = g_variant_lookup_value(hints, "image_data", G_VARIANT_TYPE("(iiibiiay)"));
if (!dict_value)
dict_value = g_variant_lookup_value(content, "icon_data", G_VARIANT_TYPE("(iiibiiay)"));
dict_value = g_variant_lookup_value(hints, "icon_data", G_VARIANT_TYPE("(iiibiiay)"));
if (dict_value) {
n->raw_icon = get_raw_image_from_data_hint(dict_value);
g_variant_unref(dict_value);
@ -243,21 +231,21 @@ static struct notification *dbus_message_to_notification(const gchar *sender, GV
* But notify-send does not support hints of type 'boolean'.
* So let's check for int and boolean until notify-send is fixed.
*/
if((dict_value = g_variant_lookup_value(content, "transient", G_VARIANT_TYPE_BOOLEAN))) {
if ((dict_value = g_variant_lookup_value(hints, "transient", G_VARIANT_TYPE_BOOLEAN))) {
n->transient = g_variant_get_boolean(dict_value);
g_variant_unref(dict_value);
} else if((dict_value = g_variant_lookup_value(content, "transient", G_VARIANT_TYPE_UINT32))) {
} else if ((dict_value = g_variant_lookup_value(hints, "transient", G_VARIANT_TYPE_UINT32))) {
n->transient = g_variant_get_uint32(dict_value) > 0;
g_variant_unref(dict_value);
} else if((dict_value = g_variant_lookup_value(content, "transient", G_VARIANT_TYPE_INT32))) {
} else if ((dict_value = g_variant_lookup_value(hints, "transient", G_VARIANT_TYPE_INT32))) {
n->transient = g_variant_get_int32(dict_value) > 0;
g_variant_unref(dict_value);
}
if((dict_value = g_variant_lookup_value(content, "value", G_VARIANT_TYPE_INT32))) {
if ((dict_value = g_variant_lookup_value(hints, "value", G_VARIANT_TYPE_INT32))) {
n->progress = g_variant_get_int32(dict_value);
g_variant_unref(dict_value);
} else if((dict_value = g_variant_lookup_value(content, "value", G_VARIANT_TYPE_UINT32))) {
} else if ((dict_value = g_variant_lookup_value(hints, "value", G_VARIANT_TYPE_UINT32))) {
n->progress = g_variant_get_uint32(dict_value);
g_variant_unref(dict_value);
}
@ -267,27 +255,19 @@ static struct notification *dbus_message_to_notification(const gchar *sender, GV
* Only accept to first one we find.
*/
for (int i = 0; i < sizeof(stack_tag_hints)/sizeof(*stack_tag_hints); ++i) {
dict_value = g_variant_lookup_value(content, stack_tag_hints[i], G_VARIANT_TYPE_STRING);
if (dict_value) {
if ((dict_value = g_variant_lookup_value(hints, stack_tag_hints[i], G_VARIANT_TYPE_STRING))) {
n->stack_tag = g_variant_dup_string(dict_value, NULL);
g_variant_unref(dict_value);
break;
}
}
}
break;
case 7:
if (g_variant_is_of_type(content, G_VARIANT_TYPE_INT32))
n->timeout = g_variant_get_int32(content) * 1000;
break;
}
g_variant_unref(content);
idx++;
}
if (timeout >= 0)
n->timeout = timeout * 1000;
g_variant_iter_free(iter);
}
g_variant_unref(hints);
g_variant_type_free(required_type);
g_free(actions); // the strv is only a shallow copy
notification_init(n);
return n;
@ -299,6 +279,13 @@ static void on_notify(GDBusConnection *connection,
GDBusMethodInvocation *invocation)
{
struct notification *n = dbus_message_to_notification(sender, parameters);
if (!n) {
g_dbus_method_invocation_return_dbus_error(
invocation,
"Cannot decode notification!",
"");
}
int id = queues_notification_insert(n);
GVariant *reply = g_variant_new("(u)", id);

View File

@ -145,6 +145,18 @@ TEST test_dbus_teardown(void)
PASS();
}
TEST test_invalid_notification(void)
{
GVariant *faulty = g_variant_new_boolean(true);
ASSERT(NULL == dbus_message_to_notification(":123", faulty));
ASSERT(NULL == dbus_invoke("Notify", faulty));
g_variant_unref(faulty);
PASS();
}
TEST test_basic_notification(void)
{
struct dbus_notification *n = dbus_notification_new();
@ -210,6 +222,7 @@ gpointer run_threaded_tests(gpointer data)
RUN_TEST(test_dbus_init);
RUN_TEST(test_basic_notification);
RUN_TEST(test_invalid_notification);
RUN_TESTp(test_server_caps, MARKUP_FULL);
RUN_TESTp(test_server_caps, MARKUP_STRIP);
RUN_TESTp(test_server_caps, MARKUP_NO);