summaryrefslogtreecommitdiff
path: root/telepathy-glib/channel.c
diff options
context:
space:
mode:
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2010-11-04 14:43:23 +0100
committerGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2010-11-08 09:49:38 +0100
commitce930a934392c573914214da70c9ff20664efe7f (patch)
tree42400c34f9cf4596229992ee8993aa1329cc610c /telepathy-glib/channel.c
parenteb587d2fbdf4f44b7ef85042507153f191ff8200 (diff)
downloadtelepathy-glib-ce930a934392c573914214da70c9ff20664efe7f.tar.gz
add tp_channel_leave_async() (fdo #30617)
Diffstat (limited to 'telepathy-glib/channel.c')
-rw-r--r--telepathy-glib/channel.c212
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)
+}