From 2b9528933b62bcb75c2b631f823a5fbe5f6186da Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Mon, 28 May 2012 10:27:34 +0200 Subject: [PATCH] WIP: TpBaseConnection: add a contact id converter function It is used in RequestHandles and GetContactByID to let CM do server roundtrip normalization/conversion of the ID. This is used by WLM server to convert email addresses to XMPP jid. https://bugs.freedesktop.org/show_bug.cgi?id=50341 --- telepathy-glib/base-connection-internal.h | 8 ++ telepathy-glib/base-connection.c | 127 +++++++++++++++++++++++++++++ telepathy-glib/base-connection.h | 8 ++ telepathy-glib/contacts-mixin.c | 61 +++++++++++--- 4 files changed, 193 insertions(+), 11 deletions(-) diff --git a/telepathy-glib/base-connection-internal.h b/telepathy-glib/base-connection-internal.h index cd731d4..ecf2b33 100644 --- a/telepathy-glib/base-connection-internal.h +++ b/telepathy-glib/base-connection-internal.h @@ -33,6 +33,14 @@ void _tp_base_connection_set_handle_repo (TpBaseConnection *self, gpointer _tp_base_connection_find_channel_manager (TpBaseConnection *self, GType type); +void _tp_base_connection_convert_contact_id_async (TpBaseConnection *self, + const gchar *id, + GAsyncReadyCallback callback, + gpointer user_data); +gchar *_tp_base_connection_convert_contact_id_finish (TpBaseConnection *self, + GAsyncResult *result, + GError **error); + G_END_DECLS #endif diff --git a/telepathy-glib/base-connection.c b/telepathy-glib/base-connection.c index fe268fc..ac84859 100644 --- a/telepathy-glib/base-connection.c +++ b/telepathy-glib/base-connection.c @@ -251,6 +251,7 @@ #define DEBUG_FLAG TP_DEBUG_CONNECTION #include "telepathy-glib/debug-internal.h" +#include "telepathy-glib/util-internal.h" static void conn_iface_init (gpointer, gpointer); static void requests_iface_init (gpointer, gpointer); @@ -422,6 +423,8 @@ struct _TpBaseConnectionPrivate /* GQuark iface => GHashTable { * unique name borrowed from interested_clients => gsize count } */ GHashTable *client_interests; + + TpBaseConnectionConvertContactIdFunc convert_contact_id_async; }; static guint tp_base_connection_get_dbus_status (TpBaseConnection *self); @@ -1686,6 +1689,11 @@ tp_base_connection_class_init (TpBaseConnectionClass *klass) requests_properties); } +static void default_convert_contact_id_async (TpBaseConnection *self, + const gchar *id, + GAsyncReadyCallback callback, + gpointer user_data); + static void tp_base_connection_init (TpBaseConnection *self) { @@ -1706,6 +1714,8 @@ tp_base_connection_init (TpBaseConnection *self) (GDestroyNotify) g_hash_table_unref); priv->interested_clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + priv->convert_contact_id_async = default_convert_contact_id_async; } static gchar * @@ -2507,6 +2517,45 @@ tp_base_connection_release_handles (TpSvcConnection *iface, tp_svc_connection_return_from_release_handles (context); } +static void +request_handles_convert_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + TpBaseConnection *self = (TpBaseConnection *) source; + DBusGMethodInvocation *context = user_data; + TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self, + TP_HANDLE_TYPE_CONTACT); + gchar *id; + TpHandle handle; + GArray *handles; + GError *error = NULL; + + id = _tp_base_connection_convert_contact_id_finish (self, result, &error); + if (id == NULL) + { + dbus_g_method_return_error (context, error); + g_clear_error (&error); + return; + } + + handle = tp_handle_ensure (contact_repo, id, NULL, &error); + if (error != NULL) + { + dbus_g_method_return_error (context, error); + g_clear_error (&error); + g_free (id); + return; + } + + handles = g_array_new (FALSE, FALSE, sizeof (guint)); + g_array_append_val (handles, handle); + + tp_svc_connection_return_from_request_handles (context, handles); + + g_free (id); + g_array_unref (handles); +} /** * tp_base_connection_dbus_request_handles: (skip) @@ -2561,6 +2610,14 @@ tp_base_connection_dbus_request_handles (TpSvcConnection *iface, goto out; } + /* FIXME: Quick And Dirty hack */ + if (count == 1 && handle_type == TP_HANDLE_TYPE_CONTACT) + { + _tp_base_connection_convert_contact_id_async (self, names[0], + request_handles_convert_cb, context); + return; + } + handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), count); for (i = 0; i < count; i++) @@ -3883,3 +3940,73 @@ _tp_base_connection_find_channel_manager (TpBaseConnection *self, return NULL; } + +/* Default no-op implementation */ +static void +default_convert_contact_id_async (TpBaseConnection *self, + const gchar *id, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *result; + + result = g_simple_async_result_new ((GObject *) self, callback, user_data, + default_convert_contact_id_async); + + g_simple_async_result_set_op_res_gpointer (result, g_strdup (id), g_free); + g_simple_async_result_complete_in_idle (result); +} + +void +_tp_base_connection_convert_contact_id_async (TpBaseConnection *self, + const gchar *id, + GAsyncReadyCallback callback, + gpointer user_data) +{ + self->priv->convert_contact_id_async (self, id, callback, user_data); +} + +gchar * +_tp_base_connection_convert_contact_id_finish (TpBaseConnection *self, + GAsyncResult *result, + GError **error) +{ + _tp_implement_finish_return_copy_pointer (self, + self->priv->convert_contact_id_async, g_strdup); +} + +/** + * TpBaseConnectionConvertContactIdFunc: (skip) + * @self: a #TpBaseConnection + * @id: a contact identifier + * @callback: a callback to call when the operation finishes + * @user_data: data to pass to @callback + * + * Signature of a function to pass to + * tp_base_connection_set_convert_contact_id_func(). + * + * @callback must be called with a GSimpleAsyncResult with the converted id set + * in op_res_gpointer. The result's source must be this function. + * + * Since: 0.UNRELEASED + */ + +/** + * tp_base_connection_set_convert_contact_id_func: (skip) + * @self: a #TpBaseConnection + * @convert_contact_id_async: a #TpBaseConnectionConvertContactIdFunc + * + * Set a function to convert well known contact id to a server-specific id. This + * is used by WLM to convert user@live.com to 1234@messenger.live.com. + * + * Since: 0.UNRELEASED + */ +void +tp_base_connection_set_convert_contact_id_func (TpBaseConnection *self, + TpBaseConnectionConvertContactIdFunc convert_contact_id_async) +{ + g_return_if_fail (TP_IS_BASE_CONNECTION (self)); + g_return_if_fail (convert_contact_id_async != NULL); + + self->priv->convert_contact_id_async = convert_contact_id_async; +} diff --git a/telepathy-glib/base-connection.h b/telepathy-glib/base-connection.h index ae772d0..f69e1fe 100644 --- a/telepathy-glib/base-connection.h +++ b/telepathy-glib/base-connection.h @@ -216,6 +216,14 @@ void tp_base_connection_add_client_interest (TpBaseConnection *self, void tp_base_connection_add_possible_client_interest (TpBaseConnection *self, GQuark token); +typedef void (*TpBaseConnectionConvertContactIdFunc) (TpBaseConnection *self, + const gchar *id, + GAsyncReadyCallback callback, + gpointer user_data); + +void tp_base_connection_set_convert_contact_id_func (TpBaseConnection *self, + TpBaseConnectionConvertContactIdFunc convert_contact_id_async); + G_END_DECLS #endif /* #ifndef __TP_BASE_CONNECTION_H__*/ diff --git a/telepathy-glib/contacts-mixin.c b/telepathy-glib/contacts-mixin.c index 90cadc6..47df4bb 100644 --- a/telepathy-glib/contacts-mixin.c +++ b/telepathy-glib/contacts-mixin.c @@ -65,6 +65,7 @@ #define DEBUG_FLAG TP_DEBUG_CONNECTION #include "debug-internal.h" +#include "base-connection-internal.h" struct _TpContactsMixinPrivate { @@ -379,29 +380,43 @@ tp_contacts_mixin_get_contact_attributes_impl ( g_hash_table_unref (result); } +typedef struct +{ + GStrv interfaces; + DBusGMethodInvocation *context; +} GetContactByIdData; + static void -tp_contacts_mixin_get_contact_by_id_impl ( - TpSvcConnectionInterfaceContacts *iface, - const gchar *id, - const gchar **interfaces, - DBusGMethodInvocation *context) +convert_contact_id_cb (GObject *source, + GAsyncResult *async_result, + gpointer user_data) { - TpBaseConnection *conn = TP_BASE_CONNECTION (iface); + TpBaseConnection *conn = (TpBaseConnection *) source; + GetContactByIdData *data = user_data; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT); TpHandle handle; GArray *handles; GHashTable *attributes; GHashTable *result; + gchar *id; GError *error = NULL; - TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (conn, context); + id = _tp_base_connection_convert_contact_id_finish (conn, async_result, + &error); + if (id == NULL) + { + dbus_g_method_return_error (data->context, error); + g_clear_error (&error); + return; + } handle = tp_handle_ensure (contact_repo, id, NULL, &error); if (handle == 0) { - dbus_g_method_return_error (context, error); + dbus_g_method_return_error (data->context, error); g_clear_error (&error); + g_free (id); return; } @@ -409,18 +424,42 @@ tp_contacts_mixin_get_contact_by_id_impl ( g_array_append_val (handles, handle); attributes = tp_contacts_mixin_get_contact_attributes (G_OBJECT (conn), - handles, interfaces, always_included_interfaces, NULL); + handles, (const gchar **) data->interfaces, always_included_interfaces, + NULL); result = g_hash_table_lookup (attributes, GUINT_TO_POINTER (handle)); g_assert (result != NULL); - tp_svc_connection_interface_contacts_return_from_get_contact_by_id (context, - handle, result); + tp_svc_connection_interface_contacts_return_from_get_contact_by_id ( + data->context, handle, result); + g_free (id); + g_strfreev (data->interfaces); + g_slice_free (GetContactByIdData, data); g_array_unref (handles); g_hash_table_unref (attributes); } +static void +tp_contacts_mixin_get_contact_by_id_impl ( + TpSvcConnectionInterfaceContacts *iface, + const gchar *id, + const gchar **interfaces, + DBusGMethodInvocation *context) +{ + TpBaseConnection *conn = TP_BASE_CONNECTION (iface); + GetContactByIdData *data; + + TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (conn, context); + + data = g_slice_new0 (GetContactByIdData); + data->interfaces = g_strdupv ((gchar **) interfaces); + data->context = context; + + _tp_base_connection_convert_contact_id_async (conn, id, + convert_contact_id_cb, data); +} + /** * tp_contacts_mixin_iface_init: (skip) * @g_iface: A pointer to the #TpSvcConnectionInterfaceContacts in an object -- 1.7.9.5