From 02112b8bf94f16ae7a3b488cb07aaf4496bec55f Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 5 Jul 2011 11:05:00 +0200 Subject: [PATCH] TpAccountChannelRequest: add org.freedesktop.Telepathy.ChannelRequest.DelegateToPreferredHandler support (#38249) --- docs/reference/Makefile.am | 1 + docs/reference/telepathy-glib-sections.txt | 2 + telepathy-glib/Makefile.am | 1 + telepathy-glib/account-channel-request-internal.h | 29 ++++ telepathy-glib/account-channel-request.c | 105 ++++++++++++++ telepathy-glib/account-channel-request.h | 11 ++ tests/dbus/Makefile.am | 5 + tests/dbus/account-channel-request.c | 156 +++++++++++++++++++++ 8 files changed, 310 insertions(+), 0 deletions(-) create mode 100644 telepathy-glib/account-channel-request-internal.h diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am index 9124c65..931c7f6 100644 --- a/docs/reference/Makefile.am +++ b/docs/reference/Makefile.am @@ -64,6 +64,7 @@ CFILE_GLOB=$(top_srcdir)/telepathy-glib/*.c $(top_builddir)/telepathy-glib/_gen/ # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h IGNORE_HFILES=\ add-dispatch-operation-context-internal.h \ + account-channel-request-internal.h \ base-connection-internal.h \ base-contact-list-internal.h \ channel-dispatch-operation-internal.h \ diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt index 67af5a2..4e860e6 100644 --- a/docs/reference/telepathy-glib-sections.txt +++ b/docs/reference/telepathy-glib-sections.txt @@ -5208,6 +5208,8 @@ tp_account_channel_request_set_channel_factory tp_account_channel_request_get_channel_request tp_account_channel_request_set_hints tp_account_channel_request_set_delegate_to_preferred_handler +TpAccountChannelRequestDelegatedChannelCb +tp_account_channel_request_set_delegated_channel_callback tp_account_channel_request_get_type TP_ACCOUNT_CHANNEL_REQUEST diff --git a/telepathy-glib/Makefile.am b/telepathy-glib/Makefile.am index 54a42b8..f2455ef 100644 --- a/telepathy-glib/Makefile.am +++ b/telepathy-glib/Makefile.am @@ -139,6 +139,7 @@ libtelepathy_glib_internal_la_LIBADD = $(ALL_LIBS) libtelepathy_glib_internal_la_SOURCES = \ account.c \ account-channel-request.c \ + account-channel-request-internal.h \ account-internal.h \ account-manager.c \ account-manager-internal.h \ diff --git a/telepathy-glib/account-channel-request-internal.h b/telepathy-glib/account-channel-request-internal.h new file mode 100644 index 0000000..03f7033 --- /dev/null +++ b/telepathy-glib/account-channel-request-internal.h @@ -0,0 +1,29 @@ +/* + * object used to request a channel from a TpAccount (internal) + * + * Copyright © 2010-2011 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __TP_ACCOUNT_CHANNEL_REQUEST_INTERNAL_H__ +#define __TP_ACCOUNT_CHANNEL_REQUEST_INTERNAL_H__ + +#include + +TpBaseClient * _tp_account_channel_request_get_client ( + TpAccountChannelRequest *self); + +#endif diff --git a/telepathy-glib/account-channel-request.c b/telepathy-glib/account-channel-request.c index 0033525..51e5301 100644 --- a/telepathy-glib/account-channel-request.c +++ b/telepathy-glib/account-channel-request.c @@ -55,7 +55,21 @@ * Since: 0.11.12 */ +/** + * TpAccountChannelRequestDelegatedChannelCb: + * @request: a #TpAccountChannelRequest instance + * @channel: a #TpChannel + * @user_data: arbitrary user-supplied data passed to + * tp_account_channel_request_set_delegated_channel_callback() + * + * Called when a client asked us to delegate @channel to another Handler. + * When this function is called you are no longer handling @channel. + * + * Since: 0.15.UNRELEASED + */ + #include "telepathy-glib/account-channel-request.h" +#include "telepathy-glib/account-channel-request-internal.h" #include #include "telepathy-glib/base-client-internal.h" @@ -132,6 +146,10 @@ struct _TpAccountChannelRequestPrivate gboolean requested; ActionType action_type; + + TpAccountChannelRequestDelegatedChannelCb delegated_channel_cb; + gpointer delegated_channel_data; + GDestroyNotify delegated_channel_destroy; }; static void @@ -187,6 +205,13 @@ tp_account_channel_request_dispose (GObject *object) tp_clear_object (&self->priv->factory); tp_clear_pointer (&self->priv->hints, g_hash_table_unref); + if (self->priv->delegated_channel_destroy != NULL) + { + self->priv->delegated_channel_destroy ( + self->priv->delegated_channel_data); + self->priv->delegated_channel_destroy = NULL; + } + if (dispose != NULL) dispose (object); } @@ -811,6 +836,27 @@ fail: } static void +delegated_channels_cb (TpBaseClient *client, + GPtrArray *channels, + gpointer user_data) +{ + TpAccountChannelRequest *self = user_data; + TpChannel *channel; + + g_return_if_fail (channels->len == 1); + + /* TpBaseClient is supposed to check we are actually handling the channel + * before calling this callback so we can assert that's the right one. */ + channel = g_ptr_array_index (channels, 0); + g_return_if_fail (TP_IS_CHANNEL (channel)); + g_return_if_fail (!tp_strdiff (tp_proxy_get_object_path (channel), + tp_proxy_get_object_path (self->priv->channel))); + + self->priv->delegated_channel_cb (self, channel, + self->priv->delegated_channel_data); +} + +static void request_and_handle_channel_async (TpAccountChannelRequest *self, GCancellable *cancellable, GAsyncReadyCallback callback, @@ -847,6 +893,12 @@ request_and_handle_channel_async (TpAccountChannelRequest *self, tp_base_client_set_channel_factory (self->priv->handler, self->priv->factory); + if (self->priv->delegated_channel_cb != NULL) + { + tp_base_client_set_delegated_channels_callback (self->priv->handler, + delegated_channels_cb, self, NULL); + } + if (!tp_base_client_register (self->priv->handler, &error)) { DEBUG ("Failed to register temp handler: %s", error->message); @@ -1602,3 +1654,56 @@ tp_account_channel_request_set_delegate_to_preferred_handler ( "org.freedesktop.Telepathy.ChannelRequest.DelegateToPreferredHandler", delegate); } + +/** + * tp_account_channel_request_set_delegated_channel_callback: + * @self: a #TpAccountChannelRequest + * @callback: function called the channel requested using @self is + * delegated, may not be %NULL + * @user_data: arbitrary user-supplied data passed to @callback + * @destroy: called with the @user_data as argument, when @self is destroyed + * + * Turn on support for + * the org.freedesktop.Telepathy.ChannelRequest.DelegateToPreferredHandler + * hint. + * + * When receiving a request containing this hint, @self will automatically + * delegate the channel to the preferred handler of the request and then call + * @callback to inform the client that it is no longer handling this channel. + * + * Note that the channel can only be delegated and so @callback be called + * after + * tp_account_channel_request_create_and_handle_channel_async () or + * tp_account_channel_request_ensure_and_observe_channel_async() has been + * called on @self. + * + * This function can't be called once @self has been used to request a + * channel. + * + * Since: 0.15.UNRELEASED + * @see_also: tp_base_client_set_delegated_channels_callback () + */ +void +tp_account_channel_request_set_delegated_channel_callback ( + TpAccountChannelRequest *self, + TpAccountChannelRequestDelegatedChannelCb callback, + gpointer user_data, + GDestroyNotify destroy) +{ + g_return_if_fail (TP_IS_ACCOUNT_CHANNEL_REQUEST (self)); + g_return_if_fail (!self->priv->requested); + + g_return_if_fail (self->priv->delegated_channel_cb == NULL); + + self->priv->delegated_channel_cb = callback; + self->priv->delegated_channel_data = user_data; + self->priv->delegated_channel_destroy = destroy; +} + +TpBaseClient * +_tp_account_channel_request_get_client (TpAccountChannelRequest *self) +{ + g_return_val_if_fail (TP_IS_ACCOUNT_CHANNEL_REQUEST (self), NULL); + + return self->priv->handler; +} diff --git a/telepathy-glib/account-channel-request.h b/telepathy-glib/account-channel-request.h index 07b3238..f3f6455 100644 --- a/telepathy-glib/account-channel-request.h +++ b/telepathy-glib/account-channel-request.h @@ -112,6 +112,17 @@ TpChannel * tp_account_channel_request_ensure_and_handle_channel_finish ( TpHandleChannelsContext **context, GError **error) G_GNUC_WARN_UNUSED_RESULT; +typedef void (*TpAccountChannelRequestDelegatedChannelCb) ( + TpAccountChannelRequest *request, + TpChannel *channel, + gpointer user_data); + +void tp_account_channel_request_set_delegated_channel_callback ( + TpAccountChannelRequest *self, + TpAccountChannelRequestDelegatedChannelCb callback, + gpointer user_data, + GDestroyNotify destroy); + /* Request and forget API */ void tp_account_channel_request_create_channel_async ( diff --git a/tests/dbus/Makefile.am b/tests/dbus/Makefile.am index 670a0b0..c5db796 100644 --- a/tests/dbus/Makefile.am +++ b/tests/dbus/Makefile.am @@ -67,7 +67,12 @@ LDADD = \ test_account_SOURCES = account.c +# this one uses internal ABI test_account_channel_request_SOURCES = account-channel-request.c +test_account_channel_request_LDADD = \ + $(top_builddir)/tests/lib/libtp-glib-tests.la \ + $(top_builddir)/telepathy-glib/libtelepathy-glib-internal.la \ + $(GLIB_LIBS) test_account_manager_SOURCES = account-manager.c diff --git a/tests/dbus/account-channel-request.c b/tests/dbus/account-channel-request.c index 7d673d9..e88afb4 100644 --- a/tests/dbus/account-channel-request.c +++ b/tests/dbus/account-channel-request.c @@ -9,6 +9,10 @@ #include +#include +#include +#include + #include "tests/lib/util.h" #include "tests/lib/simple-account.h" #include "tests/lib/simple-conn.h" @@ -531,6 +535,156 @@ test_handle_create_success_hints (Test *test, g_assert_no_error (test->error); } +static void +channel_delegated_cb (TpAccountChannelRequest *req, + TpChannel *channel, + gpointer user_data) +{ + Test *test = user_data; + + g_assert (TP_IS_ACCOUNT_CHANNEL_REQUEST (req)); + + g_assert (TP_IS_CHANNEL (channel)); + g_assert_cmpstr (tp_proxy_get_object_path (channel), ==, + tp_proxy_get_object_path (test->channel)); + + test->count--; + if (test->count <= 0) + g_main_loop_quit (test->mainloop); +} + +static void +add_channel_to_ptr_array (GPtrArray *arr, + TpChannel *channel) +{ + GValueArray *tmp; + + g_assert (arr != NULL); + g_assert (channel != NULL); + + tmp = tp_value_array_build (2, + DBUS_TYPE_G_OBJECT_PATH, tp_proxy_get_object_path (channel), + TP_HASH_TYPE_STRING_VARIANT_MAP, tp_channel_borrow_immutable_properties ( + channel), + G_TYPE_INVALID); + + g_ptr_array_add (arr, tmp); +} + +static void +no_return_cb (TpClient *proxy, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + Test *test = user_data; + + g_clear_error (&test->error); + + if (error != NULL) + { + test->error = g_error_copy (error); + goto out; + } + +out: + test->count--; + if (test->count == 0) + g_main_loop_quit (test->mainloop); +} + +#define PREFERRED_HANDLER_NAME TP_CLIENT_BUS_NAME_BASE ".Badger" + +static void +test_handle_delegated (Test *test, + gconstpointer data G_GNUC_UNUSED) +{ + GHashTable *request; + TpAccountChannelRequest *req; + GPtrArray *requests, *requests_satisified, *channels; + GHashTable *hints, *request_props, *info; + TpTestsSimpleChannelRequest *cr; + TpBaseClient *base_client; + TpClient *client; + + request = create_request (); + req = tp_account_channel_request_new (test->account, request, 0); + + /* Allow other clients to preempt the channel */ + tp_account_channel_request_set_delegated_channel_callback (req, + channel_delegated_cb, test, NULL); + + tp_account_channel_request_create_and_handle_channel_async (req, + NULL, create_and_handle_cb, test); + + g_hash_table_unref (request); + g_object_unref (req); + + g_main_loop_run (test->mainloop); + g_assert_no_error (test->error); + + /* Another client asks to dispatch the channel to it */ + requests = g_ptr_array_new (); + + hints = tp_asv_new ( + "org.freedesktop.Telepathy.ChannelRequest.DelegateToPreferredHandler", + G_TYPE_BOOLEAN, TRUE, + NULL); + + cr = tp_tests_simple_channel_request_new ("/CR", + TP_TESTS_SIMPLE_CONNECTION (test->base_connection), + tp_proxy_get_object_path (test->account), + TP_USER_ACTION_TIME_CURRENT_TIME, PREFERRED_HANDLER_NAME, + requests, hints); + + requests_satisified = g_ptr_array_sized_new (1); + g_ptr_array_add (requests_satisified, "/CR"); + + request_props = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, (GDestroyNotify) g_hash_table_unref); + + g_hash_table_insert (request_props, "/CR", + tp_tests_simple_channel_request_dup_immutable_props (cr)); + + info = tp_asv_new ( + "request-properties", TP_HASH_TYPE_OBJECT_IMMUTABLE_PROPERTIES_MAP, + request_props, NULL); + + channels = g_ptr_array_sized_new (1); + add_channel_to_ptr_array (channels, test->channel); + + base_client = _tp_account_channel_request_get_client (req); + g_assert (TP_IS_BASE_CLIENT (base_client)); + + client = tp_tests_object_new_static_class (TP_TYPE_CLIENT, + "dbus-daemon", tp_base_client_get_dbus_daemon (base_client), + "bus-name", tp_base_client_get_bus_name (base_client), + "object-path", tp_base_client_get_object_path (base_client), + NULL); + + tp_proxy_add_interface_by_id (TP_PROXY (client), + TP_IFACE_QUARK_CLIENT_HANDLER); + + tp_cli_client_handler_call_handle_channels (client, -1, + tp_proxy_get_object_path (test->account), + tp_proxy_get_object_path (test->connection), + channels, requests_satisified, 0, info, + no_return_cb, test, NULL, NULL); + + test->count = 2; + g_main_loop_run (test->mainloop); + g_assert_no_error (test->error); + + g_ptr_array_unref (requests); + g_hash_table_unref (hints); + g_object_unref (cr); + g_ptr_array_unref (requests_satisified); + g_ptr_array_unref (channels); + g_hash_table_unref (request_props); + g_hash_table_unref (info); + g_object_unref (client); +} + /* Request and forget tests */ static void @@ -977,6 +1131,8 @@ main (int argc, setup, test_handle_re_handle, teardown); g_test_add ("/account-channels/request-handle/create-success-hints", Test, NULL, setup, test_handle_create_success_hints, teardown); + g_test_add ("/account-channels/request-handle/delegated", Test, NULL, + setup, test_handle_delegated, teardown); /* Request and forget tests */ g_test_add ("/account-channels/request-forget/create-success", Test, NULL, -- 1.7.4.1