diff options
author | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2010-11-04 14:43:23 +0100 |
---|---|---|
committer | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2010-11-08 09:49:38 +0100 |
commit | ce930a934392c573914214da70c9ff20664efe7f (patch) | |
tree | 42400c34f9cf4596229992ee8993aa1329cc610c /telepathy-glib/channel.c | |
parent | eb587d2fbdf4f44b7ef85042507153f191ff8200 (diff) | |
download | telepathy-glib-ce930a934392c573914214da70c9ff20664efe7f.tar.gz |
add tp_channel_leave_async() (fdo #30617)
Diffstat (limited to 'telepathy-glib/channel.c')
-rw-r--r-- | telepathy-glib/channel.c | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/telepathy-glib/channel.c b/telepathy-glib/channel.c index b613ee9d7..7bdb290c1 100644 --- a/telepathy-glib/channel.c +++ b/telepathy-glib/channel.c @@ -27,6 +27,7 @@ #include <telepathy-glib/interfaces.h> #include <telepathy-glib/proxy-subclass.h> #include <telepathy-glib/util.h> +#include <telepathy-glib/util-internal.h> #define DEBUG_FLAG TP_DEBUG_CHANNEL #include "telepathy-glib/debug-internal.h" @@ -2122,3 +2123,214 @@ tp_channel_get_initiator_identifier (TpChannel *self) return id != NULL ? id : ""; } + +static void +channel_close_cb (TpChannel *channel, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + GSimpleAsyncResult *result = user_data; + + if (error != NULL) + { + DEBUG ("Close() failed: %s", error->message); + g_simple_async_result_set_from_error (result, error); + } + + g_simple_async_result_complete (result); + g_object_unref (result); +} + +static void +channel_remove_self_cb (TpChannel *channel, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + GSimpleAsyncResult *result = user_data; + + if (error != NULL) + { + DEBUG ("RemoveMembersWithDetails() with self handle failed: %s", + error->message); + + if (tp_proxy_get_invalidated (channel) != NULL) + { + DEBUG ("Proxy has been invalidated; succeed"); + goto succeed; + } + + DEBUG ("Close channel then"); + + tp_cli_channel_call_close (channel, -1, channel_close_cb, result, + NULL, NULL); + return; + } + + DEBUG ("RemoveMembersWithDetails() succeeded"); + +succeed: + g_simple_async_result_complete (result); + 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); +} + +static void +group_prepared_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + LeaveCtx *ctx = user_data; + TpChannel *self = (TpChannel *) source; + GError *error = NULL; + TpHandle self_handle; + 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; + } + + self_handle = tp_channel_group_get_self_handle (self); + if (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_handle); + + tp_cli_channel_interface_group_call_remove_members_with_reason ( + 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 + * @reason: the leave reason + * @message: the leave message + * @callback: a callback to call when we left the channel + * @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 properly leave the channel, we close it. + * + * If @reason equals TP_CHANNEL_GROUP_CHANGE_REASON_NONE and message is %NULL + * then @self is simply closed as well. + * + * When we left the channel, @callback will be called. + * You can then call tp_channel_leave_finish() to get the result of + * the operation. + * + * Since: 0.13.UNRELEASED + */ +void +tp_channel_leave_async (TpChannel *self, + TpChannelGroupChangeReason reason, + const gchar *message, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *result; + GQuark features[] = { TP_CHANNEL_FEATURE_GROUP, 0 }; + LeaveCtx *ctx; + + 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)) + { + DEBUG ("Channel doesn't implement Group; fallback to Close()"); + + tp_cli_channel_call_close (self, -1, channel_close_cb, result, + NULL, NULL); + return; + } + + if (tp_str_empty (message) && + reason == TP_CHANNEL_GROUP_CHANGE_REASON_NONE) + { + /* exactly equivalent to Close(), so skip the Group interface */ + 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); + + tp_proxy_prepare_async (self, features, group_prepared_cb, ctx); +} + +/** + * tp_channel_leave_finish: + * @self: a #TpChannel + * @result: a #GAsyncResult + * @error: a #GError to fill + * + * Finishes to leave a channel. + * + * Returns: %TRUE if the channel has been left; %FALSE otherwise + * + * Since: 0.13.UNRELEASED + */ +gboolean +tp_channel_leave_finish (TpChannel *self, + GAsyncResult *result, + GError **error) +{ + _tp_implement_finish_void (self, tp_channel_leave_async) +} |