summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Lortie <desrt@desrt.ca>2011-07-22 10:33:03 +0200
committerRyan Lortie <desrt@desrt.ca>2011-07-22 10:35:10 +0200
commite103f710c6ac5b9db21a88bd904b104bda1bf911 (patch)
tree6c7ac2457d3d06d65b2e91f3e323894ca9b5c5fc
parent5a8b222f297546105350e734bb79bd8373bdd1a2 (diff)
downloaddconf-e103f710c6ac5b9db21a88bd904b104bda1bf911.tar.gz
Support maybe types in dconf
Work around the fact that we can't send maybe types over D-Bus by sending a blob of serialised GVariant data instead. Abuse the fact that we're using an array to denote 'maybe' at the level of the dconf protocol and fill that array with 2 items (which would not otherwise be possible) to indicate this special case.
-rw-r--r--engine/dconf-engine.c45
-rw-r--r--service/service.c37
2 files changed, 77 insertions, 5 deletions
diff --git a/engine/dconf-engine.c b/engine/dconf-engine.c
index 087d780..88f7e83 100644
--- a/engine/dconf-engine.c
+++ b/engine/dconf-engine.c
@@ -565,6 +565,28 @@ dconf_engine_is_writable (DConfEngine *engine,
return writable;
}
+/* be conservative and fast: false negatives are OK */
+static gboolean
+is_dbusable (GVariant *value)
+{
+ const gchar *type;
+
+ type = g_variant_get_type_string (value);
+
+ /* maybe definitely won't work.
+ * variant? too lazy to check inside...
+ */
+ if (strchr (type, 'v') || strchr (type, 'm'))
+ return FALSE;
+
+ /* XXX: we could also check for '{}' not inside an array...
+ * but i'm not sure we want to support that anyway.
+ */
+
+ /* this will avoid any too-deeply-nested limits */
+ return strlen (type) < 32;
+}
+
static GVariant *
fake_maybe (GVariant *value)
{
@@ -573,7 +595,28 @@ fake_maybe (GVariant *value)
g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
if (value != NULL)
- g_variant_builder_add (&builder, "v", value);
+ {
+ if (is_dbusable (value))
+ g_variant_builder_add (&builder, "v", value);
+
+ else
+ {
+ GVariant *variant;
+ GVariant *ay;
+
+ variant = g_variant_new_variant (value);
+ ay = g_variant_new_from_data (G_VARIANT_TYPE_BYTESTRING,
+ g_variant_get_data (variant),
+ g_variant_get_size (variant),
+ TRUE,
+ (GDestroyNotify) g_variant_unref,
+ variant);
+ g_variant_builder_add (&builder, "v", ay);
+
+ g_variant_builder_add (&builder, "v",
+ g_variant_new_string ("serialised GVariant"));
+ }
+ }
return g_variant_builder_end (&builder);
}
diff --git a/service/service.c b/service/service.c
index 54418d1..99051ec 100644
--- a/service/service.c
+++ b/service/service.c
@@ -97,13 +97,42 @@ static void
unwrap_maybe (GVariant **ptr)
{
GVariant *array, *child;
+ gsize n_children;
array = *ptr;
+ n_children = g_variant_n_children (array);
- if (g_variant_n_children (array))
- child = g_variant_get_child_value (array, 0);
- else
- child = NULL;
+ switch (n_children)
+ {
+ case 0:
+ child = NULL;
+ break;
+ case 1: default:
+ child = g_variant_get_child_value (array, 0);
+ break;
+ case 2:
+ {
+ GVariant *untrusted;
+ GVariant *ay;
+
+ g_variant_get_child (array, 0, "v", &ay);
+ if (!g_variant_is_of_type (ay, G_VARIANT_TYPE_BYTESTRING))
+ {
+ g_variant_unref (ay);
+ child = NULL;
+ break;
+ }
+
+ untrusted = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT,
+ g_variant_get_data (ay),
+ g_variant_get_size (ay),
+ FALSE,
+ (GDestroyNotify) g_variant_unref, ay);
+ g_variant_ref_sink (untrusted);
+ child = g_variant_get_normal_form (untrusted);
+ g_variant_unref (untrusted);
+ }
+ }
g_variant_unref (array);
*ptr = child;