diff options
author | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2010-04-26 12:18:49 +0200 |
---|---|---|
committer | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2010-04-29 09:11:44 +0200 |
commit | e3b651768e671f5910815fb23e1807f2e8e3d690 (patch) | |
tree | 986118f2d4c207f697804e41c8b5b3725b7c4ebe /telepathy-glib/observe-channels-context.c | |
parent | 227dc04a35aa42c78bbd00464fce72c3cfd9724a (diff) | |
download | telepathy-glib-e3b651768e671f5910815fb23e1807f2e8e3d690.tar.gz |
rename base-client-context* to observe-channels-context*
Each context will have its own file and object.
Diffstat (limited to 'telepathy-glib/observe-channels-context.c')
-rw-r--r-- | telepathy-glib/observe-channels-context.c | 524 |
1 files changed, 524 insertions, 0 deletions
diff --git a/telepathy-glib/observe-channels-context.c b/telepathy-glib/observe-channels-context.c new file mode 100644 index 000000000..eddf77c3f --- /dev/null +++ b/telepathy-glib/observe-channels-context.c @@ -0,0 +1,524 @@ +/* + * Context objects for TpBaseClient calls + * + * 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 + */ + +#include "telepathy-glib/observe-channels-context.h" +#include "telepathy-glib/observe-channels-context-internal.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 _TpObserveChannelsContextClass { + /*<private>*/ + GObjectClass parent_class; +}; + +G_DEFINE_TYPE(TpObserveChannelsContext, tp_observe_channels_context, + G_TYPE_OBJECT) + +enum { + PROP_ACCOUNT = 1, + PROP_CONNECTION, + PROP_CHANNELS, + PROP_DISPATCH_OPERATION, + PROP_REQUESTS, + PROP_OBSERVER_INFO, + PROP_DBUS_CONTEXT, + N_PROPS +}; + +struct _TpObserveChannelsContextPrivate +{ + TpBaseClientContextState state; + GSimpleAsyncResult *result; +}; + +static void +tp_observe_channels_context_init (TpObserveChannelsContext *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + TP_TYPE_OBSERVE_CHANNELS_CONTEXT, TpObserveChannelsContextPrivate); + + self->priv->state = TP_BASE_CLIENT_CONTEXT_STATE_NONE; +} + +static void +tp_observe_channels_context_dispose (GObject *object) +{ + TpObserveChannelsContext *self = TP_OBSERVE_CHANNELS_CONTEXT (object); + void (*dispose) (GObject *) = + G_OBJECT_CLASS (tp_observe_channels_context_parent_class)->dispose; + + 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->dispatch_operation != NULL) + { + g_object_unref (self->dispatch_operation); + self->dispatch_operation = NULL; + } + + if (self->requests != NULL) + { + g_ptr_array_foreach (self->requests, (GFunc) g_object_unref, NULL); + g_ptr_array_unref (self->requests); + self->requests = NULL; + } + + if (self->observer_info != NULL) + { + g_hash_table_unref (self->observer_info); + self->observer_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_observe_channels_context_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + TpObserveChannelsContext *self = TP_OBSERVE_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_DISPATCH_OPERATION: + g_value_set_object (value, self->dispatch_operation); + break; + case PROP_REQUESTS: + g_value_set_boxed (value, self->requests); + break; + case PROP_DBUS_CONTEXT: + g_value_set_pointer (value, self->dbus_context); + break; + case PROP_OBSERVER_INFO: + g_value_set_boxed (value, self->observer_info); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +tp_observe_channels_context_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + TpObserveChannelsContext *self = TP_OBSERVE_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_DISPATCH_OPERATION: + self->dispatch_operation = g_value_dup_object (value); + break; + case PROP_REQUESTS: + self->requests = g_value_dup_boxed (value); + g_ptr_array_foreach (self->requests, (GFunc) g_object_ref, NULL); + break; + case PROP_DBUS_CONTEXT: + self->dbus_context = g_value_get_pointer (value); + break; + case PROP_OBSERVER_INFO: + self->observer_info = g_value_dup_boxed (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +tp_observe_channels_context_constructed (GObject *object) +{ + TpObserveChannelsContext *self = TP_OBSERVE_CHANNELS_CONTEXT (object); + void (*chain_up) (GObject *) = + ((GObjectClass *) tp_observe_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 != NULL); + g_assert (self->observer_info != NULL); + g_assert (self->dbus_context != NULL); + + /* self->dispatch_operation may be NULL (channels were requested) */ +} + +static void +tp_observe_channels_context_class_init (TpObserveChannelsContextClass *cls) +{ + GObjectClass *object_class = G_OBJECT_CLASS (cls); + GParamSpec *param_spec; + + g_type_class_add_private (cls, sizeof (TpObserveChannelsContextPrivate)); + + object_class->get_property = tp_observe_channels_context_get_property; + object_class->set_property = tp_observe_channels_context_set_property; + object_class->constructed = tp_observe_channels_context_constructed; + object_class->dispose = tp_observe_channels_context_dispose; + + param_spec = g_param_spec_object ("account", "TpAccount", + "The TpAccount that has been passed to ObserveChannels", + 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); + + param_spec = g_param_spec_object ("connection", "TpConnection", + "The TpConnection that has been passed to ObserveChannels", + 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); + + param_spec = g_param_spec_boxed ("channels", "GPtrArray of TpChannel", + "The TpChannels that have been passed to ObserveChannels", + 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); + + param_spec = g_param_spec_object ("dispatch-operation", + "TpChannelDispatchOperation", + "The TpChannelDispatchOperation that has been passed to ObserveChannels", + TP_TYPE_CHANNEL_DISPATCH_OPERATION, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_DISPATCH_OPERATION, + param_spec); + + param_spec = g_param_spec_boxed ("requests", "GPtrArray of TpChannelRequest", + "The TpChannelRequest that have been passed to ObserveChannels", + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_REQUESTS, + param_spec); + + param_spec = g_param_spec_pointer ("dbus-context", "D-Bus context", + "The DBusGMethodInvocation associated with the ObserveChannels call", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_DBUS_CONTEXT, + param_spec); + + param_spec = g_param_spec_boxed ("observer-info", "Observer info", + "The Observer_Info 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_OBSERVER_INFO, + param_spec); +} + +TpObserveChannelsContext * +_tp_observe_channels_context_new ( + TpAccount *account, + TpConnection *connection, + GPtrArray *channels, + TpChannelDispatchOperation *dispatch_operation, + GPtrArray *requests, + GHashTable *observer_info, + DBusGMethodInvocation *dbus_context) +{ + return g_object_new (TP_TYPE_OBSERVE_CHANNELS_CONTEXT, + "account", account, + "connection", connection, + "channels", channels, + "dispatch-operation", dispatch_operation, + "requests", requests, + "observer-info", observer_info, + "dbus-context", dbus_context, + NULL); +} + +void +tp_observe_channels_context_accept (TpObserveChannelsContext *self) +{ + self->priv->state = TP_BASE_CLIENT_CONTEXT_STATE_DONE; + dbus_g_method_return (self->dbus_context); +} + +void +tp_observe_channels_context_fail (TpObserveChannelsContext *self, + const GError *error) +{ + self->priv->state = TP_BASE_CLIENT_CONTEXT_STATE_FAILED; + dbus_g_method_return_error (self->dbus_context, error); +} + +void +tp_observe_channels_context_delay (TpObserveChannelsContext *self) +{ + self->priv->state = TP_BASE_CLIENT_CONTEXT_STATE_DELAYED; +} + +gboolean +tp_observe_channels_context_get_recovering (TpObserveChannelsContext *self) +{ + /* tp_asv_get_boolean returns FALSE if the key is not set which is what we + * want */ + return tp_asv_get_boolean (self->observer_info, "recovering", NULL); +} + +TpBaseClientContextState +_tp_observe_channels_context_get_state ( + TpObserveChannelsContext *self) +{ + return self->priv->state; +} + +static gboolean +context_is_prepared (TpObserveChannelsContext *self) +{ + guint i; + + if (!tp_proxy_is_prepared (self->account, TP_ACCOUNT_FEATURE_CORE)) + return FALSE; + + if (!tp_proxy_is_prepared (self->connection, TP_CONNECTION_FEATURE_CORE)) + return FALSE; + + for (i = 0; i < self->channels->len; i++) + { + TpChannel *channel = g_ptr_array_index (self->channels, i); + + if (!tp_proxy_is_prepared (channel, TP_CHANNEL_FEATURE_CORE)) + return FALSE; + } + + return TRUE; +} + +static void +context_check_prepare (TpObserveChannelsContext *self) +{ + if (!context_is_prepared (self)) + return; + + /* Context is prepared */ + g_simple_async_result_complete (self->priv->result); + + g_object_unref (self->priv->result); + self->priv->result = NULL; +} + +static void +failed_to_prepare (TpObserveChannelsContext *self, + const GError *error) +{ + g_return_if_fail (self->priv->result != NULL); + + g_simple_async_result_set_from_error (self->priv->result, error); + 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) +{ + TpObserveChannelsContext *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); + failed_to_prepare (self, error); + g_error_free (error); + goto out; + } + + context_check_prepare (self); + +out: + g_object_unref (self); +} + +static void +conn_prepare_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + TpObserveChannelsContext *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); + failed_to_prepare (self, error); + g_error_free (error); + goto out; + } + + context_check_prepare (self); + +out: + g_object_unref (self); +} + +static void +channel_prepare_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + TpObserveChannelsContext *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); + failed_to_prepare (self, error); + g_error_free (error); + goto out; + } + + context_check_prepare (self); + +out: + g_object_unref (self); +} + +static void +context_prepare (TpObserveChannelsContext *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; + + 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); + + tp_proxy_prepare_async (channel, channel_features, + channel_prepare_cb, g_object_ref (self)); + } +} + +void +tp_observe_channels_context_prepare_async (TpObserveChannelsContext *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (TP_IS_OBSERVE_CHANNELS_CONTEXT (self)); + g_return_if_fail (self->priv->result == NULL); + + self->priv->result = g_simple_async_result_new (G_OBJECT (self), + callback, user_data, tp_observe_channels_context_prepare_async); + + if (context_is_prepared (self)) + { + g_simple_async_result_complete_in_idle (self->priv->result); + g_object_unref (self->priv->result); + self->priv->result = NULL; + return; + } + + context_prepare (self); +} + +gboolean +tp_observe_channels_context_prepare_finish ( + TpObserveChannelsContext *self, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail (TP_IS_OBSERVE_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_observe_channels_context_prepare_async), FALSE); + + return TRUE; +} |