[telepathy-gabble/master] Upgrade ContactCapabilities spec to draft 2

Simon McVittie simon.mcvittie at collabora.co.uk
Wed Aug 26 10:21:00 PDT 2009


---
 .../Connection_Interface_Contact_Capabilities.xml  |  150 +++++++++++++++-----
 extensions/all.xml                                 |    4 +
 src/connection.c                                   |  108 +++++++++++----
 tests/twisted/Makefile.am                          |    2 +-
 .../{advertise-draft1.py => advertise-draft2.py}   |  145 +++++++++----------
 tests/twisted/constants.py                         |    4 +-
 6 files changed, 276 insertions(+), 137 deletions(-)
 rename tests/twisted/caps/{advertise-draft1.py => advertise-draft2.py} (53%)

diff --git a/extensions/Connection_Interface_Contact_Capabilities.xml b/extensions/Connection_Interface_Contact_Capabilities.xml
index e06ab01..d5ccebf 100644
--- a/extensions/Connection_Interface_Contact_Capabilities.xml
+++ b/extensions/Connection_Interface_Contact_Capabilities.xml
@@ -18,9 +18,11 @@ Lesser General Public License for more details.</p>
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</p>
   </tp:license>
-  <interface name="org.freedesktop.Telepathy.Connection.Interface.ContactCapabilities.DRAFT">
+  <interface name="org.freedesktop.Telepathy.Connection.Interface.ContactCapabilities.DRAFT2"
+    tp:causes-havoc="experimental">
     <tp:requires interface="org.freedesktop.Telepathy.Connection"/>
     <tp:added version="0.17.16">(as a draft)</tp:added>
+    <tp:changed version="0.17.27">(draft 2)</tp:changed>
 
     <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
       <p>Contact capabilities describe the channel classes which may be
@@ -37,38 +39,77 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
       <p>This interface also enables user interfaces to notify the connection
         manager what capabilities to advertise for the user to other contacts.
         This is done by using the
-        <tp:member-ref>SetSelfCapabilities</tp:member-ref> method, and deals
-        with channel property values pertaining to them which are implemented
-        by available client processes.</p>
+        <tp:member-ref>UpdateCapabilities</tp:member-ref> method.</p>
 
+      <tp:rationale>
+        <p>XMPP is a major user of this interface: XMPP contacts will not,
+          in general, be callable using VoIP unless they advertise suitable
+          Jingle capabilities.</p>
+
+        <p>Many other protocols also have some concept of capability flags,
+          which this interface exposes in a protocol-independent way.</p>
+      </tp:rationale>
     </tp:docstring>
 
-    <method name="SetSelfCapabilities"
-            tp:name-for-bindings="Set_Self_Capabilities">
-      <arg direction="in" name="caps" type="aa{sv}"
+    <tp:struct name="Handler_Capabilities"
+      array-name="Handler_Capabilities_List">
+      <tp:docstring>
+        A structure representing the capabilities of a single client.
+      </tp:docstring>
+
+      <tp:member name="Well_Known_Name" type="s" tp:type="DBus_Well_Known_Name">
+        <tp:docstring>
+          For implementations of the <tp:dbus-ref
+            namespace="org.freedesktop.Telepathy">Client</tp:dbus-ref>
+          interface, the well-known bus name name of the client; for any other
+          process, any other reversed domain name that uniquely identifies it.
+        </tp:docstring>
+      </tp:member>
+
+      <tp:member name="Channel_Classes" type="aa{sv}"
            tp:type="String_Variant_Map[]">
         <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
-          An array of channel classes to replace to the list of what the
-          connection can handle. If you include optional properties, they
-          may not get advertised. The given properties are matched to the
-          mandatory properties.
+          An array of channel classes that can be handled by this client.
+          This will usually be a copy of the client's <tp:dbus-ref
+            namespace="org.freedesktop.Telepathy.Client.Handler">HandlerChannelFilter</tp:dbus-ref>
+          property.
         </tp:docstring>
-      </arg>
-      <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
-        <p>Used by user interfaces to indicate which channel classes they are
-        able to handle on this connection. It replaces the previous advertised
-        channel classes by the set given as parameter.</p>
+      </tp:member>
 
-        <p>If a channel class is unknown by the connection manager, it is just
-        ignored. No error are returned in this case, and other known channel
-        class are added.</p>
+      <tp:member name="Capabilities"
+        type="as" tp:type="Handler_Capability_Token[]">
+        <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+          An array of client capabilities supported by this client, to be
+          used by the connection manager to determine what capabilities to
+          advertise. This will usually be a copy of the client's <tp:dbus-ref
+            namespace="org.freedesktop.Telepathy.Client.Handler">Capabilities</tp:dbus-ref>
+          property.
+        </tp:docstring>
+      </tp:member>
+    </tp:struct>
 
-        <p>Upon a successful invocation of this method, the
-        <tp:member-ref>ContactCapabilitiesChanged</tp:member-ref> signal
-        will only be emitted for the user's own
-        handle (as returned by GetSelfHandle) by the connection manager if, in
-        the given protocol, the given capabilities are distinct from the
-        previous state.</p>
+    <method name="UpdateCapabilities" tp:name-for-bindings="Update_Capabilities">
+      <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+        <p>Alter the connection's advertised capabilities to include
+          the intersection of the given clients' capabilities with what the
+          connection manager is able to implement.</p>
+
+        <p>On connections managed by the ChannelDispatcher, processes other
+          than the ChannelDispatcher SHOULD NOT call this method, and the
+          ChannelDispatcher SHOULD use this method to advertise the
+          capabilities of all the registered <tp:dbus-ref
+            namespace="org.freedesktop.Telepathy">Client.Handler</tp:dbus-ref>
+          implementations.On connections not managed by the ChannelDispatcher,
+          clients MAY use this method directly, to indicate the channels they
+          will handle and the extra capabilities they have.</p>
+
+        <p>Upon a successful invocation of this method, the connection manager
+          will only emit the
+          <tp:member-ref>ContactCapabilitiesChanged</tp:member-ref> signal
+          for the user's <tp:dbus-ref
+            namespace="org.freedesktop.Telepathy.Connection">SelfHandle</tp:dbus-ref>
+          if, in the underlying protocol, the new capabilities are distinct
+          from the previous state.</p>
 
         <tp:rationale>
           <p>The connection manager will essentially intersect the provided
@@ -78,10 +119,45 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
             channel) will almost certainly not be advertised.</p>
         </tp:rationale>
 
+        <p>This method MAY be called on a newly-created connection while it
+          is still in the DISCONNECTED state, to request that when the
+          connection connects, it will do so with the appropriate
+          capabilities. Doing so MUST NOT fail.</p>
       </tp:docstring>
+
+      <arg direction="in" name="Handler_Capabilities" type="a(saa{sv}as)"
+        tp:type="Handler_Capabilities[]">
+        <tp:docstring>
+          <p>The capabilities of one or more clients.</p>
+
+          <p>For each client in the given list, any capabilities previously
+            advertised for the same client name are discarded, then replaced by
+            the capabilities indicated.</p>
+
+          <p>As a result, if a client becomes unavailable, this method SHOULD
+            be called with a <tp:type>Handler_Capabilities</tp:type> structure
+            containing its name, an empty list of channel classes, and an
+            empty list of capabilities. When this is done, the connection
+            manager SHOULD free all memory associated with that client name.</p>
+
+          <tp:rationale>
+            <p>This method takes a list of clients so that
+              when the channel dispatcher first calls it (with a list of all
+              the Handlers that are initially available), the changes can be
+              made atomically, with only one transmission of updated
+              capabilities to the network. Afterwards, the channel dispatcher
+              will call this method with a single-element list every time
+              a Handler becomes available or unavailable.</p>
+          </tp:rationale>
+
+          <p>The connection manager MUST ignore any channel classes and client
+            capabilities for which there is no representation in the protocol
+            or no support in the connection manager.</p>
+        </tp:docstring>
+      </arg>
+
       <tp:possible-errors>
         <tp:error name="org.freedesktop.Telepathy.Error.NetworkError"/>
-        <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/>
       </tp:possible-errors>
     </method>
 
@@ -94,13 +170,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
           <p>The handle zero MUST NOT be included in the request.</p>
         </tp:docstring>
       </arg>
-      <!-- There was a bug in dbus-glib that prevent to use the right type:
-           Instead of a{ua(a{sv}as)}, we used a(ua{sv}as) as a workaround.
-           See http://bugs.freedesktop.org/show_bug.cgi?id=17329
-           Now there is a fix, so we don't use the workaround anymore.
-        -->
-      <arg direction="out" type="a{ua(a{sv}as)}" name="Contact_Capabilities"
-           tp:type="Contact_Capabilities_Map">
+      <arg direction="out" type="a{ua(a{sv}as)}"
+           tp:type="Contact_Capabilities_Map" name="Contact_Capabilities">
         <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
           An array of structures containing:
           <ul>
@@ -139,7 +210,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
           <p>The underlying protocol can get several contacts' capabilities at
             the same time.</p>
         </tp:rationale>
-        
+
       </tp:docstring>
     </signal>
 
@@ -160,6 +231,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
     </tp:member>
   </tp:mapping>
 
+    <tp:contact-attribute name="capabilities"
+      type="a(a{sv}as)" tp:type="Requestable_Channel_Class[]">
+      <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+        <p>The same structs that would be returned by
+          <tp:member-ref>GetContactCapabilities</tp:member-ref>.
+          Omitted from the result if the contact's capabilities
+          are not known; present in the result as an empty array if the
+          contact is known to have no capabilities at all.</p>
+      </tp:docstring>
+    </tp:contact-attribute>
+
   </interface>
 </node>
 <!-- vim:set sw=2 sts=2 et ft=xml: -->
diff --git a/extensions/all.xml b/extensions/all.xml
index 203961c..10c0db7 100644
--- a/extensions/all.xml
+++ b/extensions/all.xml
@@ -57,6 +57,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA</p>
     from="Telepathy specification"/>
   <tp:external-type name="DBus_Error_Name" type="s"
     from="Telepathy specification"/>
+  <tp:external-type name="DBus_Well_Known_Name" type="s"
+    from="Telepathy specification"/>
+  <tp:external-type name="Handler_Capability_Token" type="s"
+    from="Telepathy specification"/>
 
   <!-- for localisation -->
   <tp:external-type name="Rich_Presence_Access_Control_Type" type="u"
diff --git a/src/connection.c b/src/connection.c
index 6b627d0..e4c1e12 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -204,8 +204,8 @@ struct _GabbleConnectionPrivate
   GabbleCapabilitySet *all_caps;
   GabbleCapabilitySet *notify_caps;
   GabbleCapabilitySet *legacy_caps;
-  GabbleCapabilitySet *draft1_caps;
   GabbleCapabilitySet *bonus_caps;
+  GHashTable *client_caps;
 
   /* gobject housekeeping */
   gboolean dispose_has_run;
@@ -327,7 +327,8 @@ gabble_connection_constructor (GType type,
   priv->all_caps = gabble_capability_set_new ();
   priv->notify_caps = gabble_capability_set_new ();
   priv->legacy_caps = gabble_capability_set_new ();
-  priv->draft1_caps = gabble_capability_set_new ();
+  priv->client_caps = g_hash_table_new_full (g_str_hash, g_str_equal,
+      g_free, (GDestroyNotify) gabble_capability_set_free);
 
   /* Historically, the optional Jingle transports were in our initial
    * presence, but could be removed by AdvertiseCapabilities(). Emulate
@@ -932,10 +933,10 @@ gabble_connection_dispose (GObject *object)
    */
   g_idle_add (_unref_lm_connection, self->lmconn);
 
+  g_hash_table_destroy (priv->client_caps);
   gabble_capability_set_free (priv->all_caps);
   gabble_capability_set_free (priv->notify_caps);
   gabble_capability_set_free (priv->legacy_caps);
-  gabble_capability_set_free (priv->draft1_caps);
   gabble_capability_set_free (priv->bonus_caps);
 
   if (G_OBJECT_CLASS (gabble_connection_parent_class)->dispose)
@@ -1595,6 +1596,8 @@ static gboolean
 gabble_connection_refresh_capabilities (GabbleConnection *self)
 {
   GError *error = NULL;
+  GHashTableIter iter;
+  gpointer k, v;
 
   gabble_capability_set_clear (self->priv->all_caps);
 
@@ -1602,9 +1605,23 @@ gabble_connection_refresh_capabilities (GabbleConnection *self)
       gabble_capabilities_get_fixed_caps ());
   gabble_capability_set_update (self->priv->all_caps, self->priv->notify_caps);
   gabble_capability_set_update (self->priv->all_caps, self->priv->legacy_caps);
-  gabble_capability_set_update (self->priv->all_caps, self->priv->draft1_caps);
   gabble_capability_set_update (self->priv->all_caps, self->priv->bonus_caps);
 
+  g_hash_table_iter_init (&iter, self->priv->client_caps);
+
+  while (g_hash_table_iter_next (&iter, &k, &v))
+    {
+      if (DEBUGGING)
+        {
+          gchar *s = gabble_capability_set_dump (v, "  ");
+
+          DEBUG ("incorporating caps for %s:\n%s", (const gchar *) k, s);
+          g_free (s);
+        }
+
+      gabble_capability_set_update (self->priv->all_caps, v);
+    }
+
   if (gabble_presence_resource_has_caps (self->self_presence,
         self->priv->resource, gabble_capability_set_predicate_equals,
         self->priv->all_caps))
@@ -2392,7 +2409,7 @@ _emit_capabilities_changed (GabbleConnection *conn,
     }
   g_ptr_array_free (caps_arr, TRUE);
 
-  /* ContactCapabilities (draft 1) */
+  /* ContactCapabilities (draft 2) */
 
   caps_arr = g_ptr_array_new ();
 
@@ -2591,48 +2608,85 @@ gabble_connection_advertise_capabilities (TpSvcConnectionInterfaceCapabilities *
 }
 
 /**
- * gabble_connection_set_self_capabilities
+ * gabble_connection_update_capabilities
  *
- * Implements D-Bus method SetSelfCapabilities
+ * Implements D-Bus method UpdateCapabilities
  * on interface
  * org.freedesktop.Telepathy.Connection.Interface.ContactCapabilities
- *
- * @error: Used to return a pointer to a GError detailing any error
- *         that occurred, D-Bus will throw the error only if this
- *         function returns FALSE.
- *
- * Returns: TRUE if successful, FALSE if an error was thrown.
  */
 static void
-gabble_connection_set_self_capabilities (
+gabble_connection_update_capabilities (
     GabbleSvcConnectionInterfaceContactCapabilities *iface,
-    const GPtrArray *caps,
+    const GPtrArray *clients,
     DBusGMethodInvocation *context)
 {
-  static const gchar *null_string = NULL;
   GabbleConnection *self = GABBLE_CONNECTION (iface);
   TpBaseConnection *base = (TpBaseConnection *) self;
   GabbleCapabilitySet *old_caps;
   TpChannelManagerIter iter;
   TpChannelManager *manager;
+  guint i;
 
   TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
 
   old_caps = gabble_capability_set_copy (self->priv->all_caps);
 
-  gabble_capability_set_clear (self->priv->draft1_caps);
+  /* Now that someone has told us our *actual* capabilities, we can stop
+   * advertising spurious caps in initial presence */
+  gabble_capability_set_clear (self->priv->bonus_caps);
 
-  tp_base_connection_channel_manager_iter_init (&iter, base);
+  DEBUG ("enter");
 
-  while (tp_base_connection_channel_manager_iter_next (&iter, &manager))
+  for (i = 0; i < clients->len; i++)
     {
-      /* all channel managers must implement the capability interface */
-      g_assert (GABBLE_IS_CAPS_CHANNEL_MANAGER (manager));
+      GValueArray *va = g_ptr_array_index (clients, i);
+      const gchar *client_name = g_value_get_string (va->values + 0);
+      const GPtrArray *filters = g_value_get_boxed (va->values + 1);
+      const gchar * const * cap_tokens = g_value_get_boxed (va->values + 2);
+      GabbleCapabilitySet *cap_set;
+
+      g_hash_table_remove (self->priv->client_caps, client_name);
+
+      if ((cap_tokens == NULL || cap_tokens[0] != NULL) &&
+          filters->len == 0)
+        {
+          /* no capabilities */
+          DEBUG ("client %s can't do anything", client_name);
+          continue;
+        }
+
+      cap_set = gabble_capability_set_new ();
+
+      tp_base_connection_channel_manager_iter_init (&iter, base);
+
+      while (tp_base_connection_channel_manager_iter_next (&iter, &manager))
+        {
+          /* all channel managers must implement the capability interface */
+          g_assert (GABBLE_IS_CAPS_CHANNEL_MANAGER (manager));
+
+          gabble_caps_channel_manager_represent_client (
+              GABBLE_CAPS_CHANNEL_MANAGER (manager), client_name, filters,
+              cap_tokens, cap_set);
+        }
+
+      if (gabble_capability_set_is_empty (cap_set))
+        {
+          DEBUG ("client %s has no interesting capabilities", client_name);
+          gabble_capability_set_free (cap_set);
+        }
+      else
+        {
+          if (DEBUGGING)
+            {
+              gchar *s = gabble_capability_set_dump (cap_set, "  ");
 
-      gabble_caps_channel_manager_represent_client (
-          GABBLE_CAPS_CHANNEL_MANAGER (manager),
-          "<ContactCapabilities.DRAFT1>", caps, &null_string,
-          self->priv->draft1_caps);
+              DEBUG ("client %s contributes:\n%s", client_name, s);
+              g_free (s);
+            }
+
+          g_hash_table_insert (self->priv->client_caps, g_strdup (client_name),
+              cap_set);
+        }
     }
 
   if (gabble_connection_refresh_capabilities (self))
@@ -2641,7 +2695,7 @@ gabble_connection_set_self_capabilities (
           self->priv->all_caps);
     }
 
-  gabble_svc_connection_interface_contact_capabilities_return_from_set_self_capabilities (
+  gabble_svc_connection_interface_contact_capabilities_return_from_update_capabilities (
       context);
 
   gabble_capability_set_free (old_caps);
@@ -3369,7 +3423,7 @@ gabble_conn_contact_caps_iface_init (gpointer g_iface, gpointer iface_data)
     gabble_svc_connection_interface_contact_capabilities_implement_##x (\
     klass, gabble_connection_##x)
   IMPLEMENT(get_contact_capabilities);
-  IMPLEMENT(set_self_capabilities);
+  IMPLEMENT(update_capabilities);
 #undef IMPLEMENT
 }
 
diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am
index 0ea0a8c..ed52f27 100644
--- a/tests/twisted/Makefile.am
+++ b/tests/twisted/Makefile.am
@@ -1,7 +1,7 @@
 TWISTED_TESTS = \
 	avatar-requirements.py \
 	caps_helper.py \
-	caps/advertise-draft1.py \
+	caps/advertise-draft2.py \
 	caps/advertise-legacy.py \
 	caps/caps-cache.py \
 	caps/compat-bundles.py \
diff --git a/tests/twisted/caps/advertise-draft1.py b/tests/twisted/caps/advertise-draft2.py
similarity index 53%
rename from tests/twisted/caps/advertise-draft1.py
rename to tests/twisted/caps/advertise-draft2.py
index c6befc8..971c8cc 100644
--- a/tests/twisted/caps/advertise-draft1.py
+++ b/tests/twisted/caps/advertise-draft2.py
@@ -1,5 +1,5 @@
 """
-Test SetSelfCapabilities.
+Test UpdateCapabilities.
 """
 
 import dbus
@@ -22,6 +22,9 @@ def noop_presence_update(q, stream):
     sync_stream(q, stream)
     #q.unforbid_events(events)
 
+JINGLE_CAPS_EXCEPT_GVIDEO = [n for n in JINGLE_CAPS
+    if n != ns.GOOGLE_FEAT_VIDEO]
+
 def run_test(q, bus, conn, stream):
     conn.Connect()
 
@@ -31,124 +34,118 @@ def run_test(q, bus, conn, stream):
             EventPattern('stream-presence'),
             )
 
-    # This method call looks wrong, but it's "the other side" of
-    # test/twisted/capabilities/draft-1.py in MC 5.1 - MC doesn't know
-    # how to map Client capabilities into the old Capabilities interface.
-    add = [(cs.CHANNEL_TYPE_STREAMED_MEDIA, 2L**32-1),
-            (cs.CHANNEL_TYPE_STREAM_TUBE, 2L**32-1)]
-    remove = []
-    caps = conn.Capabilities.AdvertiseCapabilities(add, remove)
-    (disco_response, namespaces, _) = receive_presence_and_ask_caps(q, stream,
-            False)
-    check_caps(namespaces, JINGLE_CAPS)
-    # Immediately afterwards, we get SetSelfCapabilities, for which a
-    # more comprehensive test exists in tube-caps.py.
-    conn.ContactCapabilities.SetSelfCapabilities([
+    conn.ContactCapabilities.UpdateCapabilities([
+        (cs.CLIENT + '.AbiWord', [
         { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
             cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
             cs.STREAM_TUBE_SERVICE: 'x-abiword' },
         { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
             cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
             cs.STREAM_TUBE_SERVICE: 'x-abiword' },
+        ], []),
+        (cs.CLIENT + '.KCall', [
         { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA },
+        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA,
+            cs.INITIAL_AUDIO: True},
+        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA,
+            cs.INITIAL_VIDEO: True},
+        ], [
+            cs.CHANNEL_IFACE_MEDIA_SIGNALLING + '/gtalk-p2p',
+            cs.CHANNEL_IFACE_MEDIA_SIGNALLING + '/ice-udp',
+            cs.CHANNEL_IFACE_MEDIA_SIGNALLING + '/video/h264',
+            ]),
         ])
     (disco_response, namespaces, _) = receive_presence_and_ask_caps(q, stream,
             False)
     check_caps(namespaces, JINGLE_CAPS + [ns.TUBES + '/stream#x-abiword'])
 
-    # Remove all our caps again
-    add = []
-    remove = [cs.CHANNEL_TYPE_STREAMED_MEDIA,
-            cs.CHANNEL_TYPE_STREAM_TUBE]
-    caps = conn.Capabilities.AdvertiseCapabilities(add, remove)
+    # Removing our H264 codec removes our ability to do Google Video
+    conn.ContactCapabilities.UpdateCapabilities([
+        (cs.CLIENT + '.KCall', [
+        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA },
+        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA,
+            cs.INITIAL_AUDIO: True},
+        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA,
+            cs.INITIAL_VIDEO: True},
+        ], [
+            cs.CHANNEL_IFACE_MEDIA_SIGNALLING + '/gtalk-p2p',
+            cs.CHANNEL_IFACE_MEDIA_SIGNALLING + '/ice-udp',
+            ]),
+        ])
+    (disco_response, namespaces, _) = receive_presence_and_ask_caps(q, stream,
+            False)
+    check_caps(namespaces,
+            JINGLE_CAPS_EXCEPT_GVIDEO + [ns.TUBES + '/stream#x-abiword'])
+
+    # Remove AbiWord's caps
+    conn.ContactCapabilities.UpdateCapabilities([
+        (cs.CLIENT + '.AbiWord', [], []),
+        ])
     (disco_response, namespaces, _) = receive_presence_and_ask_caps(q, stream,
             False)
-    check_caps(namespaces, [ns.TUBES + '/stream#x-abiword'])
-    conn.ContactCapabilities.SetSelfCapabilities([])
+    check_caps(namespaces, JINGLE_CAPS_EXCEPT_GVIDEO)
+
+    # Remove KCall's caps too
+    conn.ContactCapabilities.UpdateCapabilities([
+        (cs.CLIENT + '.KCall', [], []),
+        ])
     (disco_response, namespaces, _) = receive_presence_and_ask_caps(q, stream,
             False)
     check_caps(namespaces, [])
 
-    # Add caps selectively (i.e. what a client that actually understood the
-    # old Capabilities interface would do). With AUDIO and GTALK_P2P, we're
-    # callable, but not via ICE-UDP, and not with video.
+    # Add caps selectively. Here we're callable, but not via ICE-UDP, and not
+    # with video.
     #
     # (Jingle and raw UDP need no special client support, so are automatically
     # enabled whenever we can do audio or video.)
-    add = [(cs.CHANNEL_TYPE_STREAMED_MEDIA,
-        cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_GTALKP2P)]
-    remove = []
-    caps = conn.Capabilities.AdvertiseCapabilities(add, remove)
+    conn.ContactCapabilities.UpdateCapabilities([
+        (cs.CLIENT + '.KCall', [
+        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA },
+        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA,
+            cs.INITIAL_AUDIO: True},
+        ], [cs.CHANNEL_IFACE_MEDIA_SIGNALLING + '/gtalk-p2p']),
+        ])
     (disco_response, namespaces, _) = receive_presence_and_ask_caps(q, stream,
             False)
     check_caps(namespaces,
             [ns.GOOGLE_P2P, ns.JINGLE_TRANSPORT_RAWUDP, ns.JINGLE,
                 ns.JINGLE_015, ns.GOOGLE_FEAT_VOICE, ns.JINGLE_RTP_AUDIO,
                 ns.JINGLE_RTP, ns.JINGLE_015_AUDIO])
-    # the call to SSC has no effect here
-    conn.ContactCapabilities.SetSelfCapabilities([
-        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA },
-        ])
-    noop_presence_update(q, stream)
-
-    # Remove all our caps again
-    add = []
-    remove = [cs.CHANNEL_TYPE_STREAMED_MEDIA,
-            cs.CHANNEL_TYPE_STREAM_TUBE]
-    caps = conn.Capabilities.AdvertiseCapabilities(add, remove)
-    (disco_response, namespaces, _) = receive_presence_and_ask_caps(q, stream,
-            False)
-    check_caps(namespaces, [])
-    # the call to SSC has no effect here
-    conn.ContactCapabilities.SetSelfCapabilities([])
-    noop_presence_update(q, stream)
 
     # With AUDIO but no transport, we are only callable via raw UDP, which
     # Google clients cannot do.
-    add = [(cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.MEDIA_CAP_AUDIO)]
-    remove = []
-    caps = conn.Capabilities.AdvertiseCapabilities(add, remove)
+    conn.ContactCapabilities.UpdateCapabilities([
+        (cs.CLIENT + '.KCall', [
+        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA },
+        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA,
+            cs.INITIAL_AUDIO: True},
+        ], [])
+        ])
     (disco_response, namespaces, _) = receive_presence_and_ask_caps(q, stream,
             False)
     check_caps(namespaces,
             [ns.JINGLE_TRANSPORT_RAWUDP, ns.JINGLE,
                 ns.JINGLE_015, ns.JINGLE_RTP_AUDIO,
                 ns.JINGLE_RTP, ns.JINGLE_015_AUDIO])
-    # the call to SSC has no effect here
-    conn.ContactCapabilities.SetSelfCapabilities([
-        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA },
-        ])
-    noop_presence_update(q, stream)
-
-    # Remove all our caps again
-    add = []
-    remove = [cs.CHANNEL_TYPE_STREAMED_MEDIA,
-            cs.CHANNEL_TYPE_STREAM_TUBE]
-    caps = conn.Capabilities.AdvertiseCapabilities(add, remove)
-    (disco_response, namespaces, _) = receive_presence_and_ask_caps(q, stream,
-            False)
-    check_caps(namespaces, [])
-    # the call to SSC has no effect here
-    conn.ContactCapabilities.SetSelfCapabilities([])
-    noop_presence_update(q, stream)
 
     # With VIDEO and ICE-UDP only, we are very futuristic indeed.
     # Google clients cannot interop with us.
-    add = [(cs.CHANNEL_TYPE_STREAMED_MEDIA,
-        cs.MEDIA_CAP_VIDEO | cs.MEDIA_CAP_ICEUDP)]
-    remove = []
-    caps = conn.Capabilities.AdvertiseCapabilities(add, remove)
+    conn.ContactCapabilities.UpdateCapabilities([
+        (cs.CLIENT + '.KCall', [
+        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA },
+        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA,
+            cs.INITIAL_VIDEO: True},
+        ], [
+            cs.CHANNEL_IFACE_MEDIA_SIGNALLING + '/ice-udp',
+            cs.CHANNEL_IFACE_MEDIA_SIGNALLING + '/video/theora',
+            ]),
+        ])
     (disco_response, namespaces, _) = receive_presence_and_ask_caps(q, stream,
             False)
     check_caps(namespaces,
             [ns.JINGLE_TRANSPORT_ICEUDP, ns.JINGLE_TRANSPORT_RAWUDP, ns.JINGLE,
                 ns.JINGLE_015, ns.JINGLE_RTP_VIDEO,
                 ns.JINGLE_RTP, ns.JINGLE_015_VIDEO])
-    # the call to SSC has no effect here
-    conn.ContactCapabilities.SetSelfCapabilities([
-        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA },
-        ])
-    noop_presence_update(q, stream)
 
 if __name__ == '__main__':
     exec_test(run_test)
diff --git a/tests/twisted/constants.py b/tests/twisted/constants.py
index 957eed7..b45e283 100644
--- a/tests/twisted/constants.py
+++ b/tests/twisted/constants.py
@@ -51,7 +51,7 @@ CONN = "org.freedesktop.Telepathy.Connection"
 CONN_IFACE_AVATARS = CONN + '.Interface.Avatars'
 CONN_IFACE_CAPS = CONN + '.Interface.Capabilities'
 CONN_IFACE_CONTACTS = CONN + '.Interface.Contacts'
-CONN_IFACE_CONTACT_CAPS = CONN + '.Interface.ContactCapabilities.DRAFT'
+CONN_IFACE_CONTACT_CAPS = CONN + '.Interface.ContactCapabilities.DRAFT2'
 CONN_IFACE_SIMPLE_PRESENCE = CONN + '.Interface.SimplePresence'
 CONN_IFACE_REQUESTS = CONN + '.Interface.Requests'
 CONN_IFACE_LOCATION = CONN + '.Interface.Location'
@@ -231,3 +231,5 @@ MEDIA_CAP_VIDEO = 2
 MEDIA_CAP_STUN = 4
 MEDIA_CAP_GTALKP2P = 8
 MEDIA_CAP_ICEUDP = 16
+
+CLIENT = 'org.freedesktop.Telepathy.Client'
-- 
1.5.6.5




More information about the telepathy-commits mailing list