summaryrefslogtreecommitdiff
path: root/telepathy-glib/handle-channels-context.c
diff options
context:
space:
mode:
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2010-05-06 16:22:51 +0200
committerGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2010-05-17 11:59:53 +0200
commitba12d63d7d756ae83d76f0a65f128937fcd31458 (patch)
tree2a3b9d8c5c1feccbd56a574d990313e6a1f71992 /telepathy-glib/handle-channels-context.c
parent5a4bfd9400e655da6d37921b7bc6cecce48bc972 (diff)
downloadtelepathy-glib-ba12d63d7d756ae83d76f0a65f128937fcd31458.tar.gz
add handle-channels-context
Diffstat (limited to 'telepathy-glib/handle-channels-context.c')
-rw-r--r--telepathy-glib/handle-channels-context.c663
1 files changed, 663 insertions, 0 deletions
diff --git a/telepathy-glib/handle-channels-context.c b/telepathy-glib/handle-channels-context.c
new file mode 100644
index 000000000..f7c078bab
--- /dev/null
+++ b/telepathy-glib/handle-channels-context.c
@@ -0,0 +1,663 @@
+/*
+ * object for HandleChannels calls context
+ *
+ * Copyright © 2010 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
+ */
+
+/**
+ * SECTION: handle-channels-context
+ * @title: TpHandleChannelsContext
+ * @short_description: context of a Handler.HandleChannels() call
+ *
+ * Object used to represent the context of a Handler.HandleChannels()
+ * D-Bus call on a #TpBaseClient.
+ */
+
+/**
+ * TpHandleChannelsContext:
+ *
+ * Data structure representing the context of a Handler.HandleChannels()
+ * call.
+ *
+ * Since: 0.11.UNRELEASED
+ */
+
+/**
+ * TpHandleChannelsContextClass:
+ *
+ * The class of a #TpHandleChannelsContext.
+ *
+ * Since: 0.11.UNRELEASED
+ */
+
+#include "telepathy-glib/handle-channels-context-internal.h"
+#include "telepathy-glib/handle-channels-context.h"
+
+#include <telepathy-glib/channel.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/gtypes.h>
+
+#define DEBUG_FLAG TP_DEBUG_CLIENT
+#include "telepathy-glib/debug-internal.h"
+
+struct _TpHandleChannelsContextClass {
+ /*<private>*/
+ GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE(TpHandleChannelsContext,
+ tp_handle_channels_context, G_TYPE_OBJECT)
+
+enum {
+ PROP_ACCOUNT = 1,
+ PROP_CONNECTION,
+ PROP_CHANNELS,
+ PROP_REQUESTS_SATISFIED,
+ PROP_USER_ACTION_TIME,
+ PROP_HANDLER_INFO,
+ PROP_DBUS_CONTEXT,
+ N_PROPS
+};
+
+struct _TpHandleChannelsContextPrivate
+{
+ TpHandleChannelsContextState state;
+ GSimpleAsyncResult *result;
+ DBusGMethodInvocation *dbus_context;
+
+ /* Number of calls we are waiting they return. Once they have all returned
+ * the context is considered as prepared */
+ guint num_pending;
+};
+
+static void
+tp_handle_channels_context_init (TpHandleChannelsContext *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ TP_TYPE_HANDLE_CHANNELS_CONTEXT,
+ TpHandleChannelsContextPrivate);
+
+ self->priv->state = TP_HANDLE_CHANNELS_CONTEXT_STATE_NONE;
+}
+
+static void
+tp_handle_channels_context_dispose (GObject *object)
+{
+ TpHandleChannelsContext *self = TP_HANDLE_CHANNELS_CONTEXT (
+ object);
+ void (*dispose) (GObject *) =
+ G_OBJECT_CLASS (tp_handle_channels_context_parent_class)->dispose;
+
+ if (self->priv->state == TP_HANDLE_CHANNELS_CONTEXT_STATE_NONE ||
+ self->priv->state == TP_HANDLE_CHANNELS_CONTEXT_STATE_DELAYED)
+ {
+ GError error = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
+ "Disposing the TpHandleChannelsContext" };
+
+ g_warning ("Disposing a context in the %s state",
+ self->priv->state == TP_HANDLE_CHANNELS_CONTEXT_STATE_NONE ?
+ "none": "delayed");
+
+ tp_handle_channels_context_fail (self, &error);
+ }
+
+ if (self->account != NULL)
+ {
+ g_object_unref (self->account);
+ self->account = NULL;
+ }
+
+ if (self->connection != NULL)
+ {
+ g_object_unref (self->connection);
+ self->connection = NULL;
+ }
+
+ if (self->channels != NULL)
+ {
+ g_ptr_array_foreach (self->channels, (GFunc) g_object_unref, NULL);
+ g_ptr_array_unref (self->channels);
+ self->channels = NULL;
+ }
+
+ if (self->requests_satisfied != NULL)
+ {
+ g_ptr_array_foreach (self->requests_satisfied, (GFunc) g_object_unref,
+ NULL);
+ g_ptr_array_unref (self->requests_satisfied);
+ self->requests_satisfied = NULL;
+ }
+
+ if (self->handler_info != NULL)
+ {
+ g_hash_table_unref (self->handler_info);
+ self->handler_info = NULL;
+ }
+
+ if (self->priv->result != NULL)
+ {
+ g_object_unref (self->priv->result);
+ self->priv->result = NULL;
+ }
+
+ if (dispose != NULL)
+ dispose (object);
+}
+
+static void
+tp_handle_channels_context_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TpHandleChannelsContext *self = TP_HANDLE_CHANNELS_CONTEXT (
+ object);
+
+ switch (property_id)
+ {
+ case PROP_ACCOUNT:
+ g_value_set_object (value, self->account);
+ break;
+
+ case PROP_CONNECTION:
+ g_value_set_object (value, self->connection);
+ break;
+
+ case PROP_CHANNELS:
+ g_value_set_boxed (value, self->channels);
+ break;
+
+ case PROP_REQUESTS_SATISFIED:
+ g_value_set_boxed (value, self->requests_satisfied);
+ break;
+
+ case PROP_USER_ACTION_TIME:
+ g_value_set_uint64 (value, self->user_action_time);
+ break;
+
+ case PROP_HANDLER_INFO:
+ g_value_set_boxed (value, self->handler_info);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+tp_handle_channels_context_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TpHandleChannelsContext *self = TP_HANDLE_CHANNELS_CONTEXT (
+ object);
+
+ switch (property_id)
+ {
+ case PROP_ACCOUNT:
+ self->account = g_value_dup_object (value);
+ break;
+
+ case PROP_CONNECTION:
+ self->connection = g_value_dup_object (value);
+ break;
+
+ case PROP_CHANNELS:
+ self->channels = g_value_dup_boxed (value);
+ g_ptr_array_foreach (self->channels, (GFunc) g_object_ref, NULL);
+ break;
+
+ case PROP_REQUESTS_SATISFIED:
+ self->requests_satisfied = g_value_dup_boxed (value);
+ g_ptr_array_foreach (self->requests_satisfied, (GFunc) g_object_ref,
+ NULL);
+ break;
+
+ case PROP_USER_ACTION_TIME:
+ self->user_action_time = g_value_get_uint64 (value);
+ break;
+
+ case PROP_HANDLER_INFO:
+ self->handler_info = g_value_dup_boxed (value);
+ break;
+
+ case PROP_DBUS_CONTEXT:
+ self->priv->dbus_context = g_value_get_pointer (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+tp_handle_channels_context_constructed (GObject *object)
+{
+ TpHandleChannelsContext *self = TP_HANDLE_CHANNELS_CONTEXT (
+ object);
+ void (*chain_up) (GObject *) =
+ ((GObjectClass *) \
+ tp_handle_channels_context_parent_class)->constructed;
+
+ if (chain_up != NULL)
+ chain_up (object);
+
+ g_assert (self->account != NULL);
+ g_assert (self->connection != NULL);
+ g_assert (self->channels != NULL);
+ g_assert (self->requests_satisfied != NULL);
+ g_assert (self->handler_info != NULL);
+ g_assert (self->priv->dbus_context != NULL);
+}
+
+static void
+tp_handle_channels_context_class_init (
+ TpHandleChannelsContextClass *cls)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (cls);
+ GParamSpec *param_spec;
+
+ g_type_class_add_private (cls, sizeof (TpHandleChannelsContextPrivate));
+
+ object_class->get_property = tp_handle_channels_context_get_property;
+ object_class->set_property = tp_handle_channels_context_set_property;
+ object_class->constructed = tp_handle_channels_context_constructed;
+ object_class->dispose = tp_handle_channels_context_dispose;
+
+ /**
+ * TpHandleChannelsContext:account:
+ *
+ * A #TpAccount object representing the Account of the DispatchOperation
+ * that has been passed to HandleChannels.
+ * Read-only except during construction.
+ *
+ * This property can't be %NULL.
+ *
+ * Since: 0.11.UNRELEASED
+ */
+ param_spec = g_param_spec_object ("account", "TpAccount",
+ "The TpAccount of the context",
+ TP_TYPE_ACCOUNT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_ACCOUNT,
+ param_spec);
+
+ /**
+ * TpHandleChannelsContext:connection:
+ *
+ * A #TpConnection object representing the Connection of the DispatchOperation
+ * that has been passed to HandleChannels.
+ * Read-only except during construction.
+ *
+ * This property can't be %NULL.
+ *
+ * Since: 0.11.UNRELEASED
+ */
+ param_spec = g_param_spec_object ("connection", "TpConnection",
+ "The TpConnection of the context",
+ TP_TYPE_CONNECTION,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CONNECTION,
+ param_spec);
+
+ /**
+ * TpHandleChannelsContext:channels:
+ *
+ * A #GPtrArray containing #TpChannel objects representing the channels
+ * that have been passed to HandleChannels.
+ * Read-only except during construction.
+ *
+ * This property can't be %NULL.
+ *
+ * Since: 0.11.UNRELEASED
+ */
+ param_spec = g_param_spec_boxed ("channels", "GPtrArray of TpChannel",
+ "The TpChannels that have been passed to HandleChannels",
+ G_TYPE_PTR_ARRAY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CHANNELS,
+ param_spec);
+
+ /**
+ * TpHandleChannelsContext:requests-satisfied:
+ *
+ * A #GPtrArray containing #TpChannelRequest objects representing the
+ * requests that have been passed to HandleChannels.
+ * Read-only except during construction.
+ *
+ * This property can't be %NULL.
+ *
+ * Since: 0.11.UNRELEASED
+ */
+ param_spec = g_param_spec_boxed ("requests-satisfied",
+ "GPtrArray of TpChannelRequest",
+ "The TpChannelRequest that has been passed to "
+ "HandleChannels",
+ G_TYPE_PTR_ARRAY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_REQUESTS_SATISFIED,
+ param_spec);
+
+ /**
+ * TpHandleChannelsContext:user-action-time:
+ *
+ * The User_Action_Time that have been passed to HandleChannels.
+ * Read-only except during construction.
+ *
+ * This property can't be %NULL.
+ *
+ * Since: 0.11.UNRELEASED
+ */
+ param_spec = g_param_spec_uint64 ("user-action-time",
+ "User action time",
+ "The User_Action_Time that has been passed to HandleChannels",
+ 0, G_MAXINT64, 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_USER_ACTION_TIME,
+ param_spec);
+
+ /**
+ * TpHandleChannelsContext:handler-info:
+ *
+ * A #GHashTable where the keys are string and values are GValue instances.
+ * It represents the Handler_info hash table that has been passed to
+ * HandleChannels.
+ *
+ * This property can't be %NULL.
+ *
+ * Since: 0.11.UNRELEASED
+ */
+ param_spec = g_param_spec_boxed ("handler-info", "Handler info",
+ "The Handler that has been passed to ObserveChannels",
+ TP_HASH_TYPE_STRING_VARIANT_MAP,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_HANDLER_INFO,
+ param_spec);
+
+ /**
+ * TpHandleChannelsContext:dbus-context: (skip)
+ *
+ * The #DBusGMethodInvocation representing the D-Bus context of the
+ * HandleChannels call.
+ * Can only be written during construction.
+ *
+ * Since: 0.11.UNRELEASED
+ */
+ param_spec = g_param_spec_pointer ("dbus-context", "D-Bus context",
+ "The DBusGMethodInvocation associated with the HandleChannels call",
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_DBUS_CONTEXT,
+ param_spec);
+}
+
+TpHandleChannelsContext * _tp_handle_channels_context_new (
+ TpAccount *account,
+ TpConnection *connection,
+ GPtrArray *channels,
+ GPtrArray *requests_satisfied,
+ guint64 user_action_time,
+ GHashTable *handler_info,
+ DBusGMethodInvocation *dbus_context)
+{
+ return g_object_new (TP_TYPE_HANDLE_CHANNELS_CONTEXT,
+ "account", account,
+ "connection", connection,
+ "channels", channels,
+ "requests-satisfied", requests_satisfied,
+ "user-action-time", user_action_time,
+ "handler-info", handler_info,
+ "dbus-context", dbus_context,
+ NULL);
+}
+
+/**
+ * tp_handle_channels_context_accept:
+ * @self: a #TpHandleChannelsContext
+ *
+ * Called by #TpBaseClientClassAddDispatchOperationImpl when it's done so
+ * the D-Bus method can return.
+ *
+ * Since: 0.11.UNRELEASED
+ */
+void
+tp_handle_channels_context_accept (TpHandleChannelsContext *self)
+{
+ g_return_if_fail (self->priv->state ==
+ TP_HANDLE_CHANNELS_CONTEXT_STATE_NONE
+ || self->priv->state == TP_HANDLE_CHANNELS_CONTEXT_STATE_DELAYED);
+ g_return_if_fail (self->priv->dbus_context != NULL);
+
+ self->priv->state = TP_HANDLE_CHANNELS_CONTEXT_STATE_DONE;
+ dbus_g_method_return (self->priv->dbus_context);
+
+ self->priv->dbus_context = NULL;
+}
+
+/**
+ * tp_handle_channels_context_fail:
+ * @self: a #TpHandleChannelsContext
+ * @error: the error to return from the method
+ *
+ * Called by #TpBaseClientClassAddDispatchOperationImpl to raise a D-Bus error.
+ *
+ * Since: 0.11.UNRELEASED
+ */
+void
+tp_handle_channels_context_fail (TpHandleChannelsContext *self,
+ const GError *error)
+{
+ g_return_if_fail (self->priv->state ==
+ TP_HANDLE_CHANNELS_CONTEXT_STATE_NONE
+ || self->priv->state == TP_HANDLE_CHANNELS_CONTEXT_STATE_DELAYED);
+ g_return_if_fail (self->priv->dbus_context != NULL);
+
+ self->priv->state = TP_HANDLE_CHANNELS_CONTEXT_STATE_FAILED;
+ dbus_g_method_return_error (self->priv->dbus_context, error);
+
+ self->priv->dbus_context = NULL;
+}
+
+/**
+ * tp_handle_channels_context_delay:
+ * @self: a #TpHandleChannelsContext
+ *
+ * Called by #TpBaseClientClassAddDispatchOperationImpl to indicate that it
+ * implements the method in an async way. The caller must take a reference
+ * to the #TpHandleChannelsContext before calling this function, and
+ * is responsible for calling either
+ * tp_handle_channels_context_accept() or
+ * tp_handle_channels_context_fail() later.
+ *
+ * Since: 0.11.UNRELEASED
+ */
+void
+tp_handle_channels_context_delay (TpHandleChannelsContext *self)
+{
+ g_return_if_fail (self->priv->state ==
+ TP_HANDLE_CHANNELS_CONTEXT_STATE_NONE);
+
+ self->priv->state = TP_HANDLE_CHANNELS_CONTEXT_STATE_DELAYED;
+}
+
+TpHandleChannelsContextState
+_tp_handle_channels_context_get_state (
+ TpHandleChannelsContext *self)
+{
+ return self->priv->state;
+}
+
+static gboolean
+context_is_prepared (TpHandleChannelsContext *self)
+{
+ return self->priv->num_pending == 0;
+}
+
+static void
+context_check_prepare (TpHandleChannelsContext *self)
+{
+ if (!context_is_prepared (self))
+ return;
+
+ /* is prepared */
+ g_simple_async_result_complete (self->priv->result);
+
+ g_object_unref (self->priv->result);
+ self->priv->result = NULL;
+}
+
+static void
+account_prepare_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TpHandleChannelsContext *self = user_data;
+ GError *error = NULL;
+
+ if (self->priv->result == NULL)
+ goto out;
+
+ if (!tp_proxy_prepare_finish (source, result, &error))
+ {
+ DEBUG ("Failed to prepare account: %s", error->message);
+ g_error_free (error);
+ }
+
+ self->priv->num_pending--;
+ context_check_prepare (self);
+
+out:
+ g_object_unref (self);
+}
+
+static void
+conn_prepare_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TpHandleChannelsContext *self = user_data;
+ GError *error = NULL;
+
+ if (self->priv->result == NULL)
+ goto out;
+
+ if (!tp_proxy_prepare_finish (source, result, &error))
+ {
+ DEBUG ("Failed to prepare connection: %s", error->message);
+ g_error_free (error);
+ }
+
+ self->priv->num_pending--;
+ context_check_prepare (self);
+
+out:
+ g_object_unref (self);
+}
+
+static void
+channel_prepare_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TpHandleChannelsContext *self = user_data;
+ GError *error = NULL;
+
+ if (self->priv->result == NULL)
+ goto out;
+
+ if (!tp_proxy_prepare_finish (source, result, &error))
+ {
+ DEBUG ("Failed to prepare channel: %s", error->message);
+
+ g_error_free (error);
+ }
+
+ self->priv->num_pending--;
+ context_check_prepare (self);
+
+out:
+ g_object_unref (self);
+}
+
+static void
+context_prepare (TpHandleChannelsContext *self)
+{
+ GQuark account_features[] = { TP_ACCOUNT_FEATURE_CORE, 0 };
+ GQuark conn_features[] = { TP_CONNECTION_FEATURE_CORE, 0 };
+ GQuark channel_features[] = { TP_CHANNEL_FEATURE_CORE, 0 };
+ guint i;
+
+ self->priv->num_pending = 2;
+
+ tp_proxy_prepare_async (self->account, account_features,
+ account_prepare_cb, g_object_ref (self));
+
+ tp_proxy_prepare_async (self->connection, conn_features,
+ conn_prepare_cb, g_object_ref (self));
+
+ for (i = 0; i < self->channels->len; i++)
+ {
+ TpChannel *channel = g_ptr_array_index (self->channels, i);
+
+ self->priv->num_pending++;
+
+ tp_proxy_prepare_async (channel, channel_features,
+ channel_prepare_cb, g_object_ref (self));
+ }
+}
+
+void
+_tp_handle_channels_context_prepare_async (
+ TpHandleChannelsContext *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (TP_IS_HANDLE_CHANNELS_CONTEXT (self));
+ /* This is only used once, by TpBaseClient, so for simplicity, we only
+ * allow one asynchronous preparation */
+ g_return_if_fail (self->priv->result == NULL);
+
+ self->priv->result = g_simple_async_result_new (G_OBJECT (self),
+ callback, user_data, _tp_handle_channels_context_prepare_async);
+
+ context_prepare (self);
+}
+
+gboolean
+_tp_handle_channels_context_prepare_finish (
+ TpHandleChannelsContext *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_HANDLE_CHANNELS_CONTEXT (self), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (self), _tp_handle_channels_context_prepare_async),
+ FALSE);
+
+ return TRUE;
+}