From 1cd3eb53b6f02c21cc695860615eae6d512e7d30 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Mon, 7 May 2012 17:49:45 +0200 Subject: [PATCH] tp_channel_join/leave_async: require TP_CHANNEL_FEATURE_CONTACTS to work properly That feature is needed to ensure we have a self contact. https://bugs.freedesktop.org/show_bug.cgi?id=49371 --- telepathy-glib/channel.c | 125 +++++++++------------------------------------- telepathy-glib/channel.h | 22 ++++---- tests/dbus/channel.c | 40 ++++++--------- 3 files changed, 48 insertions(+), 139 deletions(-) diff --git a/telepathy-glib/channel.c b/telepathy-glib/channel.c index 43c16a9..de6af55 100644 --- a/telepathy-glib/channel.c +++ b/telepathy-glib/channel.c @@ -1870,10 +1870,10 @@ channel_join_cb (TpChannel *self, * You can then call tp_channel_join_finish() to get the result of * the operation. * - * Note that unlike tp_channel_leave_async(), %TP_CHANNEL_FEATURE_GROUP feature - * must be prepared before calling this function. + * %TP_CHANNEL_FEATURE_CONTACTS feature must be prepared before calling this + * function. * - * Since: 0.15.5 + * Since: 0.UNRELEASED */ void tp_channel_join_async (TpChannel *self, @@ -1882,16 +1882,18 @@ tp_channel_join_async (TpChannel *self, gpointer user_data) { GSimpleAsyncResult *result; + TpHandle self_handle; GArray *array; g_return_if_fail (TP_IS_CHANNEL (self)); - g_return_if_fail (tp_proxy_is_prepared (self, TP_CHANNEL_FEATURE_GROUP)); + g_return_if_fail (tp_proxy_is_prepared (self, TP_CHANNEL_FEATURE_CONTACTS)); result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, tp_channel_join_async); array = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), 1); - g_array_append_val (array, self->priv->group_self_handle); + self_handle = tp_contact_get_handle (self->priv->group_self_contact); + g_array_append_val (array, self_handle); tp_cli_channel_interface_group_call_add_members (self, -1, array, message, channel_join_cb, result, g_object_unref, NULL); @@ -1947,9 +1949,6 @@ channel_close_cb (TpChannel *channel, g_object_unref (result); } -/* This is only called from the main loop, as a result of group_prepared_cb - * having the same property, so it can complete LeaveCtx.result without - * an idle. */ static void channel_remove_self_cb (TpChannel *channel, const GError *error, @@ -1958,7 +1957,7 @@ channel_remove_self_cb (TpChannel *channel, { GSimpleAsyncResult *result = user_data; - if (tp_proxy_get_invalidated (channel) != NULL && + if (tp_proxy_get_invalidated (channel) == NULL && error != NULL) { DEBUG ("RemoveMembersWithDetails() with self handle failed; call Close()" @@ -1973,82 +1972,6 @@ channel_remove_self_cb (TpChannel *channel, g_object_unref (result); } -typedef struct -{ - GSimpleAsyncResult *result; - gchar *message; - TpChannelGroupChangeReason reason; -} LeaveCtx; - -/* Takes the reference on @result */ -static LeaveCtx * -leave_ctx_new (GSimpleAsyncResult *result, - const gchar *message, - TpChannelGroupChangeReason reason) -{ - LeaveCtx *ctx = g_slice_new (LeaveCtx); - - ctx->result = result; - ctx->message = message != NULL ? g_strdup (message) : g_strdup (""); - ctx->reason = reason; - - return ctx; -} - -static void -leave_ctx_free (LeaveCtx *ctx) -{ - g_object_unref (ctx->result); - g_free (ctx->message); - - g_slice_free (LeaveCtx, ctx); -} - -/* This is only called from the main loop, so it can safely complete - * LeaveCtx.result without an idle. */ -static void -group_prepared_cb (GObject *source, - GAsyncResult *res, - gpointer user_data) -{ - LeaveCtx *ctx = user_data; - TpChannel *self = (TpChannel *) source; - GError *error = NULL; - GArray *handles; - - if (!tp_proxy_prepare_finish (source, res, &error)) - { - DEBUG ("Failed to prepare Group feature; fallback to Close(): %s", - error->message); - - g_error_free (error); - goto call_close; - } - - if (self->priv->group_self_handle == 0) - { - DEBUG ("We are not in the channel, fallback to Close()"); - goto call_close; - } - - handles = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), 1); - g_array_append_val (handles, self->priv->group_self_handle); - - tp_cli_channel_interface_group_call_remove_members ( - self, -1, handles, ctx->message, ctx->reason, - channel_remove_self_cb, g_object_ref (ctx->result), NULL, NULL); - - g_array_unref (handles); - leave_ctx_free (ctx); - return; - -call_close: - tp_cli_channel_call_close (self, -1, channel_close_cb, - g_object_ref (ctx->result), NULL, NULL); - - leave_ctx_free (ctx); -} - /** * tp_channel_leave_async: * @self: a #TpChannel @@ -2058,18 +1981,13 @@ call_close: * @user_data: data to pass to @callback * * Leave channel @self with @reason as reason and @message as leave message. - * If @self doesn't implement #TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP or if - * for any reason we can't properly leave the channel, we close it. + * If %TP_CHANNEL_FEATURE_CONTACTS feature is not prepared, we close it. * * When we left the channel, @callback will be called. * You can then call tp_channel_leave_finish() to get the result of * the operation. * - * Note that unlike tp_channel_join_async(), %TP_CHANNEL_FEATURE_GROUP feature - * does not have to be prepared and will be prepared for you. But this is a - * deprecated behaviour. - * - * Since: 0.13.10 + * Since: 0.UNRELEASED */ void tp_channel_leave_async (TpChannel *self, @@ -2079,30 +1997,33 @@ tp_channel_leave_async (TpChannel *self, gpointer user_data) { GSimpleAsyncResult *result; - GQuark features[] = { TP_CHANNEL_FEATURE_GROUP, 0 }; - LeaveCtx *ctx; + TpHandle self_handle; + GArray *handles; g_return_if_fail (TP_IS_CHANNEL (self)); result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, tp_channel_leave_async); - if (tp_proxy_is_prepared (self, TP_CHANNEL_FEATURE_CORE) && - !tp_proxy_has_interface_by_id (self, - TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP)) + if (!tp_proxy_is_prepared (self, TP_CHANNEL_FEATURE_CONTACTS)) { - DEBUG ("Channel doesn't implement Group; fallback to Close()"); + DEBUG ("TP_CHANNEL_FEATURE_CONTACTS is not prepared; " + "fallback to Close()"); tp_cli_channel_call_close (self, -1, channel_close_cb, result, NULL, NULL); return; } - /* We need to prepare TP_CHANNEL_FEATURE_GROUP to get - * tp_channel_group_get_self_handle() working */ - ctx = leave_ctx_new (result, message, reason); + handles = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), 1); + self_handle = tp_contact_get_handle (self->priv->group_self_contact); + g_array_append_val (handles, self_handle); + + tp_cli_channel_interface_group_call_remove_members ( + self, -1, handles, message, reason, + channel_remove_self_cb, result, NULL, NULL); - tp_proxy_prepare_async (self, features, group_prepared_cb, ctx); + g_array_unref (handles); } /** diff --git a/telepathy-glib/channel.h b/telepathy-glib/channel.h index 32a849d..b27727e 100644 --- a/telepathy-glib/channel.h +++ b/telepathy-glib/channel.h @@ -158,17 +158,6 @@ _TP_DEPRECATED_IN_0_20_FOR (tp_channel_group_get_contact_owner) TpHandle tp_channel_group_get_handle_owner (TpChannel *self, TpHandle handle); #endif -_TP_AVAILABLE_IN_0_16 -void tp_channel_join_async (TpChannel *self, - const gchar *message, - GAsyncReadyCallback callback, - gpointer user_data); - -_TP_AVAILABLE_IN_0_16 -gboolean tp_channel_join_finish (TpChannel *self, - GAsyncResult *result, - GError **error); - #define TP_CHANNEL_FEATURE_CONTACTS \ tp_channel_get_feature_quark_contacts () _TP_AVAILABLE_IN_0_16 @@ -192,6 +181,17 @@ _TP_AVAILABLE_IN_0_16 TpContact *tp_channel_group_get_contact_owner (TpChannel *self, TpContact *contact); +_TP_AVAILABLE_IN_0_16 +void tp_channel_join_async (TpChannel *self, + const gchar *message, + GAsyncReadyCallback callback, + gpointer user_data); + +_TP_AVAILABLE_IN_0_16 +gboolean tp_channel_join_finish (TpChannel *self, + GAsyncResult *result, + GError **error); + #define TP_CHANNEL_FEATURE_CHAT_STATES \ tp_channel_get_feature_quark_chat_states () GQuark tp_channel_get_feature_quark_chat_states (void) G_GNUC_CONST; diff --git a/tests/dbus/channel.c b/tests/dbus/channel.c index 6137e40..34e80d7 100644 --- a/tests/dbus/channel.c +++ b/tests/dbus/channel.c @@ -226,10 +226,7 @@ test_leave_contact_prepared_no_reason (Test *test, g_assert (tp_proxy_get_invalidated (test->channel_contact) == NULL); - tp_proxy_prepare_async (test->channel_contact, features, - channel_prepared_cb, test); - g_main_loop_run (test->mainloop); - g_assert_no_error (test->error); + tp_tests_proxy_run_until_prepared (test->channel_contact, features); tp_channel_leave_async (test->channel_contact, TP_CHANNEL_GROUP_CHANGE_REASON_NONE, @@ -249,10 +246,7 @@ test_leave_contact_prepared_reason (Test *test, g_assert (tp_proxy_get_invalidated (test->channel_contact) == NULL); - tp_proxy_prepare_async (test->channel_contact, features, - channel_prepared_cb, test); - g_main_loop_run (test->mainloop); - g_assert_no_error (test->error); + tp_tests_proxy_run_until_prepared (test->channel_contact, features); tp_channel_leave_async (test->channel_contact, TP_CHANNEL_GROUP_CHANGE_REASON_BUSY, @@ -296,8 +290,8 @@ test_leave_room_unprepared_no_reason (Test *test, g_assert_no_error (test->error); g_assert (tp_proxy_get_invalidated (test->channel_room) != NULL); - g_assert_cmpuint (test->chan_room_service->removed_handle, !=, 0); - g_assert_cmpstr (test->chan_room_service->removed_message, ==, ""); + g_assert_cmpuint (test->chan_room_service->removed_handle, ==, 0); + g_assert_cmpstr (test->chan_room_service->removed_message, ==, NULL); g_assert_cmpuint (test->chan_room_service->removed_reason, ==, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); } @@ -316,21 +310,21 @@ test_leave_room_unprepared_reason (Test *test, g_assert_no_error (test->error); g_assert (tp_proxy_get_invalidated (test->channel_room) != NULL); - check_removed (test->chan_room_service); + g_assert_cmpuint (test->chan_room_service->removed_handle, ==, 0); + g_assert_cmpstr (test->chan_room_service->removed_message, ==, NULL); + g_assert_cmpuint (test->chan_room_service->removed_reason, ==, + TP_CHANNEL_GROUP_CHANGE_REASON_NONE); } static void test_leave_room_prepared_no_reason (Test *test, gconstpointer data G_GNUC_UNUSED) { - GQuark features[] = { TP_CHANNEL_FEATURE_CORE, 0 }; + GQuark features[] = { TP_CHANNEL_FEATURE_CONTACTS, 0 }; g_assert (tp_proxy_get_invalidated (test->channel_room) == NULL); - tp_proxy_prepare_async (test->channel_room, features, - channel_prepared_cb, test); - g_main_loop_run (test->mainloop); - g_assert_no_error (test->error); + tp_tests_proxy_run_until_prepared (test->channel_room, features); tp_channel_leave_async (test->channel_room, TP_CHANNEL_GROUP_CHANGE_REASON_NONE, @@ -350,14 +344,11 @@ static void test_leave_room_prepared_reason (Test *test, gconstpointer data G_GNUC_UNUSED) { - GQuark features[] = { TP_CHANNEL_FEATURE_CORE, 0 }; + GQuark features[] = { TP_CHANNEL_FEATURE_CONTACTS, 0 }; g_assert (tp_proxy_get_invalidated (test->channel_room) == NULL); - tp_proxy_prepare_async (test->channel_room, features, - channel_prepared_cb, test); - g_main_loop_run (test->mainloop); - g_assert_no_error (test->error); + tp_tests_proxy_run_until_prepared (test->channel_room, features); tp_channel_leave_async (test->channel_room, TP_CHANNEL_GROUP_CHANGE_REASON_BUSY, @@ -561,12 +552,9 @@ static void test_join_room (Test *test, gconstpointer data G_GNUC_UNUSED) { - GQuark features[] = { TP_CHANNEL_FEATURE_GROUP, 0 }; + GQuark features[] = { TP_CHANNEL_FEATURE_CONTACTS, 0 }; - tp_proxy_prepare_async (test->channel_room, features, - channel_prepared_cb, test); - g_main_loop_run (test->mainloop); - g_assert_no_error (test->error); + tp_tests_proxy_run_until_prepared (test->channel_room, features); tp_channel_join_async (test->channel_room, "Hello World", join_cb, test); -- 1.7.9.5