[telepathy-gabble/master] Correctly handle caps from bare JIDs.

Will Thompson will.thompson at collabora.co.uk
Tue Jun 16 09:42:52 PDT 2009


---
 src/presence.c                      |   21 +++++++
 tests/twisted/Makefile.am           |    1 +
 tests/twisted/caps/from-bare-jid.py |  112 +++++++++++++++++++++++++++++++++++
 3 files changed, 134 insertions(+), 0 deletions(-)
 create mode 100644 tests/twisted/caps/from-bare-jid.py

diff --git a/src/presence.c b/src/presence.c
index 744fcd7..300cbc8 100644
--- a/src/presence.c
+++ b/src/presence.c
@@ -206,6 +206,18 @@ gabble_presence_set_capabilities (GabblePresence *presence,
   GabblePresencePrivate *priv = GABBLE_PRESENCE_PRIV (presence);
   GSList *i;
 
+  if (resource == NULL && priv->resources != NULL)
+    {
+      /* This is consistent with the handling of presence: if we get presence
+       * from a bare JID, we throw away all the resources, and if we get
+       * presence from a resource, any presence we stored from a bare JID is
+       * overridden by the aggregated presence.
+       */
+      DEBUG ("Ignoring caps for NULL resource since we have presence for "
+        "some resources");
+      return;
+    }
+
   presence->caps = 0;
   if (presence->per_channel_manager_caps != NULL)
     {
@@ -215,6 +227,15 @@ gabble_presence_set_capabilities (GabblePresence *presence,
     }
   presence->per_channel_manager_caps = g_hash_table_new (NULL, NULL);
 
+  if (resource == NULL)
+    {
+      DEBUG ("adding caps %u to bare jid", caps);
+      presence->caps = caps;
+      gabble_presence_cache_update_cache_entry (
+          presence->per_channel_manager_caps, per_channel_manager_caps);
+      return;
+    }
+
   DEBUG ("about to add caps %u to resource %s with serial %u", caps, resource,
     serial);
 
diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am
index 209bbaa..9e7b0d8 100644
--- a/tests/twisted/Makefile.am
+++ b/tests/twisted/Makefile.am
@@ -1,5 +1,6 @@
 TWISTED_TESTS = \
 	avatar-requirements.py \
+	caps/from-bare-jid.py \
 	muc/name-conflict.py \
 	muc/renamed.py \
 	muc/roomlist.py \
diff --git a/tests/twisted/caps/from-bare-jid.py b/tests/twisted/caps/from-bare-jid.py
new file mode 100644
index 0000000..8e86c9a
--- /dev/null
+++ b/tests/twisted/caps/from-bare-jid.py
@@ -0,0 +1,112 @@
+"""
+Tests receiving capabilities from bare JIDs.
+"""
+
+from twisted.words.xish import xpath
+
+from servicetest import (
+    assertEquals, assertContains, assertDoesNotContain, EventPattern,
+    )
+from gabbletest import make_presence, exec_test
+from caps_helper import compute_caps_hash, make_caps_disco_reply
+import constants as cs
+import ns
+
+def test(q, bus, conn, stream):
+    conn.Connect()
+    q.expect('dbus-signal', signal='StatusChanged',
+        args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
+
+    client = 'http://example.com/perverse-client'
+    contact_bare_jid = 'edgecase at example.com'
+    contact_with_resource = 'edgecase at example.com/hi'
+    contact_handle = conn.RequestHandles(cs.HT_CONTACT, [contact_bare_jid])[0]
+
+    # Gabble gets a presence stanza from a bare JID, which is a tad surprising.
+    features = [
+        'http://jabber.org/protocol/jingle',
+        'http://jabber.org/protocol/jingle/description/audio',
+        'http://www.google.com/transport/p2p',
+        ]
+    caps = {'node': client,
+            'hash': 'sha-1',
+            'ver': compute_caps_hash([], features, {}),
+           }
+    p = make_presence(contact_bare_jid, status='Hello', caps=caps)
+    stream.send(p)
+
+    # Gabble looks up the hash
+    event = q.expect('stream-iq', to=contact_bare_jid,
+        query_ns='http://jabber.org/protocol/disco#info')
+    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
+    assertEquals(client + '#' + caps['ver'], query_node.attributes['node'])
+
+    # The bare jid replies
+    result = make_caps_disco_reply(stream, event.stanza, features, {})
+    stream.send(result)
+
+    # Gabble lets us know their caps have changed. (Gabble used to ignore the
+    # reply.)
+    streamed_media_caps = (contact_handle, cs.CHANNEL_TYPE_STREAMED_MEDIA,
+        0, 3, 0, 1)
+    e = q.expect('dbus-signal', signal='CapabilitiesChanged')
+    assertContains(streamed_media_caps, e.args[0])
+
+    # Gabble gets another presence stanza from the bare JID, with different
+    # caps.
+    features.append(ns.TUBES)
+    caps = {'node': client,
+            'hash': 'sha-1',
+            'ver': compute_caps_hash([], features, {}),
+           }
+    p = make_presence(contact_bare_jid, status='Get out the abacus', caps=caps)
+    stream.send(p)
+
+    # Gabble looks up the new hash
+    disco2 = q.expect('stream-iq', to=contact_bare_jid,
+        query_ns='http://jabber.org/protocol/disco#info')
+    query_node = xpath.queryForNodes('/iq/query', disco2.stanza)[0]
+    assertEquals(client + '#' + caps['ver'], query_node.attributes['node'])
+
+    # This time, before the bare JID replies, Gabble gets a presence from the
+    # resourceful jid.
+    features_ = features + [ns.CHAT_STATES]
+    caps = {'node': client,
+            'hash': 'sha-1',
+            'ver': compute_caps_hash([], features_, {}),
+           }
+    p = make_presence(contact_with_resource, status='Count this', caps=caps)
+    stream.send(p)
+
+    # Gabble throws away presence from the bare JID when it gets presence from
+    # a resource (and vice versa), so it should now say the contact is
+    # incapable.  Gabble also looks up the resourceful JID's hash.
+    cc, disco3 = q.expect_many(
+        EventPattern('dbus-signal', signal='CapabilitiesChanged'),
+        EventPattern('stream-iq', to=contact_with_resource,
+            query_ns='http://jabber.org/protocol/disco#info'),
+        )
+
+    assertDoesNotContain(streamed_media_caps, cc.args[0])
+
+    query_node = xpath.queryForNodes('/iq/query', disco3.stanza)[0]
+    assertEquals(client + '#' + caps['ver'], query_node.attributes['node'])
+
+    # The bare jid replies! Getting a disco reply from a bare JID when we've
+    # got presence from resources used to crash Gabble, but now it just ignores
+    # it.
+    result = make_caps_disco_reply(stream, disco2.stanza, features, {})
+    stream.send(result)
+
+    # Now the resourceful JID replies:
+    result = make_caps_disco_reply(stream, disco3.stanza, features_, {})
+    stream.send(result)
+
+    # Gabble should announce that the contact has acquired some caps.
+    e = q.expect('dbus-signal', signal='CapabilitiesChanged')
+    assertContains(streamed_media_caps, e.args[0])
+
+    conn.Disconnect()
+
+if __name__ == '__main__':
+    exec_test(test)
-- 
1.5.6.5




More information about the telepathy-commits mailing list