[Telepathy-commits] [telepathy-gabble/master] Implement the "respawning" behaviour for IM channels with pending messages remaining
Simon McVittie
simon.mcvittie at collabora.co.uk
Tue Aug 19 10:53:58 PDT 2008
20080724144216-53eee-d2efd8bc914582f1b5c7e9b89ff810fb21e7e51b.gz
---
src/im-channel.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/im-factory.c | 30 ++++++++++++++++++++------
2 files changed, 82 insertions(+), 9 deletions(-)
diff --git a/src/im-channel.c b/src/im-channel.c
index 5971b44..a42f613 100644
--- a/src/im-channel.c
+++ b/src/im-channel.c
@@ -77,6 +77,7 @@ enum
PROP_REQUESTED,
PROP_CONNECTION,
PROP_INTERFACES,
+ PROP_WILL_RETURN,
LAST_PROPERTY
};
@@ -153,6 +154,30 @@ gabble_im_channel_constructor (GType type, guint n_props,
return obj;
}
+
+/* FIXME: this is a hack - we should add API for this to TpTextMixin */
+static gboolean
+gabble_im_channel_has_pending (GabbleIMChannel *self)
+{
+ GPtrArray *dummy = NULL;
+ gboolean ret;
+ guint i;
+
+ tp_text_mixin_list_pending_messages ((GObject *) self, FALSE,
+ &dummy, NULL);
+
+ g_assert (dummy != NULL);
+ ret = (dummy->len > 0);
+
+ for (i = 0; i < dummy->len; i++)
+ g_value_array_free (g_ptr_array_index (dummy, i));
+
+ g_ptr_array_free (dummy, TRUE);
+
+ return ret;
+}
+
+
static void
gabble_im_channel_get_property (GObject *object,
guint property_id,
@@ -206,6 +231,9 @@ gabble_im_channel_get_property (GObject *object,
case PROP_INTERFACES:
g_value_set_boxed (value, gabble_im_channel_interfaces);
break;
+ case PROP_WILL_RETURN:
+ g_value_set_boolean (value, gabble_im_channel_has_pending (chan));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -350,6 +378,14 @@ gabble_im_channel_class_init (GabbleIMChannelClass *gabble_im_channel_class)
g_object_class_install_property (object_class, PROP_INITIATOR_ID,
param_spec);
+ param_spec = g_param_spec_boolean ("will-return", "Will return?",
+ "True if this channel has pending messages, and so will reopen when "
+ "closed",
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NAME);
+ g_object_class_install_property (object_class, PROP_WILL_RETURN, param_spec);
+
tp_text_mixin_class_init (object_class,
G_STRUCT_OFFSET (GabbleIMChannelClass, text_class));
@@ -515,6 +551,29 @@ gabble_im_channel_close (TpSvcChannel *iface,
if (!priv->closed)
{
+ /* The IM factory will resurrect the channel if we have pending
+ * messages. When we're resurrected, we want the initiator
+ * to be the contact who sent us those messages, if it isn't already */
+ if (gabble_im_channel_has_pending (self))
+ {
+ if (priv->initiator != priv->handle)
+ {
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles
+ ((TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT);
+
+ g_assert (priv->initiator != 0);
+ g_assert (priv->handle != 0);
+
+ tp_handle_unref (contact_repo, priv->initiator);
+ priv->initiator = priv->handle;
+ tp_handle_ref (contact_repo, priv->initiator);
+ }
+ }
+ else
+ {
+ priv->closed = TRUE;
+ }
+
tp_svc_channel_emit_closed (self);
if (presence && (presence->caps & PRESENCE_CAP_CHAT_STATES))
@@ -526,8 +585,6 @@ gabble_im_channel_close (TpSvcChannel *iface,
TP_CHANNEL_CHAT_STATE_GONE, priv->peer_jid, NULL, priv->conn,
FALSE /* emit_signal */, NULL);
}
-
- priv->closed = TRUE;
}
tp_svc_channel_return_from_close (context);
diff --git a/src/im-factory.c b/src/im-factory.c
index 11775bd..17a7cec 100644
--- a/src/im-factory.c
+++ b/src/im-factory.c
@@ -289,22 +289,38 @@ im_factory_message_cb (LmMessageHandler *handler,
* im_channel_closed_cb:
*
* Signal callback for when an IM channel is closed. Removes the references
- * that #GabbleConnection holds to them.
+ * that #GabbleConnection holds to them - unless the channel has pending
+ * messages, in which case it is re-announced (so from the perspective of the
+ * D-Bus API, it was replaced by an identical channel).
*/
static void
im_channel_closed_cb (GabbleIMChannel *chan, gpointer user_data)
{
- GabbleImFactory *conn = GABBLE_IM_FACTORY (user_data);
- GabbleImFactoryPrivate *priv = GABBLE_IM_FACTORY_GET_PRIVATE (conn);
+ GabbleImFactory *self = GABBLE_IM_FACTORY (user_data);
+ GabbleImFactoryPrivate *priv = GABBLE_IM_FACTORY_GET_PRIVATE (self);
TpHandle contact_handle;
+ gboolean will_return;
if (priv->channels)
{
- g_object_get (chan, "handle", &contact_handle, NULL);
+ g_object_get (chan,
+ "handle", &contact_handle,
+ "will-return", &will_return,
+ NULL);
- DEBUG ("removing channel with handle %d", contact_handle);
-
- g_hash_table_remove (priv->channels, GINT_TO_POINTER (contact_handle));
+ if (will_return)
+ {
+ DEBUG ("reopening channel with handle %u due to pending messages",
+ contact_handle);
+ tp_channel_factory_iface_emit_new_channel (self,
+ (TpChannelIface *) chan, NULL);
+ }
+ else
+ {
+ DEBUG ("removing channel with handle %u", contact_handle);
+ g_hash_table_remove (priv->channels,
+ GUINT_TO_POINTER (contact_handle));
+ }
}
}
--
1.5.6.3
More information about the Telepathy-commits
mailing list