[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