From 60e03f52d8dd14adb4c4b88b306441b125496d20 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Mon, 28 May 2012 10:27:34 +0200 Subject: [PATCH] WIP: add tp_handle_ensure_async() 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 --- docs/reference/telepathy-glib-sections.txt | 6 + telepathy-glib/base-connection.c | 34 +++++ telepathy-glib/contacts-mixin.c | 71 +++++++--- telepathy-glib/handle-repo-internal.h | 6 + telepathy-glib/handle-repo.c | 211 ++++++++++++++++++++++------ telepathy-glib/handle-repo.h | 33 +++++ 6 files changed, 297 insertions(+), 64 deletions(-) diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt index 302c508..9c090d4 100644 --- a/docs/reference/telepathy-glib-sections.txt +++ b/docs/reference/telepathy-glib-sections.txt @@ -252,6 +252,12 @@ tp_handle_set_qdata tp_handle_get_qdata tp_handle_ensure tp_handle_lookup + +tp_handle_ensure_async +tp_handle_ensure_finish +TpHandleRepoIfaceEnsureHandleFinishFunc +TpHandleRepoIfaceEnsureHandleFunc +tp_handle_repo_iface_implement_ensure_handle_async TP_HANDLE_REPO_IFACE TP_IS_HANDLE_REPO_IFACE diff --git a/telepathy-glib/base-connection.c b/telepathy-glib/base-connection.c index fe268fc..3776590 100644 --- a/telepathy-glib/base-connection.c +++ b/telepathy-glib/base-connection.c @@ -2507,6 +2507,32 @@ tp_base_connection_release_handles (TpSvcConnection *iface, tp_svc_connection_return_from_release_handles (context); } +static void +ensure_handle_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + TpHandleRepoIface *repo = (TpHandleRepoIface *) source; + DBusGMethodInvocation *context = user_data; + TpHandle handle; + GArray *handles; + GError *error = NULL; + + handle = tp_handle_ensure_finish (repo, result, &error); + if (handle == 0) + { + dbus_g_method_return_error (context, error); + g_clear_error (&error); + 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_array_unref (handles); +} /** * tp_base_connection_dbus_request_handles: (skip) @@ -2561,6 +2587,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_handle_ensure_async (handle_repo, self, names[0], NULL, + ensure_handle_cb, context); + return; + } + handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), count); for (i = 0; i < count; i++) diff --git a/telepathy-glib/contacts-mixin.c b/telepathy-glib/contacts-mixin.c index 90cadc6..d7c6b7c 100644 --- a/telepathy-glib/contacts-mixin.c +++ b/telepathy-glib/contacts-mixin.c @@ -379,46 +379,77 @@ tp_contacts_mixin_get_contact_attributes_impl ( g_hash_table_unref (result); } +typedef struct +{ + TpBaseConnection *conn; + 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) +ensure_handle_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) { - TpBaseConnection *conn = TP_BASE_CONNECTION (iface); - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, - TP_HANDLE_TYPE_CONTACT); + TpHandleRepoIface *contact_repo = (TpHandleRepoIface *) source; + GetContactByIdData *data = user_data; TpHandle handle; GArray *handles; GHashTable *attributes; - GHashTable *result; + GHashTable *ret; GError *error = NULL; - TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (conn, context); - - handle = tp_handle_ensure (contact_repo, id, NULL, &error); + handle = tp_handle_ensure_finish (contact_repo, result, &error); if (handle == 0) { - dbus_g_method_return_error (context, error); + dbus_g_method_return_error (data->context, error); g_clear_error (&error); - return; + goto out; } handles = g_array_new (FALSE, FALSE, sizeof (TpHandle)); g_array_append_val (handles, handle); - attributes = tp_contacts_mixin_get_contact_attributes (G_OBJECT (conn), - handles, interfaces, always_included_interfaces, NULL); + attributes = tp_contacts_mixin_get_contact_attributes (G_OBJECT (data->conn), + handles, (const gchar **) data->interfaces, always_included_interfaces, + NULL); - result = g_hash_table_lookup (attributes, GUINT_TO_POINTER (handle)); - g_assert (result != NULL); + ret = g_hash_table_lookup (attributes, GUINT_TO_POINTER (handle)); + g_assert (ret != 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, ret); g_array_unref (handles); g_hash_table_unref (attributes); + +out: + g_object_unref (data->conn); + g_strfreev (data->interfaces); + g_slice_free (GetContactByIdData, data); +} + +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); + TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, + TP_HANDLE_TYPE_CONTACT); + GetContactByIdData *data; + + TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (conn, context); + + data = g_slice_new0 (GetContactByIdData); + data->conn = g_object_ref (conn); + data->interfaces = g_strdupv ((gchar **) interfaces); + data->context = context; + + tp_handle_ensure_async (contact_repo, conn, id, NULL, + ensure_handle_cb, data); } /** diff --git a/telepathy-glib/handle-repo-internal.h b/telepathy-glib/handle-repo-internal.h index 722f59c..5a0268a 100644 --- a/telepathy-glib/handle-repo-internal.h +++ b/telepathy-glib/handle-repo-internal.h @@ -29,6 +29,9 @@ G_BEGIN_DECLS +/* G_DEFINE_INTERFACE wants that name */ +typedef struct _TpHandleRepoIfaceClass TpHandleRepoIfaceInterface; + /* <-- this is no longer a gtkdoc comment because this is not public API * TpHandleRepoIfaceClass: * @parent_class: Fields shared with GTypeInterface @@ -71,6 +74,9 @@ struct _TpHandleRepoIfaceClass { TpHandle (*lookup_handle) (TpHandleRepoIface *self, const char *id, gpointer context, GError **error); + TpHandleRepoIfaceEnsureHandleFunc ensure_handle_async; + TpHandleRepoIfaceEnsureHandleFinishFunc ensure_handle_finish; + void (*set_qdata) (TpHandleRepoIface *repo, TpHandle handle, GQuark key_id, gpointer data, GDestroyNotify destroy); gpointer (*get_qdata) (TpHandleRepoIface *repo, TpHandle handle, diff --git a/telepathy-glib/handle-repo.c b/telepathy-glib/handle-repo.c index 5fc49bd..753a532 100644 --- a/telepathy-glib/handle-repo.c +++ b/telepathy-glib/handle-repo.c @@ -37,51 +37,9 @@ #include #include +#include -static void -repo_base_init (gpointer klass) -{ - static gboolean initialized = FALSE; - - if (!initialized) - { - GParamSpec *param_spec; - - initialized = TRUE; - - param_spec = g_param_spec_uint ("handle-type", "Handle type", - "The TpHandleType held in this handle repository.", - 0, G_MAXUINT32, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_interface_install_property (klass, param_spec); - } -} - -GType -tp_handle_repo_iface_get_type (void) -{ - static GType type = 0; - if (G_UNLIKELY (type == 0)) - { - static const GTypeInfo info = { - sizeof (TpHandleRepoIfaceClass), - repo_base_init, - NULL, /* base_finalize */ - NULL, /* class_init */ - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL /* instance_init */ - }; - - type = g_type_register_static (G_TYPE_INTERFACE, "TpHandleRepoIface", - &info, 0); - } - - return type; -} - +G_DEFINE_INTERFACE (TpHandleRepoIface, tp_handle_repo_iface, G_TYPE_OBJECT); /** * tp_handle_is_valid: (skip) @@ -345,6 +303,109 @@ tp_handle_ensure (TpHandleRepoIface *self, id, context, error); } +/** + * tp_handle_ensure_async: (skip) + * @self: A handle repository implementation + * @connection: the #TpBaseConnection using this handle repo + * @id: A string whose handle is required + * @context: User data to be passed to the normalization callback + * @callback: a callback to call when the operation finishes + * @user_data: data to pass to @callback + * + * Asyncronously normalize an identifier and create an handle for it. This could + * involve server round-trip. This is to be prefered over tp_handle_ensure() for + * user provided contact identifiers, but not necessary for identifiers coming + * from server. + * + * Since: 0.UNRELEASED + */ +void +tp_handle_ensure_async (TpHandleRepoIface *self, + TpBaseConnection *connection, + const gchar *id, + gpointer context, + GAsyncReadyCallback callback, + gpointer user_data) +{ + return TP_HANDLE_REPO_IFACE_GET_CLASS (self)->ensure_handle_async (self, + connection, id, context, callback, user_data); +} + +/** + * tp_handle_ensure_finish: (skip) + * @self: A handle repository implementation + * @result: a #GAsyncResult + * @error: a #GError to fill + * + * Finishes tp_handle_ensure_async() + * + * Returns: non-0 #TpHandle if the operation was successful, otherwise 0. + * + * Since: 0.UNRELEASED + */ +TpHandle +tp_handle_ensure_finish (TpHandleRepoIface *self, + GAsyncResult *result, + GError **error) +{ + return TP_HANDLE_REPO_IFACE_GET_CLASS (self)->ensure_handle_finish (self, + result, error); +} + +/** + * TpHandleRepoIfaceEnsureHandleFunc: (skip) + * @self: A handle repository implementation + * @connection: the #TpBaseConnection using this handle repo + * @id: A string whose handle is required + * @context: User data to be passed to the normalization callback + * @callback: a callback to call when the operation finishes + * @user_data: data to pass to @callback + * + * Signature of a tp_handle_ensure_async() implementation. See + * tp_handle_repo_implement_ensure_handle_async(). + * + * Since: 0.UNRELEASED + */ + +/** + * TpHandleRepoIfaceEnsureHandleFinishFunc: (skip) + * @self: A handle repository implementation + * @result: a #GAsyncResult + * @error: a #GError to fill + * + * Signature of a tp_handle_ensure_finish() implementation. See + * tp_handle_repo_implement_ensure_handle_async(). + * + * Since: 0.UNRELEASED + */ + +/** + * tp_handle_repo_iface_implement_ensure_handle_async: (skip) + * @self: A handle repository implementation + * @ensure_handle_async: an implementation for tp_handle_ensure_async() + * @ensure_handle_finish: an implementation for tp_handle_ensure_finish(), or + * %NULL to use default implementation + * + * Give a custom implementation for tp_handle_ensure_async() and + * tp_handle_ensure_finish(). This is to be used if handle normalization require + * server round-trip. + * + * Since: 0.UNRELEASED + */ +void +tp_handle_repo_iface_implement_ensure_handle_async (TpHandleRepoIface *self, + TpHandleRepoIfaceEnsureHandleFunc ensure_handle_async, + TpHandleRepoIfaceEnsureHandleFinishFunc ensure_handle_finish) +{ + TpHandleRepoIfaceClass *klass = TP_HANDLE_REPO_IFACE_GET_CLASS (self); + + g_return_if_fail (ensure_handle_async != NULL); + + klass->ensure_handle_async = ensure_handle_async; + + if (ensure_handle_finish != NULL) + klass->ensure_handle_finish = ensure_handle_finish; +} /** * tp_handle_lookup: (skip) @@ -419,3 +480,65 @@ tp_handle_get_qdata (TpHandleRepoIface *repo, TpHandle handle, return TP_HANDLE_REPO_IFACE_GET_CLASS (repo)->get_qdata (repo, handle, key_id); } + +static void +default_ensure_handle_async (TpHandleRepoIface *self, + TpBaseConnection *connection, + const gchar *id, + gpointer context, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *result; + TpHandle handle; + GError *error = NULL; + + result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + default_ensure_handle_async); + + handle = tp_handle_ensure (self, id, context, &error); + if (handle == 0) + { + g_simple_async_result_take_error (result, error); + } + else + { + g_simple_async_result_set_op_res_gpointer (result, + GUINT_TO_POINTER (handle), NULL); + } + + g_simple_async_result_complete_in_idle (result); + + g_object_unref (result); +} + +static TpHandle +default_ensure_handle_finish (TpHandleRepoIface *self, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple = (GSimpleAsyncResult *) result; + + g_return_val_if_fail (g_simple_async_result_is_valid (result, + G_OBJECT (self), NULL), 0); + + if (g_simple_async_result_propagate_error (simple, error)) + return 0; + + return GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (simple)); +} + +static void +tp_handle_repo_iface_default_init (TpHandleRepoIfaceInterface *iface) +{ + GParamSpec *param_spec; + + iface->ensure_handle_async = default_ensure_handle_async; + iface->ensure_handle_finish = default_ensure_handle_finish; + + param_spec = g_param_spec_uint ("handle-type", "Handle type", + "The TpHandleType held in this handle repository.", + 0, G_MAXUINT32, 0, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, param_spec); +} diff --git a/telepathy-glib/handle-repo.h b/telepathy-glib/handle-repo.h index cfe58e4..85c45a6 100644 --- a/telepathy-glib/handle-repo.h +++ b/telepathy-glib/handle-repo.h @@ -26,11 +26,16 @@ #include +#include + #include #include G_BEGIN_DECLS +/* Forward declaration to avoid circular includes */ +typedef struct _TpBaseConnection TpBaseConnection; + /* Forward declaration because it's in the HandleRepo API */ #define TP_TYPE_HANDLE_SET (tp_handle_set_get_type ()) @@ -111,6 +116,34 @@ TpHandle tp_handle_ensure (TpHandleRepoIface *self, const gchar *id, gpointer context, GError **error) G_GNUC_WARN_UNUSED_RESULT; +_TP_AVAILABLE_IN_UNRELEASED +void tp_handle_ensure_async (TpHandleRepoIface *self, + TpBaseConnection *connection, + const gchar *id, + gpointer context, + GAsyncReadyCallback callback, + gpointer user_data); +_TP_AVAILABLE_IN_UNRELEASED +TpHandle tp_handle_ensure_finish (TpHandleRepoIface *self, + GAsyncResult *result, + GError **error); + +typedef void (*TpHandleRepoIfaceEnsureHandleFunc) (TpHandleRepoIface *self, + TpBaseConnection *connection, + const gchar *id, + gpointer context, + GAsyncReadyCallback callback, + gpointer user_data); +typedef TpHandle (*TpHandleRepoIfaceEnsureHandleFinishFunc) (TpHandleRepoIface *self, + GAsyncResult *result, + GError **error); + +_TP_AVAILABLE_IN_UNRELEASED +void tp_handle_repo_iface_implement_ensure_handle_async ( + TpHandleRepoIface *self, + TpHandleRepoIfaceEnsureHandleFunc ensure_handle_async, + TpHandleRepoIfaceEnsureHandleFinishFunc ensure_handle_finish); + void tp_handle_set_qdata (TpHandleRepoIface *repo, TpHandle handle, GQuark key_id, gpointer data, GDestroyNotify destroy); gpointer tp_handle_get_qdata (TpHandleRepoIface *repo, TpHandle handle, -- 1.7.9.5