[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