diff options
author | Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> | 2011-03-15 20:38:15 -0400 |
---|---|---|
committer | Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> | 2011-03-15 20:38:15 -0400 |
commit | 5f674080ff0ddffc1ff08bab24246d5286d09ded (patch) | |
tree | d11ddec1fcb80d81fd9c0cd34a86095e73eff5b9 | |
parent | 4e8209969d0a67299c5b2ff6beb21d4c482034f1 (diff) |
Change TplChannel into an interface and port
This change will allow TplTextChannel to inherit TpTextChannel, choose
what feature it wants to be prepared. It also slightly change the action
chain API to better fit GAsync normal signature.
-rw-r--r-- | telepathy-logger/action-chain-internal.h | 5 | ||||
-rw-r--r-- | telepathy-logger/action-chain.c | 39 | ||||
-rw-r--r-- | telepathy-logger/channel-internal.h | 51 | ||||
-rw-r--r-- | telepathy-logger/channel.c | 262 | ||||
-rw-r--r-- | telepathy-logger/dbus-service.c | 24 | ||||
-rw-r--r-- | telepathy-logger/observer.c | 18 | ||||
-rw-r--r-- | telepathy-logger/text-channel-internal.h | 31 | ||||
-rw-r--r-- | telepathy-logger/text-channel.c | 154 |
8 files changed, 222 insertions, 362 deletions
diff --git a/telepathy-logger/action-chain-internal.h b/telepathy-logger/action-chain-internal.h index f0a75f4..c2c072f 100644 --- a/telepathy-logger/action-chain-internal.h +++ b/telepathy-logger/action-chain-internal.h @@ -40,8 +40,9 @@ void _tpl_action_chain_append (TplActionChain *self, TplPendingAction func, void _tpl_action_chain_prepend (TplActionChain *self, TplPendingAction func, gpointer user_data); void _tpl_action_chain_continue (TplActionChain *self); -void _tpl_action_chain_terminate (TplActionChain *self); +void _tpl_action_chain_terminate (TplActionChain *self, const GError *error); gpointer _tpl_action_chain_get_object (TplActionChain *self); -gboolean _tpl_action_chain_new_finish (GAsyncResult *result); +gboolean _tpl_action_chain_new_finish (GObject *source, + GAsyncResult *result, GError **error); #endif // __TPL_ACTION_CHAIN_H__ diff --git a/telepathy-logger/action-chain.c b/telepathy-logger/action-chain.c index f68a770..0999885 100644 --- a/telepathy-logger/action-chain.c +++ b/telepathy-logger/action-chain.c @@ -110,12 +110,7 @@ void _tpl_action_chain_continue (TplActionChain *self) { if (g_queue_is_empty (self->chain)) - { - GSimpleAsyncResult *simple = self->simple; - - g_simple_async_result_set_op_res_gboolean (simple, TRUE); - g_simple_async_result_complete (simple); - } + g_simple_async_result_complete (self->simple); else { TplActionLink *l = g_queue_pop_head (self->chain); @@ -127,35 +122,49 @@ _tpl_action_chain_continue (TplActionChain *self) void -_tpl_action_chain_terminate (TplActionChain *self) +_tpl_action_chain_terminate (TplActionChain *self, + const GError *error) { GSimpleAsyncResult *simple = self->simple; - g_simple_async_result_set_op_res_gboolean (simple, FALSE); + g_assert (error != NULL); + + g_simple_async_result_set_from_error (simple, error); g_simple_async_result_complete (simple); } /** * _tpl_action_chain_new_finish: + * @source: the #GObject pass to _tpl_action_chain_new_async() + * @result: the #GAsyncResult pass in callback + * @error: a pointer to a #GError that will be set on error, or NULL to ignore * * Get the result from running the action chain (%TRUE if the chain completed - * successfully, %FALSE if it was terminated). + * successfully, %FALSE with @error set if it was terminated). * * This function also frees the chain. + * + * Returns: %TRUE on success, %FALSE with @error set on error. */ gboolean -_tpl_action_chain_new_finish (GAsyncResult *result) +_tpl_action_chain_new_finish (GObject *source, + GAsyncResult *result, + GError **error) { TplActionChain *chain; - gboolean retval; + + g_return_val_if_fail (g_simple_async_result_is_valid (result, source, + _tpl_action_chain_new_async), FALSE); chain = g_object_get_data (G_OBJECT (result), "chain"); - retval = g_simple_async_result_get_op_res_gboolean ( - G_SIMPLE_ASYNC_RESULT (result)); + g_return_val_if_fail (chain != NULL, FALSE); - _tpl_action_chain_free (chain); + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), + error)) + return FALSE; - return retval; + _tpl_action_chain_free (chain); + return TRUE; } diff --git a/telepathy-logger/channel-internal.h b/telepathy-logger/channel-internal.h index 7c5ec5e..9da0f61 100644 --- a/telepathy-logger/channel-internal.h +++ b/telepathy-logger/channel-internal.h @@ -30,40 +30,35 @@ #include <telepathy-glib/channel.h> G_BEGIN_DECLS -#define TPL_TYPE_CHANNEL (_tpl_channel_get_type ()) -#define TPL_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TPL_TYPE_CHANNEL, TplChannel)) -#define TPL_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TPL_TYPE_CHANNEL, TplChannelClass)) -#define TPL_IS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TPL_TYPE_CHANNEL)) -#define TPL_IS_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TPL_TYPE_CHANNEL)) -#define TPL_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TPL_TYPE_CHANNEL, TplChannelClass)) -typedef struct _TplChannelPriv TplChannelPriv; +#define TPL_TYPE_CHANNEL (_tpl_channel_get_type ()) +#define TPL_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TPL_TYPE_CHANNEL, TplChannel)) +#define TPL_IS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TPL_TYPE_CHANNEL)) +#define TPL_CHANNEL_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TPL_TYPE_CHANNEL, TplChannelInterface)) -typedef struct -{ - TpChannel parent; - - /* private */ - TplChannelPriv *priv; -} TplChannel; +typedef struct _TplChannel TplChannel; +typedef struct _TplChannelInterface TplChannelInterface; -typedef struct +struct _TplChannelInterface { - TpChannelClass parent_class; - /* Virtual method, to be implemented by subclasses */ - void (*call_when_ready) (TplChannel *self, GAsyncReadyCallback cb, - gpointer user_data); - /* Protected method, should be called only by subclasses to prepare - * TplChannel */ - void (*call_when_ready_protected) (TplChannel *self, GAsyncReadyCallback cb, - gpointer user_data); -} TplChannelClass; + GTypeInterface g_iface; + + void (*prepare_async) (TplChannel *self, + GAsyncReadyCallback cb, + gpointer user_data); + gboolean (*prepare_finish) (TplChannel *self, + GAsyncResult *result, + GError **error); +}; -GType _tpl_channel_get_type (void); +GType _tpl_channel_get_type (void) G_GNUC_CONST; -TpAccount *_tpl_channel_get_account (TplChannel *self); -void _tpl_channel_call_when_ready (TplChannel *self, GAsyncReadyCallback cb, - gpointer user_data); +void _tpl_channel_prepare_async (TplChannel *self, + GAsyncReadyCallback cb, + gpointer user_data); +gboolean _tpl_channel_prepare_finish (TplChannel *self, + GAsyncResult *result, + GError **error); G_END_DECLS #endif // __TPL_CHANNEL_H__ diff --git a/telepathy-logger/channel.c b/telepathy-logger/channel.c index a098e46..fe5309c 100644 --- a/telepathy-logger/channel.c +++ b/telepathy-logger/channel.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2009 Collabora Ltd. + * Copyright (C) 2009-2011 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,168 +17,25 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk> + * Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> */ #include "config.h" #include "channel-internal.h" -#include <string.h> - #include <glib.h> -#include <telepathy-glib/util.h> - -#include <telepathy-logger/text-channel-internal.h> -#include <telepathy-logger/observer-internal.h> - -#define DEBUG_FLAG TPL_DEBUG_CHANNEL -#include <telepathy-logger/action-chain-internal.h> -#include <telepathy-logger/debug-internal.h> -#include <telepathy-logger/util-internal.h> - -#define TPCHAN_PROP_PREFIX "org.freedesktop.Telepathy.Channel." -#define TPCHAN_PROP_PREFIX_LEN strlen(TPCHAN_PROP_PREFIX) - -static void tpl_channel_set_account (TplChannel *self, TpAccount *data); -static void call_when_ready_protected (TplChannel *self, - GAsyncReadyCallback cb, gpointer user_data); -static void pendingproc_get_ready_tp_connection (TplActionChain *ctx, - gpointer user_data); -static void pendingproc_get_ready_tp_channel (TplActionChain *ctx, - gpointer user_data); - -G_DEFINE_ABSTRACT_TYPE (TplChannel, _tpl_channel, TP_TYPE_CHANNEL) - -struct _TplChannelPriv -{ - TpAccount *account; -}; - -enum -{ - PROP0, - PROP_ACCOUNT -}; - -static void -tpl_channel_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - TplChannelPriv *priv = TPL_CHANNEL (object)->priv; - - switch (param_id) - { - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -tpl_channel_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - TplChannel *self = TPL_CHANNEL (object); - - switch (param_id) { - case PROP_ACCOUNT: - tpl_channel_set_account (self, g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - - -static void -tpl_channel_dispose (GObject *obj) -{ - TplChannelPriv *priv = TPL_CHANNEL (obj)->priv; - - if (priv->account != NULL) - { - g_object_unref (priv->account); - priv->account = NULL; - } - - G_OBJECT_CLASS (_tpl_channel_parent_class)->dispose (obj); -} - - -static void -_tpl_channel_class_init (TplChannelClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *param_spec; - - object_class->dispose = tpl_channel_dispose; - object_class->get_property = tpl_channel_get_property; - object_class->set_property = tpl_channel_set_property; - - klass->call_when_ready_protected = call_when_ready_protected; - - /** - * TplChannel:account: - * - * the TpAccount instance associated with TplChannel - */ - param_spec = g_param_spec_object ("account", - "Account", "TpAccount instance associated with TplChannel", - 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); - - g_type_class_add_private (object_class, sizeof (TplChannelPriv)); -} - - -static void -_tpl_channel_init (TplChannel *self) -{ - TplChannelPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TPL_TYPE_CHANNEL, - TplChannelPriv); - self->priv = priv; -} - - -TpAccount * -_tpl_channel_get_account (TplChannel *self) -{ - TplChannelPriv *priv; - - g_return_val_if_fail (TPL_IS_CHANNEL (self), NULL); - - priv = self->priv; - return priv->account; -} +G_DEFINE_INTERFACE (TplChannel, _tpl_channel, TP_TYPE_CHANNEL) static void -tpl_channel_set_account (TplChannel *self, - TpAccount *data) +_tpl_channel_default_init (TplChannelInterface *iface) { - TplChannelPriv *priv; - - g_return_if_fail (TPL_IS_CHANNEL (self)); - g_return_if_fail (TP_IS_ACCOUNT (data)); - - priv = self->priv; - g_return_if_fail (priv->account == NULL); - - priv->account = g_object_ref (data); } /** - * tpl_channel_call_when_ready + * tpl_channel_prepare_async * @self: a TplChannel instance * @cb: a callback * @user_data: user's data passed to the callback @@ -186,116 +43,29 @@ tpl_channel_set_account (TplChannel *self, * The TplObserver has no idea of what TplChannel subclass instance it's * dealing with. * In order to prepare the subclass instance this method has to - * be called, which will call #TplChannelClass.call_when_ready + * be called, which will call #TplChannelClass.prepare_async * virtual method, implemented (mandatory) by #TplChannel subclasses. - * Such method has to call, internally, - * #TplChannelClass.call_when_ready_protected in order to prepare also the - * #TplChannel instance. */ void -_tpl_channel_call_when_ready (TplChannel *self, +_tpl_channel_prepare_async (TplChannel *self, GAsyncReadyCallback cb, gpointer user_data) { g_return_if_fail (TPL_IS_CHANNEL (self)); - /* Subclasses have to implement it */ - g_return_if_fail (TPL_CHANNEL_GET_CLASS (self)->call_when_ready != NULL); - - TPL_CHANNEL_GET_CLASS (self)->call_when_ready (self, cb, user_data); -} - - -/** - * call_when_ready_protected - * @self: a TplChannel instance - * @cb: a callback - * @user_data: user's data passed to the callback - * - * This static method is called from #TplChannelClass.call_when_ready, implemented by - * #TplChannel subclasses. - * - * See also: %tpl_channel_call_when_ready - */ -static void -call_when_ready_protected (TplChannel *self, - GAsyncReadyCallback cb, - gpointer user_data) -{ - TplActionChain *actions; - - actions = _tpl_action_chain_new_async (G_OBJECT (self), cb, user_data); - _tpl_action_chain_append (actions, pendingproc_get_ready_tp_connection, NULL); - _tpl_action_chain_append (actions, pendingproc_get_ready_tp_channel, NULL); - _tpl_action_chain_continue (actions); -} - -static void -conn_prepared_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - TplActionChain *ctx = user_data; - GError *error = NULL; - - if (!tp_proxy_prepare_finish (source, result, &error)) - { - TplChannel *tpl_chan; - - tpl_chan = _tpl_action_chain_get_object (ctx); - PATH_DEBUG (tpl_chan, "Giving up channel observation: %s", - error->message); + g_return_if_fail (TPL_CHANNEL_GET_IFACE (self)->prepare_async != NULL); - _tpl_action_chain_terminate (ctx); - g_error_free (error); - return; - } - - _tpl_action_chain_continue (ctx); + TPL_CHANNEL_GET_IFACE (self)->prepare_async (self, cb, user_data); } -static void -pendingproc_get_ready_tp_connection (TplActionChain *ctx, - gpointer user_data) -{ - TplChannel *tpl_chan = _tpl_action_chain_get_object (ctx); - TpConnection *tp_conn = tp_channel_borrow_connection (TP_CHANNEL ( - tpl_chan)); - GQuark features[] = { TP_CONNECTION_FEATURE_CORE, 0 }; - - tp_proxy_prepare_async (tp_conn, features, conn_prepared_cb, ctx); -} -static void -channel_prepared_cb (GObject *source, +gboolean +_tpl_channel_prepare_finish (TplChannel *self, GAsyncResult *result, - gpointer user_data) -{ - TplActionChain *ctx = user_data; - TplChannel *tpl_chan = _tpl_action_chain_get_object (ctx); - GError *error = NULL; - - if (!tp_proxy_prepare_finish (source, result, &error)) - { - PATH_DEBUG (tpl_chan, "Giving up channel observation: %s", - error->message); - - _tpl_action_chain_terminate (ctx); - g_error_free (error); - return; - - } - - _tpl_action_chain_continue (ctx); -} - -static void -pendingproc_get_ready_tp_channel (TplActionChain *ctx, - gpointer user_data) + GError **error) { - TplChannel *tpl_chan = _tpl_action_chain_get_object (ctx); - GQuark features[] = { TP_CHANNEL_FEATURE_CORE, TP_CHANNEL_FEATURE_GROUP, 0 }; + g_return_val_if_fail (TPL_IS_CHANNEL (self), FALSE); + g_return_val_if_fail (TPL_CHANNEL_GET_IFACE (self)->prepare_finish != NULL, + FALSE); - /* user_data is a TplChannel instance */ - tp_proxy_prepare_async (TP_CHANNEL (tpl_chan), features, channel_prepared_cb, - ctx); + return TPL_CHANNEL_GET_IFACE (self)->prepare_finish (self, result, error); } diff --git a/telepathy-logger/dbus-service.c b/telepathy-logger/dbus-service.c index 536733d..22561ad 100644 --- a/telepathy-logger/dbus-service.c +++ b/telepathy-logger/dbus-service.c @@ -214,9 +214,9 @@ favourite_contacts_file_read_line_cb (GObject *object, if (error != NULL) { - DEBUG ("failed to open favourite contacts file: %s", error->message); + g_prefix_error (&error, "failed to open favourite contacts file: "); + _tpl_action_chain_terminate (action_chain, error); g_clear_error (&error); - _tpl_action_chain_terminate (action_chain); } else if (line != NULL) { @@ -260,9 +260,9 @@ favourite_contacts_file_open_cb (GObject *object, } else { - DEBUG ("Failed to open the favourite contacts file: %s", error->message); + g_prefix_error (&error, "Failed to open the favourite contacts file: "); + _tpl_action_chain_terminate (action_chain, error); g_clear_error (&error); - _tpl_action_chain_terminate (action_chain); } } @@ -309,11 +309,13 @@ favourite_contacts_file_parsed_cb (GObject *object, { TplDBusService *self = TPL_DBUS_SERVICE (object); TplDBusServicePriv *priv = self->priv; + GError *error = NULL; - if (!_tpl_action_chain_new_finish (result)) + if (!_tpl_action_chain_new_finish (object, result, &error)) { DEBUG ("Failed to parse the favourite contacts file and/or execute " - "subsequent queued method calls"); + "subsequent queued method calls: %s", error->message); + g_error_free (error); } priv->favourite_contacts_actions = NULL; @@ -602,9 +604,10 @@ pendingproc_add_favourite_contact (TplActionChain *action_chain, return; pendingproc_add_favourite_contact_ERROR: - g_clear_error (&error); if (action_chain != NULL) - _tpl_action_chain_terminate (action_chain); + _tpl_action_chain_terminate (action_chain, error); + + g_clear_error (&error); } @@ -702,9 +705,10 @@ pendingproc_remove_favourite_contact (TplActionChain *action_chain, return; pendingproc_remove_favourite_contact_ERROR: - g_clear_error (&error); if (action_chain != NULL) - _tpl_action_chain_terminate (action_chain); + _tpl_action_chain_terminate (action_chain, error); + + g_clear_error (&error); } static void diff --git a/telepathy-logger/observer.c b/telepathy-logger/observer.c index a2bd40b..2645e08 100644 --- a/telepathy-logger/observer.c +++ b/telepathy-logger/observer.c @@ -82,7 +82,8 @@ */ static void tpl_observer_dispose (GObject * obj); -static void got_tpl_text_channel_ready_cb (GObject *obj, GAsyncResult *result, +static void channel_prepared_cb (GObject *obj, + GAsyncResult *result, gpointer user_data); static TplChannelFactory tpl_observer_get_channel_factory (TplObserver *self); @@ -181,7 +182,7 @@ tpl_observer_observe_channels (TpBaseClient *client, g_hash_table_insert (self->priv->preparing_channels, (gchar *) tp_proxy_get_object_path (tpl_chan), tpl_chan); - _tpl_channel_call_when_ready (tpl_chan, got_tpl_text_channel_ready_cb, + _tpl_channel_prepare_async (tpl_chan, channel_prepared_cb, observing_ctx); } @@ -227,23 +228,24 @@ _tpl_observer_register_channel (TplObserver *self, return TRUE; } + static void -got_tpl_text_channel_ready_cb (GObject *obj, +channel_prepared_cb (GObject *obj, GAsyncResult *result, gpointer user_data) { ObservingContext *observing_ctx = user_data; - gboolean success = _tpl_action_chain_new_finish (result); + GError *error = NULL; - if (success) + if (_tpl_action_chain_new_finish (obj, result, &error)) { - PATH_DEBUG (obj, "prepared channel"); - + PATH_DEBUG (obj, "channel prepared"); _tpl_observer_register_channel (observing_ctx->self, TPL_CHANNEL (obj)); } else { - PATH_DEBUG (obj, "failed to prepare"); + PATH_DEBUG (obj, "failed to prepare channel: %s", error->message); + g_error_free (error); } g_hash_table_remove (observing_ctx->self->priv->preparing_channels, diff --git a/telepathy-logger/text-channel-internal.h b/telepathy-logger/text-channel-internal.h index 2b71a01..00f4d87 100644 --- a/telepathy-logger/text-channel-internal.h +++ b/telepathy-logger/text-channel-internal.h @@ -31,21 +31,34 @@ #include <telepathy-glib/channel.h> #include <telepathy-glib/connection.h> #include <telepathy-glib/contact.h> +#include <telepathy-glib/text-channel.h> -#include <telepathy-logger/channel-internal.h> +#include "channel-internal.h" G_BEGIN_DECLS -#define TPL_TYPE_TEXT_CHANNEL (_tpl_text_channel_get_type ()) -#define TPL_TEXT_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TPL_TYPE_TEXT_CHANNEL, TplTextChannel)) -#define TPL_TEXT_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TPL_TYPE_TEXT_CHANNEL, TplTextChannelClass)) -#define TPL_IS_TEXT_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TPL_TYPE_TEXT_CHANNEL)) -#define TPL_IS_TEXT_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TPL_TYPE_TEXT_CHANNEL)) -#define TPL_TEXT_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TPL_TYPE_TEXT_CHANNEL, TplTextChannelClass)) + +#define TPL_TYPE_TEXT_CHANNEL (_tpl_text_channel_get_type ()) +#define TPL_TEXT_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TPL_TYPE_TEXT_CHANNEL, TplTextChannel)) +#define TPL_TEXT_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TPL_TYPE_TEXT_CHANNEL, TplTextChannelClass)) +#define TPL_IS_TEXT_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TPL_TYPE_TEXT_CHANNEL)) +#define TPL_IS_TEXT_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TPL_TYPE_TEXT_CHANNEL)) +#define TPL_TEXT_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TPL_TYPE_TEXT_CHANNEL, TplTextChannelClass)) + + +#define TPL_TEXT_CHANNEL_ERROR \ + g_quark_from_static_string ("tpl-text-channel-error-quark") + +typedef enum +{ + /* generic error */ + TPL_TEXT_CHANNEL_ERROR_FAILED, + TPL_TEXT_CHANNEL_ERROR_NEED_MESSAGE_INTERFACE, +} TplTextChannelError; typedef struct _TplTextChannelPriv TplTextChannelPriv; typedef struct { - TplChannel parent; + TpTextChannel parent; /* private */ TplTextChannelPriv *priv; @@ -53,7 +66,7 @@ typedef struct typedef struct { - TplChannelClass parent_class; + TpTextChannelClass parent_class; } TplTextChannelClass; GType _tpl_text_channel_get_type (void); diff --git a/telepathy-logger/text-channel.c b/telepathy-logger/text-channel.c index 6b2f054..58114bd 100644 --- a/telepathy-logger/text-channel.c +++ b/telepathy-logger/text-channel.c @@ -43,6 +43,7 @@ struct _TplTextChannelPriv { + TpAccount *account; TplEntity *self; gboolean is_chatroom; TplEntity *chatroom; /* only set if is_chatroom==TRUE */ @@ -62,36 +63,86 @@ static TpContactFeature features[3] = { TP_CONTACT_FEATURE_AVATAR_TOKEN }; -G_DEFINE_TYPE (TplTextChannel, _tpl_text_channel, TPL_TYPE_CHANNEL) +static void tpl_text_channel_iface_init (TplChannelInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (TplTextChannel, _tpl_text_channel, + TP_TYPE_TEXT_CHANNEL, + G_IMPLEMENT_INTERFACE (TPL_TYPE_CHANNEL, tpl_text_channel_iface_init)) static void -got_tpl_chan_ready_cb (GObject *obj, +connection_prepared_cb (GObject *source, GAsyncResult *result, gpointer user_data) { - TpProxy *proxy = TP_PROXY (obj); TplActionChain *ctx = user_data; + GError *error = NULL; - /* if TplChannel preparation is OK (and support Message interface, - * keep on with the TplTextChannel */ - if (_tpl_action_chain_new_finish (result) - && tp_proxy_has_interface_by_id (proxy, - TP_IFACE_QUARK_CHANNEL_INTERFACE_MESSAGES)) - _tpl_action_chain_continue (ctx); - else - _tpl_action_chain_terminate (ctx); + if (!tp_proxy_prepare_finish (source, result, &error)) + { + _tpl_action_chain_terminate (ctx, error); + g_error_free (error); + return; + } + + _tpl_action_chain_continue (ctx); } static void -pendingproc_prepare_tpl_channel (TplActionChain *ctx, +pendingproc_prepare_tp_connection (TplActionChain *ctx, gpointer user_data) { - TplChannel *tpl_chan = TPL_CHANNEL (_tpl_action_chain_get_object (ctx)); + TplChannel *chan = _tpl_action_chain_get_object (ctx); + TpConnection *conn = tp_channel_borrow_connection (TP_CHANNEL (chan)); + GQuark conn_features[] = { TP_CONNECTION_FEATURE_CORE, 0 }; - TPL_CHANNEL_GET_CLASS (tpl_chan)->call_when_ready_protected (tpl_chan, - got_tpl_chan_ready_cb, ctx); + tp_proxy_prepare_async (conn, conn_features, connection_prepared_cb, ctx); +} + + +static void +channel_prepared_cb (GObject *source, + GAsyncResult *result, + gpointer ctx) +{ + TplChannel *chan = _tpl_action_chain_get_object (ctx); + GError *error = NULL; + + if (!tp_proxy_prepare_finish (source, result, &error)) + { + _tpl_action_chain_terminate (ctx, error); + g_error_free (error); + return; + } + else if (!tp_proxy_has_interface_by_id (TP_PROXY (chan), + TP_IFACE_QUARK_CHANNEL_INTERFACE_MESSAGES)) + { + error = g_error_new (TPL_TEXT_CHANNEL_ERROR, + TPL_TEXT_CHANNEL_ERROR_NEED_MESSAGE_INTERFACE, + "The text channel does not implement Message interface."); + _tpl_action_chain_terminate (ctx, error); + g_error_free (error); + } + + _tpl_action_chain_continue (ctx); +} + + +static void +pendingproc_prepare_tp_text_channel (TplActionChain *ctx, + gpointer user_data) +{ + TplChannel *chan = _tpl_action_chain_get_object (ctx); + GQuark chan_features[] = { + TP_CHANNEL_FEATURE_CORE, + TP_CHANNEL_FEATURE_GROUP, + TP_TEXT_CHANNEL_FEATURE_INCOMING_MESSAGES, + 0 + }; + + /* user_data is a TplChannel instance */ + tp_proxy_prepare_async (chan, chan_features, channel_prepared_cb, ctx); } @@ -116,13 +167,16 @@ get_self_contact_cb (TpConnection *connection, { TpConnection *tp_conn = tp_channel_borrow_connection (tp_chan); const gchar *conn_path; + GError *new_error = NULL; conn_path = tp_proxy_get_object_path (TP_PROXY (tp_conn)); - PATH_DEBUG (tpl_text, "Error resolving self handle for connection %s." - " Aborting channel observation", conn_path); + new_error = g_error_new (error->domain, error->code, + "Error resolving self handle for connection %s: %s)", + conn_path, error->message); - _tpl_action_chain_terminate (ctx); + _tpl_action_chain_terminate (ctx, new_error); + g_error_free (new_error); return; } @@ -168,10 +222,13 @@ get_remote_contacts_cb (TpConnection *connection, if (error != NULL) { - DEBUG ("Failed to get remote contacts: %s", error->message); - if (ctx != NULL) - _tpl_action_chain_terminate (ctx); + { + GError *new_error = NULL; + new_error = g_error_new (error->domain, error->code, + "Failed to get remote contacts: %s", error->message); + _tpl_action_chain_terminate (ctx, error); + } return; } @@ -444,7 +501,7 @@ tpl_text_channel_store_message (TplTextChannel *self, /* Initialise TplTextEvent */ event = g_object_new (TPL_TYPE_TEXT_EVENT, /* TplEvent */ - "account", _tpl_channel_get_account (TPL_CHANNEL (self)), + "account", priv->account, "channel-path", tp_proxy_get_object_path (TP_PROXY (self)), "receiver", receiver, "sender", sender, @@ -538,33 +595,34 @@ pendingproc_connect_message_signals (TplActionChain *ctx, return; disaster: - DEBUG ("couldn't connect to signals: %s", error->message); - g_clear_error (&error); - _tpl_action_chain_terminate (ctx); + g_prefix_error (&error, "Couldn't connect to signals: "); + _tpl_action_chain_terminate (ctx, error); + g_error_free (error); +} + +static gboolean +tpl_text_channel_prepare_finish (TplChannel *chan, + GAsyncResult *result, + GError **error) +{ + return _tpl_action_chain_new_finish (G_OBJECT (chan), result, error); } static void -tpl_text_channel_call_when_ready (TplChannel *chan, - GAsyncReadyCallback cb, gpointer user_data) +tpl_text_channel_prepare_async (TplChannel *chan, + GAsyncReadyCallback cb, + gpointer user_data) { TplActionChain *actions; - /* first: connect signals, so none are lost - * second: prepare all TplChannel - * third: cache my contact and the remote one. - * last: connect to Message signals - * - * If for any reason, the order is changed, it's needed to check what objects - * are unreferenced by g_object_unref but used by a next action AND what - * object are actually not prepared but used anyway */ actions = _tpl_action_chain_new_async (G_OBJECT (chan), cb, user_data); - _tpl_action_chain_append (actions, pendingproc_prepare_tpl_channel, NULL); + _tpl_action_chain_append (actions, pendingproc_prepare_tp_connection, NULL); + _tpl_action_chain_append (actions, pendingproc_prepare_tp_text_channel, NULL); _tpl_action_chain_append (actions, pendingproc_get_my_contact, NULL); _tpl_action_chain_append (actions, pendingproc_get_remote_contacts, NULL); _tpl_action_chain_append (actions, pendingproc_connect_message_signals, NULL); - /* start the chain consuming */ _tpl_action_chain_continue (actions); } @@ -595,18 +653,23 @@ static void _tpl_text_channel_class_init (TplTextChannelClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - TplChannelClass *tpl_chan_class = TPL_CHANNEL_CLASS (klass); object_class->dispose = tpl_text_channel_dispose; object_class->finalize = tpl_text_channel_finalize; - tpl_chan_class->call_when_ready = tpl_text_channel_call_when_ready; - g_type_class_add_private (object_class, sizeof (TplTextChannelPriv)); } static void +tpl_text_channel_iface_init (TplChannelInterface *iface) +{ + iface->prepare_async = tpl_text_channel_prepare_async; + iface->prepare_finish = tpl_text_channel_prepare_finish; +} + + +static void _tpl_text_channel_init (TplTextChannel *self) { TplTextChannelPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, @@ -652,8 +715,9 @@ _tpl_text_channel_new (TpConnection *conn, GError **error) { TpProxy *conn_proxy = TP_PROXY (conn); + TplTextChannel *self; - /* Do what tpl_channel_new does + set TplTextChannel specific properties */ + /* Do what tpl_channel_new does + set TplTextChannel specific */ g_return_val_if_fail (TP_IS_CONNECTION (conn), NULL); g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); @@ -663,9 +727,7 @@ _tpl_text_channel_new (TpConnection *conn, if (!tp_dbus_check_valid_object_path (object_path, error)) return NULL; - return g_object_new (TPL_TYPE_TEXT_CHANNEL, - /* TplChannel properties */ - "account", account, + self = g_object_new (TPL_TYPE_TEXT_CHANNEL, /* TpChannel properties */ "connection", conn, "dbus-daemon", conn_proxy->dbus_daemon, @@ -674,4 +736,8 @@ _tpl_text_channel_new (TpConnection *conn, "handle-type", (guint) TP_UNKNOWN_HANDLE_TYPE, "channel-properties", tp_chan_props, NULL); + + self->priv->account = g_object_ref (account); + + return self; } |