[Telepathy-commits] [telepathy-mission-control/master] Safer update of properties

Alberto Mardegan alberto.mardegan at nokia.com
Mon Jan 5 01:40:43 PST 2009


Use a different approach on updating properties: look for known properties, and
check their type before using them.
The _mc_iface_update_props() supports updating properties which come with an
interface prefix.
---
 libmcclient/dbus-api.c   |   67 ++++++++
 libmcclient/dbus-api.h   |   13 ++-
 libmcclient/mc-account.c |  410 +++++++++++++++++++++++++++------------------
 3 files changed, 324 insertions(+), 166 deletions(-)

diff --git a/libmcclient/dbus-api.c b/libmcclient/dbus-api.c
index 237cf83..e6c0d27 100644
--- a/libmcclient/dbus-api.c
+++ b/libmcclient/dbus-api.c
@@ -24,10 +24,16 @@
 #include "dbus-api.h"
 #include <string.h>
 
+#include <dbus/dbus-protocol.h>
+
 /* auto-generated stubs */
 #include "_gen/gtypes-body.h"
 #include "_gen/interfaces-body.h"
 
+/* interface + dot + property name + zero terminator */
+#define MC_QUALIFIED_PROPERTY_NAME_LEN \
+    (DBUS_MAXIMUM_NAME_LENGTH + 1 + DBUS_MAXIMUM_NAME_LENGTH + 1)
+
 #define MC_IFACE_IS_READY(iface_data) (*(iface_data->props_data_ptr) != NULL)
 
 typedef struct _McIfaceStatus McIfaceStatus;
@@ -354,13 +360,74 @@ _mc_gtype_from_dbus_signature (const gchar *signature)
 {
     if (G_UNLIKELY (!signature)) return G_TYPE_INVALID;
 
+    /* dbus-glib's functions that create the GTypes are implemented using a
+     * lookup table, so that if the sub-component types are the same, the same
+     * GType is returned.
+     * So here it should be safe to use any of the functions that return the
+     * desired type */
     if (strcmp (signature, "s") == 0)
         return G_TYPE_STRING;
     if (strcmp (signature, "b") == 0)
         return G_TYPE_BOOLEAN;
     if (strcmp (signature, "u") == 0)
         return G_TYPE_UINT;
+    if (strcmp (signature, "o") == 0)
+        return DBUS_TYPE_G_OBJECT_PATH;
+    if (strcmp (signature, "as") == 0)
+        return G_TYPE_STRV;
+    if (strcmp (signature, "a{sv}") == 0)
+        return TP_HASH_TYPE_STRING_VARIANT_MAP;
+    if (strcmp (signature, "(uss)") == 0)
+        return TP_STRUCT_TYPE_SIMPLE_PRESENCE;
+    if (strcmp (signature, "a(oa{sv})") == 0)
+        return MC_ARRAY_TYPE_CHANNEL_DETAILS_LIST;
     g_warning ("%s: Type %s not mapped", G_STRFUNC, signature);
     return G_TYPE_INVALID;
 }
 
+void
+_mc_iface_update_props (const McIfaceProperty *props_definition,
+                        GHashTable *properties, gpointer proxy_props,
+                        const gchar *iface_name, gsize iface_name_len)
+{
+    const McIfaceProperty *prop;
+    gchar qualified_name[MC_QUALIFIED_PROPERTY_NAME_LEN], *name_ptr = NULL;
+
+    if (iface_name)
+    {
+        g_return_if_fail (iface_name_len <= DBUS_MAXIMUM_NAME_LENGTH);
+        strcpy (qualified_name, iface_name);
+        name_ptr = qualified_name + iface_name_len;
+        *name_ptr = '.';
+        name_ptr++;
+    }
+
+    for (prop = props_definition; prop->name != NULL; prop++)
+    {
+        GValue *value;
+        GType type;
+
+        g_return_if_fail (strlen (prop->name) <= DBUS_MAXIMUM_NAME_LENGTH);
+        if (name_ptr)
+        {
+            strcpy (name_ptr, prop->name);
+            value = g_hash_table_lookup (properties, qualified_name);
+        }
+        else
+            value = g_hash_table_lookup (properties, prop->name);
+        if (!value) continue;
+
+        type = _mc_gtype_from_dbus_signature (prop->dbus_signature);
+        if (G_LIKELY (G_VALUE_HOLDS (value, type)))
+        {
+            prop->update_property (prop->name, value, proxy_props);
+        }
+        else
+        {
+            g_warning ("%s: %s is a %s, expecting %s",
+                       G_STRFUNC, prop->name,
+                       G_VALUE_TYPE_NAME (value), g_type_name (type));
+        }
+    }
+}
+
diff --git a/libmcclient/dbus-api.h b/libmcclient/dbus-api.h
index 2c8e809..104c0bc 100644
--- a/libmcclient/dbus-api.h
+++ b/libmcclient/dbus-api.h
@@ -54,8 +54,6 @@
 #include <libmcclient/_gen/gtypes.h>
 #include <libmcclient/_gen/interfaces.h>
 
-#define MC_STRUCT_TYPE_ACCOUNT_PRESENCE (TP_STRUCT_TYPE_SIMPLE_PRESENCE)
-
 void _mc_ext_register_dbus_glib_marshallers (void);
 
 inline void _mc_gvalue_stolen (GValue *value);
@@ -66,6 +64,13 @@ typedef struct _McIfaceData McIfaceData;
 typedef void (*McIfaceCreateProps) (TpProxy *proxy, GHashTable *props);
 typedef void (*McIfaceSetupPropsMonitor) (TpProxy *proxy, GQuark interface);
 
+typedef struct {
+    gchar *name;
+    gchar *dbus_signature;
+    void (*update_property) (const gchar *name, const GValue *value,
+                             gpointer props_struct);
+} McIfaceProperty;
+
 struct _McIfaceData {
     /* id of the interface */
     GQuark id;
@@ -121,4 +126,8 @@ gboolean _mc_iface_is_ready (gpointer object, GQuark iface);
 
 GType _mc_gtype_from_dbus_signature (const gchar *signature);
 
+void _mc_iface_update_props (const McIfaceProperty *props_definition,
+                             GHashTable *properties, gpointer proxy_props,
+                             const gchar *iface_name, gsize iface_name_len);
+
 #endif
diff --git a/libmcclient/mc-account.c b/libmcclient/mc-account.c
index 0548bcd..1c94205 100644
--- a/libmcclient/mc-account.c
+++ b/libmcclient/mc-account.c
@@ -383,184 +383,266 @@ mc_account_new (TpDBusDaemon *dbus, const gchar *object_path)
 }
 
 static void
-update_property (gpointer key, gpointer ht_value, gpointer user_data)
+update_display_name (const gchar *name, const GValue *value,
+                     gpointer user_data)
 {
-    McAccount *account = user_data;
+    McAccount *account = MC_ACCOUNT (user_data);
+    McAccountProps *props = account->priv->props;
+
+    g_free (props->display_name);
+    props->display_name = g_value_dup_string (value);
+    if (props->emit_changed)
+        g_signal_emit (account, _mc_account_signals[STRING_CHANGED],
+                       MC_QUARK_DISPLAY_NAME,
+                       MC_QUARK_DISPLAY_NAME,
+                       props->display_name);
+}
+
+static void
+update_icon (const gchar *name, const GValue *value, gpointer user_data)
+{
+    McAccount *account = MC_ACCOUNT (user_data);
+    McAccountProps *props = account->priv->props;
+
+    g_free (props->icon);
+    props->icon = g_value_dup_string (value);
+    if (props->emit_changed)
+        g_signal_emit (account, _mc_account_signals[STRING_CHANGED],
+                       MC_QUARK_ICON,
+                       MC_QUARK_ICON,
+                       props->icon);
+}
+
+static void
+update_valid (const gchar *name, const GValue *value, gpointer user_data)
+{
+    McAccount *account = MC_ACCOUNT (user_data);
+    McAccountProps *props = account->priv->props;
+
+    props->valid = g_value_get_boolean (value);
+    if (props->emit_changed)
+        g_signal_emit (account, _mc_account_signals[FLAG_CHANGED],
+                       MC_QUARK_VALID,
+                       MC_QUARK_VALID,
+                       props->valid);
+}
+
+static void
+update_enabled (const gchar *name, const GValue *value, gpointer user_data)
+{
+    McAccount *account = MC_ACCOUNT (user_data);
+    McAccountProps *props = account->priv->props;
+
+    props->enabled = g_value_get_boolean (value);
+    if (props->emit_changed)
+        g_signal_emit (account, _mc_account_signals[FLAG_CHANGED],
+                       MC_QUARK_ENABLED,
+                       MC_QUARK_ENABLED,
+                       props->enabled);
+}
+
+static void
+update_nickname (const gchar *name, const GValue *value, gpointer user_data)
+{
+    McAccount *account = MC_ACCOUNT (user_data);
+    McAccountProps *props = account->priv->props;
+
+    g_free (props->nickname);
+    props->nickname = g_value_dup_string (value);
+    if (props->emit_changed)
+        g_signal_emit (account, _mc_account_signals[STRING_CHANGED],
+                       MC_QUARK_NICKNAME,
+                       MC_QUARK_NICKNAME,
+                       props->nickname);
+}
+
+static void
+update_parameters (const gchar *name, const GValue *value,
+                   gpointer user_data)
+{
+    McAccount *account = MC_ACCOUNT (user_data);
+    McAccountProps *props = account->priv->props;
+    GHashTable *old_parameters = props->parameters;
+
+    props->parameters = g_value_dup_boxed (value);
+    if (props->emit_changed)
+        g_signal_emit (account, _mc_account_signals[PARAMETERS_CHANGED],
+                       0,
+                       old_parameters, props->parameters);
+    if (old_parameters)
+        g_hash_table_destroy (old_parameters);
+}
+
+static void
+update_automatic_presence (const gchar *name, const GValue *value,
+                           gpointer user_data)
+{
+    McAccount *account = MC_ACCOUNT (user_data);
     McAccountProps *props = account->priv->props;
-    GValue *value = ht_value;
-    const gchar *name = key;
     GValueArray *va;
 
-    if (strcmp (name, "DisplayName") == 0)
-    {
-	g_free (props->display_name);
-	props->display_name = g_value_dup_string (value);
-	if (props->emit_changed)
-	    g_signal_emit (account, _mc_account_signals[STRING_CHANGED],
-			   MC_QUARK_DISPLAY_NAME,
-			   MC_QUARK_DISPLAY_NAME,
-			   props->display_name);
-    }
-    else if (strcmp (name, "Icon") == 0)
-    {
-	g_free (props->icon);
-	props->icon = g_value_dup_string (value);
-	if (props->emit_changed)
-	    g_signal_emit (account, _mc_account_signals[STRING_CHANGED],
-			   MC_QUARK_ICON,
-			   MC_QUARK_ICON,
-			   props->icon);
-    }
-    else if (strcmp (name, "Valid") == 0)
-    {
-	props->valid = g_value_get_boolean (value);
-	if (props->emit_changed)
-	    g_signal_emit (account, _mc_account_signals[FLAG_CHANGED],
-			   MC_QUARK_VALID,
-			   MC_QUARK_VALID,
-			   props->valid);
-    }
-    else if (strcmp (name, "Enabled") == 0)
-    {
-	props->enabled = g_value_get_boolean (value);
-	if (props->emit_changed)
-	    g_signal_emit (account, _mc_account_signals[FLAG_CHANGED],
-			   MC_QUARK_ENABLED,
-			   MC_QUARK_ENABLED,
-			   props->enabled);
-    }
-    else if (strcmp (name, "Nickname") == 0)
-    {
-	g_free (props->nickname);
-	props->nickname = g_value_dup_string (value);
-	if (props->emit_changed)
-	    g_signal_emit (account, _mc_account_signals[STRING_CHANGED],
-			   MC_QUARK_NICKNAME,
-			   MC_QUARK_NICKNAME,
-			   props->nickname);
-    }
-    else if (strcmp (name, "Parameters") == 0)
-    {
-	GHashTable *old_parameters = props->parameters;
-
-	props->parameters = g_value_get_boxed (value);
-	_mc_gvalue_stolen (value);
-	if (props->emit_changed)
-	    g_signal_emit (account, _mc_account_signals[PARAMETERS_CHANGED],
-			   0,
-			   old_parameters, props->parameters);
-	if (old_parameters)
-	    g_hash_table_destroy (old_parameters);
-    }
-    else if (strcmp (name, "AutomaticPresence") == 0)
-    {
-	g_free (props->auto_presence_status);
-	g_free (props->auto_presence_message);
-	va = g_value_get_boxed (value);
-	props->auto_presence_type = (gint)g_value_get_uint (va->values);
-	props->auto_presence_status = g_value_dup_string (va->values + 1);
-	props->auto_presence_message = g_value_dup_string (va->values + 2);
-	if (props->emit_changed)
-	    g_signal_emit (account, _mc_account_signals[PRESENCE_CHANGED],
-			   MC_QUARK_AUTOMATIC_PRESENCE,
-			   MC_QUARK_AUTOMATIC_PRESENCE,
-			   props->auto_presence_type,
-			   props->auto_presence_status,
-			   props->auto_presence_message);
-    }
-    else if (strcmp (name, "ConnectAutomatically") == 0)
-    {
-	props->connect_automatically = g_value_get_boolean (value);
-	if (props->emit_changed)
-	    g_signal_emit (account, _mc_account_signals[FLAG_CHANGED],
-			   MC_QUARK_CONNECT_AUTOMATICALLY,
-			   MC_QUARK_CONNECT_AUTOMATICALLY,
-			   props->connect_automatically);
-    }
-    else if (strcmp (name, "Connection") == 0)
-    {
-	const gchar *object_path;
-	g_free (props->connection);
-	if (G_LIKELY (G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH)))
-	{
-	    object_path = g_value_get_boxed (value);
-	    if (object_path && strcmp (object_path, "/") != 0)
-		props->connection = g_strdup (object_path);
-	    else
-		props->connection = NULL;
-	}
-	else
-	{
-	    g_warning ("%s: %s not an object path", G_STRFUNC, name);
-	    props->connection = NULL;
-	}
-    }
-    else if (strcmp (name, "ConnectionStatus") == 0)
-    {
-	props->connection_status = g_value_get_uint (value);
-	if (props->emit_changed)
-	    props->emit_connection_status_changed = TRUE;
-    }
-    else if (strcmp (name, "ConnectionStatusReason") == 0)
-    {
-	props->connection_status_reason = g_value_get_uint (value);
-	if (props->emit_changed)
-	    props->emit_connection_status_changed = TRUE;
-    }
-    else if (strcmp (name, "CurrentPresence") == 0)
-    {
-	g_free (props->curr_presence_status);
-	g_free (props->curr_presence_message);
-	va = g_value_get_boxed (value);
-	props->curr_presence_type = (gint)g_value_get_uint (va->values);
-	props->curr_presence_status = g_value_dup_string (va->values + 1);
-	props->curr_presence_message = g_value_dup_string (va->values + 2);
-	if (props->emit_changed)
-	    g_signal_emit (account, _mc_account_signals[PRESENCE_CHANGED],
-			   MC_QUARK_CURRENT_PRESENCE,
-			   MC_QUARK_CURRENT_PRESENCE,
-			   props->curr_presence_type,
-			   props->curr_presence_status,
-			   props->curr_presence_message);
-    }
-    else if (strcmp (name, "RequestedPresence") == 0)
-    {
-	g_free (props->req_presence_status);
-	g_free (props->req_presence_message);
-	va = g_value_get_boxed (value);
-	props->req_presence_type = (gint)g_value_get_uint (va->values);
-	props->req_presence_status = g_value_dup_string (va->values + 1);
-	props->req_presence_message = g_value_dup_string (va->values + 2);
-	if (props->emit_changed)
-	    g_signal_emit (account, _mc_account_signals[PRESENCE_CHANGED],
-			   MC_QUARK_REQUESTED_PRESENCE,
-			   MC_QUARK_REQUESTED_PRESENCE,
-			   props->req_presence_type,
-			   props->req_presence_status,
-			   props->req_presence_message);
-    }
-    else if (strcmp (name, "NormalizedName") == 0)
-    {
-	g_free (props->normalized_name);
-	props->normalized_name = g_value_dup_string (value);
-	if (props->emit_changed)
-	    g_signal_emit (account, _mc_account_signals[STRING_CHANGED],
-			   MC_QUARK_NORMALIZED_NAME,
-			   MC_QUARK_NORMALIZED_NAME,
-			   props->normalized_name);
-    }
+    g_free (props->auto_presence_status);
+    g_free (props->auto_presence_message);
+    va = g_value_get_boxed (value);
+    props->auto_presence_type = (gint)g_value_get_uint (va->values);
+    props->auto_presence_status = g_value_dup_string (va->values + 1);
+    props->auto_presence_message = g_value_dup_string (va->values + 2);
+    if (props->emit_changed)
+        g_signal_emit (account, _mc_account_signals[PRESENCE_CHANGED],
+                       MC_QUARK_AUTOMATIC_PRESENCE,
+                       MC_QUARK_AUTOMATIC_PRESENCE,
+                       props->auto_presence_type,
+                       props->auto_presence_status,
+                       props->auto_presence_message);
+}
+
+static void
+update_connect_automatically (const gchar *name, const GValue *value,
+                              gpointer user_data)
+{
+    McAccount *account = MC_ACCOUNT (user_data);
+    McAccountProps *props = account->priv->props;
+
+    props->connect_automatically = g_value_get_boolean (value);
+    if (props->emit_changed)
+        g_signal_emit (account, _mc_account_signals[FLAG_CHANGED],
+                       MC_QUARK_CONNECT_AUTOMATICALLY,
+                       MC_QUARK_CONNECT_AUTOMATICALLY,
+                       props->connect_automatically);
 }
 
 static void
+update_connection (const gchar *name, const GValue *value,
+                   gpointer user_data)
+{
+    McAccount *account = MC_ACCOUNT (user_data);
+    McAccountProps *props = account->priv->props;
+    const gchar *object_path;
+
+    g_free (props->connection);
+    object_path = g_value_get_boxed (value);
+    if (object_path && strcmp (object_path, "/") != 0)
+        props->connection = g_strdup (object_path);
+    else
+        props->connection = NULL;
+}
+
+static void
+update_connection_status (const gchar *name, const GValue *value,
+                          gpointer user_data)
+{
+    McAccount *account = MC_ACCOUNT (user_data);
+    McAccountProps *props = account->priv->props;
+
+    props->connection_status = g_value_get_uint (value);
+    if (props->emit_changed)
+        props->emit_connection_status_changed = TRUE;
+}
+
+static void
+update_connection_status_reason (const gchar *name, const GValue *value,
+                                 gpointer user_data)
+{
+    McAccount *account = MC_ACCOUNT (user_data);
+    McAccountProps *props = account->priv->props;
+
+    props->connection_status_reason = g_value_get_uint (value);
+    if (props->emit_changed)
+        props->emit_connection_status_changed = TRUE;
+}
+
+static void
+update_current_presence (const gchar *name, const GValue *value,
+                         gpointer user_data)
+{
+    McAccount *account = MC_ACCOUNT (user_data);
+    McAccountProps *props = account->priv->props;
+    GValueArray *va;
+
+    g_free (props->curr_presence_status);
+    g_free (props->curr_presence_message);
+    va = g_value_get_boxed (value);
+    props->curr_presence_type = (gint)g_value_get_uint (va->values);
+    props->curr_presence_status = g_value_dup_string (va->values + 1);
+    props->curr_presence_message = g_value_dup_string (va->values + 2);
+    if (props->emit_changed)
+        g_signal_emit (account, _mc_account_signals[PRESENCE_CHANGED],
+                       MC_QUARK_CURRENT_PRESENCE,
+                       MC_QUARK_CURRENT_PRESENCE,
+                       props->curr_presence_type,
+                       props->curr_presence_status,
+                       props->curr_presence_message);
+}
+
+static void
+update_requested_presence (const gchar *name, const GValue *value,
+                           gpointer user_data)
+{
+    McAccount *account = MC_ACCOUNT (user_data);
+    McAccountProps *props = account->priv->props;
+    GValueArray *va;
+
+    g_free (props->req_presence_status);
+    g_free (props->req_presence_message);
+    va = g_value_get_boxed (value);
+    props->req_presence_type = (gint)g_value_get_uint (va->values);
+    props->req_presence_status = g_value_dup_string (va->values + 1);
+    props->req_presence_message = g_value_dup_string (va->values + 2);
+    if (props->emit_changed)
+        g_signal_emit (account, _mc_account_signals[PRESENCE_CHANGED],
+                       MC_QUARK_REQUESTED_PRESENCE,
+                       MC_QUARK_REQUESTED_PRESENCE,
+                       props->req_presence_type,
+                       props->req_presence_status,
+                       props->req_presence_message);
+}
+
+static void
+update_normalized_name (const gchar *name, const GValue *value,
+                        gpointer user_data)
+{
+    McAccount *account = MC_ACCOUNT (user_data);
+    McAccountProps *props = account->priv->props;
+
+    g_free (props->normalized_name);
+    props->normalized_name = g_value_dup_string (value);
+    if (props->emit_changed)
+        g_signal_emit (account, _mc_account_signals[STRING_CHANGED],
+                       MC_QUARK_NORMALIZED_NAME,
+                       MC_QUARK_NORMALIZED_NAME,
+                       props->normalized_name);
+}
+
+static const McIfaceProperty account_properties[] =
+{
+    { "DisplayName", "s", update_display_name },
+    { "Icon", "s", update_icon },
+    { "Valid", "b", update_valid },
+    { "Enabled", "b", update_enabled },
+    { "Nickname", "s", update_nickname },
+    { "Parameters", "a{sv}", update_parameters },
+    { "AutomaticPresence", "(uss)", update_automatic_presence },
+    { "ConnectAutomatically", "b", update_connect_automatically },
+    { "Connection", "o", update_connection },
+    { "ConnectionStatus", "u", update_connection_status },
+    { "ConnectionStatusReason", "u", update_connection_status_reason },
+    { "CurrentPresence", "(uss)", update_current_presence },
+    { "RequestedPresence", "(uss)", update_requested_presence },
+    { "NormalizedName", "s", update_normalized_name },
+    { NULL, NULL, NULL }
+};
+
+static void
 create_props (TpProxy *proxy, GHashTable *props)
 {
     McAccount *account = MC_ACCOUNT (proxy);
     McAccountPrivate *priv = account->priv;
 
     priv->props = g_malloc0 (sizeof (McAccountProps));
-    g_hash_table_foreach (props, update_property, account);
+    _mc_iface_update_props (account_properties, props, account, NULL, 0);
     priv->props->emit_changed = TRUE;
 }
+
 static void 
 on_account_property_changed (TpProxy *proxy, GHashTable *props, 
 			     gpointer user_data, GObject *weak_object) 
@@ -571,7 +653,7 @@ on_account_property_changed (TpProxy *proxy, GHashTable *props,
     /* if the GetAll method hasn't returned yet, we do nothing */
     if (G_UNLIKELY (!priv->props)) return;
 
-    g_hash_table_foreach (props, update_property, account);
+    _mc_iface_update_props (account_properties, props, account, NULL, 0);
     if (priv->props->emit_connection_status_changed)
     {
 	g_signal_emit (account,
-- 
1.5.6.5




More information about the Telepathy-commits mailing list