[Telepathy-commits] [telepathy-gabble/master] Update the ContactCapabilities spec in extensions/, finish the implementation of caps advertisement, write a full twisted test
Alban Crequy
alban.crequy at collabora.co.uk
Fri Dec 5 09:42:34 PST 2008
---
.../Connection_Interface_Contact_Capabilities.xml | 61 ++---
src/capabilities.c | 17 +-
src/capabilities.h | 3 +-
src/caps-hash.c | 3 +-
src/channel-manager.c | 45 +++-
src/channel-manager.h | 30 ++-
src/connection.c | 158 ++++++---
src/private-tubes-factory.c | 139 +++++++--
tests/twisted/test-caps-tubes.py | 340 +++++++++++++++++---
9 files changed, 629 insertions(+), 167 deletions(-)
diff --git a/extensions/Connection_Interface_Contact_Capabilities.xml b/extensions/Connection_Interface_Contact_Capabilities.xml
index 098a81e..c40142a 100644
--- a/extensions/Connection_Interface_Contact_Capabilities.xml
+++ b/extensions/Connection_Interface_Contact_Capabilities.xml
@@ -23,59 +23,44 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
<tp:docstring xmlns="http://www.w3.org/1999/xhtml">
<p>An interface for connections where it is possible to know what channel
- types may be created before the request is made to the connection
+ classes may be created before the request is made to the connection
object. Each capability represents a commitment by the connection
manager that it will ordinarily be able to create a channel when given
- a request with the given type and handle.</p>
+ a request with the properties defined by the channel class.</p>
<p>Capabilities pertain to particular contact handles, and represent
- activities such as having a text chat or a voice call with the user.
- The activities are represented by the D-Bus interface name of the
- channel type for that activity, and channel properties which can be
- requested.</p>
+ activities such as having a text chat, a voice call with the user or a
+ stream tube of a defined type.</p>
<p>This interface also provides for user interfaces notifying the
connection manager of what capabilities to advertise for the user. This
- is done by using the AdvertiseContactCapabilities method, and deals with
- the interface names of channel types and the channel properties values
- pertaining to them which are implemented by available client
- processes.</p>
+ is done by using the SetSelfCapabilities method, and deals with
+ channel properties values pertaining to them which are implemented by
+ available client processes.</p>
</tp:docstring>
- <method name="AdvertiseContactCapabilities">
- <arg direction="in" name="add" type="aa{sv}"
+ <method name="SetSelfCapabilities">
+ <arg direction="in" name="caps" type="aa{sv}"
tp:type="String_Variant_Map[]">
<tp:docstring xmlns="http://www.w3.org/1999/xhtml">
- An array of channel classes to add to the list of what the connection
- can handle
- </tp:docstring>
- </arg>
- <arg direction="in" name="remove" type="aa{sv}"
- tp:type="String_Variant_Map[]">
- <tp:docstring>
- An array of channel classes to remove from the list of what the
+ An array of channel classes to replace to the list of what the
connection can handle
</tp:docstring>
</arg>
- <arg direction="out" type="aa{sv}" tp:type="String_Variant_Map[]">
- <tp:docstring>
- An array of channel classes describing the current capabilities.
- </tp:docstring>
- </arg>
<tp:docstring xmlns="http://www.w3.org/1999/xhtml">
- <p>Used by user interfaces to indicate which channel types they are able
- to handle on this connection. Because these may be provided by
- different client processes, this method accepts channel types to add
- and remove from the set already advertised on this connection.</p>
+ <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>
+
+ <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>
<p>Upon a successful invocation of this method, the
ContactCapabilitiesChanged signal will be emitted for the user's own
handle (as returned by GetSelfHandle) by the connection manager to
- indicate the changes that have been made. This signal should also be
- monitored to ensure that the set is kept accurate - for example, a
- client may remove capabilities when it exits which are still provided
- by another client.</p>
+ indicate the changes that have been made.</p>
</tp:docstring>
<tp:possible-errors>
<tp:error name="org.freedesktop.Telepathy.Error.NetworkError"/>
@@ -117,13 +102,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
</method>
<signal name="ContactCapabilitiesChanged">
- <arg name="caps" type="(a(ua{sv}as)a(ua{sv}as))" tp:type="Contact_Capability_Change">
+ <arg name="caps" type="a(ua{sv}as)" tp:type="Enhanced_Contact_Capability[]">
<tp:docstring xmlns="http://www.w3.org/1999/xhtml">
- An struct containing:
- <ul>
- <li>the contact's removed capabilities</li>
- <li>the contact's added capabilities</li>
- </ul>
+ All the capabilities of the contact
</tp:docstring>
</arg>
<tp:docstring xmlns="http://www.w3.org/1999/xhtml">
@@ -143,7 +124,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
Fixed_Properties nor to Allowed_Properties, the request will fail.
</tp:docstring>
<tp:member type="u" tp:type="Contact_Handle" name="Handle"/>
- <tp:member type="a{sv}" tp:type="String_Variant_Map"
+ <tp:member type="a{sv}" tp:type="Channel_Class"
name="Fixed_Properties">
<tp:docstring>
A dictionary mapping the channel properties to their values.
diff --git a/src/capabilities.c b/src/capabilities.c
index 459e153..dc7fd51 100644
--- a/src/capabilities.c
+++ b/src/capabilities.c
@@ -20,7 +20,7 @@
#include "config.h"
#include "capabilities.h"
-
+#include "channel-manager.h"
#include "namespaces.h"
#include "presence-cache.h"
#include <telepathy-glib/interfaces.h>
@@ -53,8 +53,12 @@ static const Feature self_advertised_features[] =
};
GSList *
-capabilities_get_features (GabblePresenceCapabilities caps)
+capabilities_get_features (GabblePresenceCapabilities caps,
+ GHashTable *per_channel_factory_caps)
{
+ GHashTableIter channel_manager_iter;
+ GabbleChannelManager *manager;
+ gpointer cap;
GSList *features = NULL;
const Feature *i;
@@ -62,6 +66,15 @@ capabilities_get_features (GabblePresenceCapabilities caps)
if ((i->caps & caps) == i->caps)
features = g_slist_append (features, (gpointer) i);
+ if (per_channel_factory_caps != NULL)
+ {
+ g_hash_table_iter_init (&channel_manager_iter, per_channel_factory_caps);
+ while (g_hash_table_iter_next (&channel_manager_iter, &manager, &cap))
+ {
+ gabble_channel_manager_get_feature_list (manager, cap, &features);
+ }
+ }
+
return features;
}
diff --git a/src/capabilities.h b/src/capabilities.h
index 20ad1be..1cb5fde 100644
--- a/src/capabilities.h
+++ b/src/capabilities.h
@@ -54,7 +54,8 @@ struct _Feature
* Return a linked list of const Feature structs corresponding to the given
* GabblePresenceCapabilities.
*/
-GSList *capabilities_get_features (GabblePresenceCapabilities caps);
+GSList *capabilities_get_features (GabblePresenceCapabilities caps,
+ GHashTable *per_channel_factory_caps);
/*
* capabilities_fill_cache
diff --git a/src/caps-hash.c b/src/caps-hash.c
index ff8a11c..14ea622 100644
--- a/src/caps-hash.c
+++ b/src/caps-hash.c
@@ -357,7 +357,8 @@ gchar *
caps_hash_compute_from_self_presence (GabbleConnection *self)
{
GabblePresence *presence = self->self_presence;
- GSList *features_list = capabilities_get_features (presence->caps);
+ GSList *features_list = capabilities_get_features (presence->caps,
+ presence->per_channel_factory_caps);
GPtrArray *features = g_ptr_array_new ();
GPtrArray *identities = g_ptr_array_new ();
GPtrArray *dataforms = g_ptr_array_new ();
diff --git a/src/channel-manager.c b/src/channel-manager.c
index c9984c0..06a504e 100644
--- a/src/channel-manager.c
+++ b/src/channel-manager.c
@@ -363,6 +363,22 @@ void gabble_channel_manager_get_contact_capabilities (
/* ... else assume there is not caps for this kind of channels */
}
+void gabble_channel_manager_get_feature_list (
+ GabbleChannelManager *manager,
+ gpointer specific_caps,
+ GSList **features)
+{
+ GabbleChannelManagerIface *iface = GABBLE_CHANNEL_MANAGER_GET_INTERFACE (
+ manager);
+ GabbleChannelManagerGetFeatureListFunc method = iface->get_feature_list;
+
+ if (method != NULL)
+ {
+ method (manager, specific_caps, features);
+ }
+ /* ... else nothing to do */
+}
+
gpointer gabble_channel_manager_parse_capabilities (
GabbleChannelManager *manager,
LmMessageNode *child)
@@ -425,22 +441,37 @@ void gabble_channel_manager_update_capabilities (
/* ... else, do what? */
}
-void gabble_channel_manager_get_capability_changes (
+gboolean gabble_channel_manager_capabilities_diff (
GabbleChannelManager *manager,
TpHandle handle,
gpointer specific_old_caps,
- gpointer specific_new_caps,
- GPtrArray *added_array,
- GPtrArray *removed_array)
+ gpointer specific_new_caps)
+{
+ GabbleChannelManagerIface *iface = GABBLE_CHANNEL_MANAGER_GET_INTERFACE (
+ manager);
+ GabbleChannelManagerCapsDiffFunc method = iface->caps_diff;
+
+ if (method != NULL)
+ {
+ return method (manager, handle, specific_old_caps, specific_new_caps);
+ }
+ /* ... else, nothing to do */
+ return FALSE;
+}
+
+void
+gabble_channel_manager_add_capability (GabbleChannelManager *manager,
+ GabbleConnection *conn,
+ TpHandle handle,
+ GHashTable *cap)
{
GabbleChannelManagerIface *iface = GABBLE_CHANNEL_MANAGER_GET_INTERFACE (
manager);
- GabbleChannelManagerGetCapChangesFunc method = iface->get_cap_changes;
+ GabbleChannelManagerAddCapFunc method = iface->add_cap;
if (method != NULL)
{
- method (manager, handle, specific_old_caps, specific_new_caps,
- added_array, removed_array);
+ method (manager, conn, handle, cap);
}
/* ... else, nothing to do */
}
diff --git a/src/channel-manager.h b/src/channel-manager.h
index 4154ea7..d8aa3de 100644
--- a/src/channel-manager.h
+++ b/src/channel-manager.h
@@ -56,6 +56,9 @@ typedef void (*GabbleChannelManagerGetContactCapsFunc) (
GabbleChannelManager *manager, GabbleConnection *conn, TpHandle handle,
GPtrArray *arr);
+typedef void (*GabbleChannelManagerGetFeatureListFunc) (
+ GabbleChannelManager *manager, gpointer specific_caps, GSList **features);
+
typedef gpointer (*GabbleChannelManagerParseCapsFunc) (
GabbleChannelManager *manager, LmMessageNode *children);
@@ -69,15 +72,22 @@ typedef void (*GabbleChannelManagerCopyCapsFunc) (
typedef void (*GabbleChannelManagerUpdateCapsFunc) (
GabbleChannelManager *manager, gpointer *specific_caps_out, gpointer specific_caps_in);
-typedef void (*GabbleChannelManagerGetCapChangesFunc) (
+typedef gboolean (*GabbleChannelManagerCapsDiffFunc) (
GabbleChannelManager *manager, TpHandle handle, gpointer specific_old_caps,
- gpointer specific_new_caps, GPtrArray *added_array,
- GPtrArray *removed_array);
+ gpointer specific_new_caps);
+
+typedef void (*GabbleChannelManagerAddCapFunc) (
+ GabbleChannelManager *manager, GabbleConnection *conn, TpHandle handle,
+ GHashTable *cap);
+
void gabble_channel_manager_get_contact_capabilities (
GabbleChannelManager *manager, GabbleConnection *conn, TpHandle handle,
GPtrArray *arr);
+void gabble_channel_manager_get_feature_list (
+ GabbleChannelManager *manager, gpointer specific_caps, GSList **features);
+
gpointer gabble_channel_manager_parse_capabilities (
GabbleChannelManager *manager, LmMessageNode *children);
@@ -91,10 +101,14 @@ void gabble_channel_manager_update_capabilities (
GabbleChannelManager *manager, gpointer specific_caps_out,
gpointer specific_caps_in);
-void gabble_channel_manager_get_capability_changes (
+gboolean gabble_channel_manager_capabilities_diff (
GabbleChannelManager *manager, TpHandle handle, gpointer specific_old_caps,
- gpointer specific_new_caps, GPtrArray *added_array,
- GPtrArray *removed_array);
+ gpointer specific_new_caps);
+
+void gabble_channel_manager_add_capability (
+ GabbleChannelManager *manager, GabbleConnection *conn, TpHandle handle,
+ GHashTable *cap);
+
typedef void (*GabbleChannelManagerForeachChannelFunc) (
GabbleChannelManager *manager, GabbleExportableChannelFunc func,
@@ -135,11 +149,13 @@ struct _GabbleChannelManagerIface {
GTypeInterface parent;
GabbleChannelManagerGetContactCapsFunc get_contact_caps;
+ GabbleChannelManagerGetFeatureListFunc get_feature_list;
GabbleChannelManagerParseCapsFunc parse_caps;
GabbleChannelManagerFreeCapsFunc free_caps;
GabbleChannelManagerCopyCapsFunc copy_caps;
GabbleChannelManagerUpdateCapsFunc update_caps;
- GabbleChannelManagerGetCapChangesFunc get_cap_changes;
+ GabbleChannelManagerCapsDiffFunc caps_diff;
+ GabbleChannelManagerAddCapFunc add_cap;
GabbleChannelManagerForeachChannelFunc foreach_channel;
diff --git a/src/connection.c b/src/connection.c
index 972284d..47f2680 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -1517,7 +1517,8 @@ connection_iq_disco_cb (LmMessageHandler *handler,
lm_message_node_set_attribute (identity, "name", PACKAGE_STRING);
lm_message_node_set_attribute (identity, "type", "pc");
- features = capabilities_get_features (self->self_presence->caps);
+ features = capabilities_get_features (self->self_presence->caps,
+ self->self_presence->per_channel_factory_caps);
DEBUG ("caps now %u", self->self_presence->caps);
@@ -2129,22 +2130,38 @@ _emit_capabilities_changed (GabbleConnection *conn,
g_ptr_array_free (caps_arr, TRUE);
}
+/**
+ * gabble_connection_get_handle_contact_capabilities
+ *
+ * Add capabilities of handle to the given GPtrArray
+ */
+static void
+gabble_connection_get_handle_contact_capabilities (GabbleConnection *self,
+ TpHandle handle, GPtrArray *arr)
+{
+ guint i;
+
+ for (i = 0; i < self->channel_managers->len; i++)
+ {
+ GabbleChannelManager *manager = GABBLE_CHANNEL_MANAGER (
+ g_ptr_array_index (self->channel_managers, i));
+
+ gabble_channel_manager_get_contact_capabilities (manager, self, handle,
+ arr);
+ }
+}
+
+
static void
_emit_contact_capabilities_changed (GabbleConnection *conn,
TpHandle handle,
GHashTable *old_caps,
GHashTable *new_caps)
{
- GValueArray *arr = g_value_array_new (2);
- GPtrArray *removed_array;
- GPtrArray *added_array;
- GValue removed = {0, };
- GValue added = {0, };
+ GPtrArray *ret;
+ gboolean diff = FALSE;
guint i;
- removed_array = g_ptr_array_new ();
- added_array = g_ptr_array_new ();
-
for (i = 0; i < conn->channel_managers->len; i++)
{
GabbleChannelManager *manager = GABBLE_CHANNEL_MANAGER (
@@ -2157,28 +2174,24 @@ _emit_contact_capabilities_changed (GabbleConnection *conn,
if (new_caps != NULL)
per_channel_factory_caps_new = g_hash_table_lookup (new_caps, manager);
- gabble_channel_manager_get_capability_changes (manager, handle,
- per_channel_factory_caps_old, per_channel_factory_caps_new,
- added_array, removed_array);
+ if (gabble_channel_manager_capabilities_diff (manager, handle,
+ per_channel_factory_caps_old, per_channel_factory_caps_new))
+ {
+ diff = TRUE;
+ break;
+ }
}
- g_value_init (&removed, GABBLE_ARRAY_TYPE_ENHANCED_CONTACT_CAPABILITY_LIST);
- g_value_init (&added, GABBLE_ARRAY_TYPE_ENHANCED_CONTACT_CAPABILITY_LIST);
-
- g_value_set_boxed (&removed, removed_array);
- g_value_set_boxed (&added, added_array);
-
- g_value_array_append (arr, &removed);
- g_value_array_append (arr, &added);
-
/* Don't emit the D-Bus signal if there is no change */
- if (added_array->len + removed_array->len > 0)
- {
- gabble_svc_connection_interface_contact_capabilities_emit_contact_capabilities_changed (
- conn, arr);
- }
+ if (! diff)
+ return;
+
+ ret = g_ptr_array_new ();
- g_value_array_free (arr);
+ gabble_connection_get_handle_contact_capabilities (conn, handle, ret);
+ gabble_svc_connection_interface_contact_capabilities_emit_contact_capabilities_changed (
+ conn, ret);
+ g_ptr_array_free (ret, TRUE);
}
static void
@@ -2315,6 +2328,73 @@ gabble_connection_advertise_capabilities (TpSvcConnectionInterfaceCapabilities *
g_ptr_array_free (ret, TRUE);
}
+/**
+ * gabble_connection_set_self_capabilities
+ *
+ * Implements D-Bus method SetSelfCapabilities
+ * 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 (
+ GabbleSvcConnectionInterfaceContactCapabilities *iface,
+ const GPtrArray *caps,
+ DBusGMethodInvocation *context)
+{
+ GabbleConnection *self = GABBLE_CONNECTION (iface);
+ TpBaseConnection *base = (TpBaseConnection *) self;
+ GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (self);
+ guint i;
+ GabblePresence *pres = self->self_presence;
+ GHashTable *save_caps;
+ GError *error = NULL;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ /* reset the caps, and fill with the given parameter but keep a backup for
+ * diffing: we don't want to emit a signal if nothing has changed */
+ save_caps = pres->per_channel_factory_caps;
+ pres->per_channel_factory_caps = NULL;
+
+ for (i = 0; i < caps->len; i++)
+ {
+ GHashTable *cap_to_add = g_ptr_array_index (caps, i);
+ guint j;
+
+ for (j = 0; j < self->channel_managers->len; j++)
+ {
+ GabbleChannelManager *manager = GABBLE_CHANNEL_MANAGER (
+ g_ptr_array_index (self->channel_managers, j));
+
+ gabble_channel_manager_add_capability (manager, self,
+ base->self_handle, cap_to_add);
+ }
+ }
+
+ priv->caps_serial++;
+
+ if (!_gabble_connection_signal_own_presence (self, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ return;
+ }
+
+ _emit_contact_capabilities_changed (self, base->self_handle,
+ save_caps,
+ pres->per_channel_factory_caps);
+ gabble_presence_cache_free_specific_cache (save_caps);
+
+
+ gabble_svc_connection_interface_contact_capabilities_return_from_set_self_capabilities
+ (context);
+}
+
static const gchar *assumed_caps[] =
{
TP_IFACE_CHANNEL_TYPE_TEXT,
@@ -2396,28 +2476,6 @@ gabble_connection_get_handle_capabilities (GabbleConnection *self,
}
-/**
- * gabble_connection_get_handle_contact_capabilities
- *
- * Add capabilities of handle to the given GPtrArray
- */
-static void
-gabble_connection_get_handle_contact_capabilities (GabbleConnection *self,
- TpHandle handle, GPtrArray *arr)
-{
- guint i;
-
- for (i = 0; i < self->channel_managers->len; i++)
- {
- GabbleChannelManager *manager = GABBLE_CHANNEL_MANAGER (
- g_ptr_array_index (self->channel_managers, i));
-
- gabble_channel_manager_get_contact_capabilities (manager, self, handle,
- arr);
- }
-}
-
-
static void
conn_capabilities_fill_contact_attributes (GObject *obj,
const GArray *contacts, GHashTable *attributes_hash)
@@ -3064,7 +3122,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);
- /* TODO: publish own caps */
+ IMPLEMENT(set_self_capabilities);
#undef IMPLEMENT
}
diff --git a/src/private-tubes-factory.c b/src/private-tubes-factory.c
index 1b9a4f5..5af202d 100644
--- a/src/private-tubes-factory.c
+++ b/src/private-tubes-factory.c
@@ -36,6 +36,7 @@
#define DEBUG_FLAG GABBLE_DEBUG_TUBES
#include "channel-manager.h"
+#include "capabilities.h"
#include "connection.h"
#include "debug.h"
#include "muc-channel.h"
@@ -90,7 +91,9 @@ struct _GabblePrivateTubesFactoryPrivate
typedef struct _TubesCapabilities TubesCapabilities;
struct _TubesCapabilities
{
+ /* Service -> Feature */
GHashTable *stream_tube_caps;
+ /* ServiceName -> Feature */
GHashTable *dbus_tube_caps;
};
@@ -441,6 +444,7 @@ gabble_private_tubes_factory_get_contact_caps (GabbleChannelManager *manager,
TpHandle handle,
GPtrArray *arr)
{
+ TpBaseConnection *base = (TpBaseConnection *) conn;
TubesCapabilities *caps;
GHashTable *stream_tube_caps;
GHashTable *dbus_tube_caps;
@@ -451,7 +455,10 @@ gabble_private_tubes_factory_get_contact_caps (GabbleChannelManager *manager,
g_assert (handle != 0);
- presence = gabble_presence_cache_get (conn->presence_cache, handle);
+ if (handle == base->self_handle)
+ presence = conn->self_presence;
+ else
+ presence = gabble_presence_cache_get (conn->presence_cache, handle);
if (presence == NULL)
return;
@@ -469,7 +476,7 @@ gabble_private_tubes_factory_get_contact_caps (GabbleChannelManager *manager,
if (stream_tube_caps != NULL)
{
g_hash_table_iter_init (&tube_caps_iter, stream_tube_caps);
- while (g_hash_table_iter_next (&tube_caps_iter, &service, &dummy))
+ while (g_hash_table_iter_next (&tube_caps_iter, &service, &dummy))
{
add_service_to_array (service, arr, TP_TUBE_TYPE_STREAM, handle);
}
@@ -478,13 +485,36 @@ gabble_private_tubes_factory_get_contact_caps (GabbleChannelManager *manager,
if (dbus_tube_caps != NULL)
{
g_hash_table_iter_init (&tube_caps_iter, dbus_tube_caps);
- while (g_hash_table_iter_next (&tube_caps_iter, &service, &dummy))
+ while (g_hash_table_iter_next (&tube_caps_iter, &service, &dummy))
{
add_service_to_array (service, arr, TP_TUBE_TYPE_DBUS, handle);
}
}
}
+static void
+gabble_private_tubes_factory_get_feature_list (GabbleChannelManager *manager,
+ gpointer specific_caps,
+ GSList **features)
+{
+ TubesCapabilities *caps = specific_caps;
+ GHashTableIter iter;
+ gchar *service;
+ Feature *feat;
+
+ g_hash_table_iter_init (&iter, caps->stream_tube_caps);
+ while (g_hash_table_iter_next (&iter, &service, &feat))
+ {
+ *features = g_slist_append (*features, (gpointer) feat);
+ }
+
+ g_hash_table_iter_init (&iter, caps->dbus_tube_caps);
+ while (g_hash_table_iter_next (&iter, &service, &feat))
+ {
+ *features = g_slist_append (*features, (gpointer) feat);
+ }
+}
+
static gpointer
gabble_private_tubes_factory_parse_caps (
GabbleChannelManager *manager,
@@ -595,14 +625,12 @@ gabble_private_tubes_factory_update_caps (
caps_out->dbus_tube_caps, g_strdup, NULL);
}
-static void
-gabble_private_tubes_factory_get_cap_changes (
+static gboolean
+gabble_private_tubes_factory_caps_diff (
GabbleChannelManager *manager,
TpHandle handle,
- gpointer specific_old_caps,
- gpointer specific_new_caps,
- GPtrArray *added_array,
- GPtrArray *removed_array)
+ gpointer specific_old_caps,
+ gpointer specific_new_caps)
{
TubesCapabilities *old_caps = specific_old_caps;
TubesCapabilities *new_caps = specific_new_caps;
@@ -613,27 +641,25 @@ gabble_private_tubes_factory_get_cap_changes (
if (old_caps != NULL)
{
g_hash_table_iter_init (&tube_caps_iter, old_caps->stream_tube_caps);
- while (g_hash_table_iter_next (&tube_caps_iter, &service, &dummy))
+ while (g_hash_table_iter_next (&tube_caps_iter, &service, &dummy))
{
gpointer key, value;
if (new_caps == NULL ||
!g_hash_table_lookup_extended (new_caps->stream_tube_caps,
service, &key, &value))
{
- add_service_to_array (service, removed_array,
- TP_TUBE_TYPE_STREAM, handle);
+ return TRUE;
}
}
g_hash_table_iter_init (&tube_caps_iter, old_caps->dbus_tube_caps);
- while (g_hash_table_iter_next (&tube_caps_iter, &service, &dummy))
+ while (g_hash_table_iter_next (&tube_caps_iter, &service, &dummy))
{
gpointer key, value;
if (new_caps == NULL ||
!g_hash_table_lookup_extended (new_caps->dbus_tube_caps,
service, &key, &value))
{
- add_service_to_array (service, removed_array,
- TP_TUBE_TYPE_DBUS, handle);
+ return TRUE;
}
}
}
@@ -641,30 +667,97 @@ gabble_private_tubes_factory_get_cap_changes (
if (new_caps != NULL)
{
g_hash_table_iter_init (&tube_caps_iter, new_caps->stream_tube_caps);
- while (g_hash_table_iter_next (&tube_caps_iter, &service, &dummy))
+ while (g_hash_table_iter_next (&tube_caps_iter, &service, &dummy))
{
gpointer key, value;
if (old_caps == NULL ||
!g_hash_table_lookup_extended (old_caps->stream_tube_caps,
service, &key, &value))
{
- add_service_to_array (service, added_array,
- TP_TUBE_TYPE_STREAM, handle);
+ return TRUE;
}
}
g_hash_table_iter_init (&tube_caps_iter, new_caps->dbus_tube_caps);
- while (g_hash_table_iter_next (&tube_caps_iter, &service, &dummy))
+ while (g_hash_table_iter_next (&tube_caps_iter, &service, &dummy))
{
gpointer key, value;
if (old_caps == NULL ||
!g_hash_table_lookup_extended (old_caps->dbus_tube_caps,
service, &key, &value))
{
- add_service_to_array (service, added_array,
- TP_TUBE_TYPE_DBUS, handle);
+ return TRUE;
}
}
}
+ return FALSE;
+}
+
+static void
+gabble_private_tubes_factory_add_cap (GabbleChannelManager *manager,
+ GabbleConnection *conn,
+ TpHandle handle,
+ GHashTable *cap)
+{
+ TpBaseConnection *base = (TpBaseConnection *) conn;
+ GabblePresence *presence;
+ TubesCapabilities *caps;
+ const gchar *channel_type;
+
+ channel_type = tp_asv_get_string (cap,
+ TP_IFACE_CHANNEL ".ChannelType");
+
+ /* this channel is not for this factory */
+ if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES) &&
+ tp_strdiff (channel_type, GABBLE_IFACE_CHANNEL_TYPE_STREAM_TUBE) &&
+ tp_strdiff (channel_type, GABBLE_IFACE_CHANNEL_TYPE_DBUS_TUBE))
+ return;
+
+ if (tp_asv_get_uint32 (cap,
+ TP_IFACE_CHANNEL ".TargetHandleType", NULL) != TP_HANDLE_TYPE_CONTACT)
+ return;
+
+ if (handle == base->self_handle)
+ presence = conn->self_presence;
+ else
+ presence = gabble_presence_cache_get (conn->presence_cache, handle);
+
+ g_assert (presence != NULL);
+
+ if (presence->per_channel_factory_caps == NULL)
+ presence->per_channel_factory_caps = g_hash_table_new (NULL, NULL);
+
+ caps = g_hash_table_lookup (presence->per_channel_factory_caps, manager);
+ if (caps == NULL)
+ {
+ caps = g_new0 (TubesCapabilities, 1);
+ caps->stream_tube_caps = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ caps->dbus_tube_caps = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ g_hash_table_insert (presence->per_channel_factory_caps, manager, caps);
+ }
+
+ if (!tp_strdiff (channel_type, GABBLE_IFACE_CHANNEL_TYPE_STREAM_TUBE))
+ {
+ Feature *feat = g_new0 (Feature, 1);
+ gchar *service = g_strdup (tp_asv_get_string (cap,
+ GABBLE_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service"));
+ feat->feature_type = FEATURE_OPTIONAL;
+ feat->ns = g_strdup_printf ("%s/stream/%s", NS_TUBES, service);
+ feat->caps = 0;
+ g_hash_table_insert (caps->stream_tube_caps, service, feat);
+ }
+ else if (!tp_strdiff (channel_type, GABBLE_IFACE_CHANNEL_TYPE_DBUS_TUBE))
+ {
+ Feature *feat = g_new0 (Feature, 1);
+ gchar *service = g_strdup (tp_asv_get_string (cap,
+ GABBLE_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName"));
+ feat->feature_type = FEATURE_OPTIONAL;
+ feat->ns = g_strdup_printf ("%s/dbus/%s", NS_TUBES, service);
+ feat->caps = 0;
+ g_hash_table_insert (caps->dbus_tube_caps, service, feat);
+ }
+ /* TODO: how to free the service? */
}
struct _ForeachData
@@ -1088,11 +1181,13 @@ channel_manager_iface_init (gpointer g_iface,
GabbleChannelManagerIface *iface = g_iface;
iface->get_contact_caps = gabble_private_tubes_factory_get_contact_caps;
+ iface->get_feature_list = gabble_private_tubes_factory_get_feature_list;
iface->parse_caps = gabble_private_tubes_factory_parse_caps;
iface->free_caps = gabble_private_tubes_factory_free_caps;
iface->copy_caps = gabble_private_tubes_factory_copy_caps;
iface->update_caps = gabble_private_tubes_factory_update_caps;
- iface->get_cap_changes = gabble_private_tubes_factory_get_cap_changes;
+ iface->caps_diff = gabble_private_tubes_factory_caps_diff;
+ iface->add_cap = gabble_private_tubes_factory_add_cap;
iface->foreach_channel = gabble_private_tubes_factory_foreach_channel;
diff --git a/tests/twisted/test-caps-tubes.py b/tests/twisted/test-caps-tubes.py
index ed3943b..a344247 100644
--- a/tests/twisted/test-caps-tubes.py
+++ b/tests/twisted/test-caps-tubes.py
@@ -1,9 +1,11 @@
"""
Test tubes capabilities with Connection.Interface.ContactCapabilities.DRAFT
-Receive presence and caps from contacts and check that GetContactCapabilities
-works correctly and that ContactCapabilitiesChanged is correctly received.
-Also check that GetContactAttributes gives the same results.
+
+1. Receive presence and caps from contacts and check that
+GetContactCapabilities works correctly and that ContactCapabilitiesChanged is
+correctly received. Also check that GetContactAttributes gives the same
+results.
- no tube cap at all
- 1 stream tube cap
@@ -13,6 +15,20 @@ Also check that GetContactAttributes gives the same results.
- 1 stream tube + 1 D-Bus tube caps, again, to test whether the caps cache
works with tubes
+2. Test SetSelfCapabilities and test that a presence stanza is sent to the
+contacts, test that the D-Bus signal ContactCapabilitiesChanged is fired for
+the self handle, ask Gabble for its caps with an iq request, check the reply
+is correct, and ask Gabble for its caps using D-Bus method
+GetContactCapabilities. Also check that GetContactAttributes gives the same
+results.
+
+- no tube cap at all
+- 1 stream tube cap
+- 1 D-Bus tube cap
+- 1 stream tube + 1 D-Bus tube caps
+- 2 stream tube + 2 D-Bus tube caps
+- 1 stream tube + 1 D-Bus tube caps, again, just for the fun
+
"""
import dbus
@@ -106,7 +122,55 @@ def presence_add_caps(presence, ver, client, hash=None):
c['hash'] = hash
return presence
-def _test_tube_caps(q, bus, conn, stream, contact, contact_handle, client):
+def receive_presence_and_ask_caps(q, stream):
+ # receive presence stanza
+ event_stream, event_dbus = q.expect_many(
+ EventPattern('stream-presence'),
+ EventPattern('dbus-signal', signal='ContactCapabilitiesChanged')
+ )
+ signaled_caps = event_dbus.args[0]
+
+ c_nodes = xpath.queryForNodes('/presence/c', event_stream.stanza)
+ assert c_nodes is not None
+ assert len(c_nodes) == 1
+ hash = c_nodes[0].attributes['hash']
+ ver = c_nodes[0].attributes['ver']
+ node = c_nodes[0].attributes['node']
+ assert hash == 'sha-1'
+
+ # ask caps
+ request = """
+<iq from='fake_contact at jabber.org/resource'
+ id='disco1'
+ to='gabble at jabber.org/resource'
+ type='get'>
+ <query xmlns='http://jabber.org/protocol/disco#info'
+ node='""" + node + '#' + ver + """'/>
+</iq>
+"""
+ stream.send(request)
+
+ # receive caps
+ event = q.expect('stream-iq',
+ query_ns='http://jabber.org/protocol/disco#info')
+ caps_str = str(xpath.queryForNodes('/iq/query/feature', event.stanza))
+
+ return (event, caps_str, signaled_caps)
+
+def caps_contain(event, cap):
+ node = xpath.queryForNodes('/iq/query/feature[@var="%s"]'
+ % cap,
+ event.stanza)
+ if node is None:
+ return False
+ if len(node) != 1:
+ return False
+ var = node[0].attributes['var']
+ if var is None:
+ return False
+ return var == cap
+
+def test_tube_caps_from_contact(q, bus, conn, stream, contact, contact_handle, client):
conn_caps_iface = dbus.Interface(conn, caps_iface)
conn_contacts_iface = dbus.Interface(conn, contacts_iface)
@@ -180,11 +244,9 @@ def _test_tube_caps(q, bus, conn, stream, contact, contact_handle, client):
stream.send(result)
event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
- removed = event.args[0][0]
- added = event.args[0][1]
- assert len(removed) == 0, removed
- assert len(added) == 1, added
- assert added[0][1] \
+ signaled_caps = event.args[0]
+ assert len(signaled_caps) == 2, signaled_caps # basic caps + daap
+ assert signaled_caps[1][1] \
['org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service'] \
== 'daap'
@@ -227,14 +289,9 @@ def _test_tube_caps(q, bus, conn, stream, contact, contact_handle, client):
stream.send(result)
event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
- removed = event.args[0][0]
- added = event.args[0][1]
- assert len(removed) == 1, removed
- assert len(added) == 1, added
- assert removed[0][1] \
- ['org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service'] \
- == 'daap'
- assert added[0][1] \
+ signaled_caps = event.args[0]
+ assert len(signaled_caps) == 2, signaled_caps # basic caps + Xiangqi
+ assert signaled_caps[1][1] \
['org.freedesktop.Telepathy.Channel.Type.DBusTube.DRAFT.ServiceName'] \
== 'com.example.Xiangqi'
@@ -279,13 +336,14 @@ def _test_tube_caps(q, bus, conn, stream, contact, contact_handle, client):
stream.send(result)
event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
- removed = event.args[0][0]
- added = event.args[0][1]
- assert len(removed) == 0, removed
- assert len(added) == 1, added
- assert added[0][1] \
+ signaled_caps = event.args[0]
+ assert len(signaled_caps) == 3, signaled_caps # basic caps + daap+xiangqi
+ assert signaled_caps[1][1] \
['org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service'] \
== 'daap'
+ assert signaled_caps[2][1] \
+ ['org.freedesktop.Telepathy.Channel.Type.DBusTube.DRAFT.ServiceName'] \
+ == 'com.example.Xiangqi'
# daap + xiangqi capabilities
daap_xiangqi_caps = [
@@ -333,14 +391,18 @@ def _test_tube_caps(q, bus, conn, stream, contact, contact_handle, client):
stream.send(result)
event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
- removed = event.args[0][0]
- added = event.args[0][1]
- assert len(removed) == 0, removed
- assert len(added) == 2, added
- assert added[0][1] \
+ signaled_caps = event.args[0]
+ assert len(signaled_caps) == 5, signaled_caps # basic caps + 4 tubes
+ assert signaled_caps[1][1] \
+ ['org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service'] \
+ == 'daap'
+ assert signaled_caps[2][1] \
['org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service'] \
== 'http'
- assert added[1][1] \
+ assert signaled_caps[3][1] \
+ ['org.freedesktop.Telepathy.Channel.Type.DBusTube.DRAFT.ServiceName'] \
+ == 'com.example.Xiangqi'
+ assert signaled_caps[4][1] \
['org.freedesktop.Telepathy.Channel.Type.DBusTube.DRAFT.ServiceName'] \
== 'com.example.Go'
@@ -374,16 +436,14 @@ def _test_tube_caps(q, bus, conn, stream, contact, contact_handle, client):
# Gabble does not look up our capabilities because of the cache
event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
- removed = event.args[0][0]
- added = event.args[0][1]
- assert len(removed) == 2, removed
- assert len(added) == 0, added
- assert removed[0][1] \
+ signaled_caps = event.args[0]
+ assert len(signaled_caps) == 3, signaled_caps # basic caps + daap+xiangqi
+ assert signaled_caps[1][1] \
['org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service'] \
- == 'http'
- assert removed[1][1] \
+ == 'daap'
+ assert signaled_caps[2][1] \
['org.freedesktop.Telepathy.Channel.Type.DBusTube.DRAFT.ServiceName'] \
- == 'com.example.Go'
+ == 'com.example.Xiangqi'
# daap + xiangqi capabilities
daap_xiangqi_caps = [
@@ -401,6 +461,209 @@ def _test_tube_caps(q, bus, conn, stream, contact, contact_handle, client):
[contact_handle][caps_iface + '/caps']
assert caps_via_contacts_iface == caps, caps_via_contacts_iface
+def test_tube_caps_to_contact(q, bus, conn, stream):
+ basic_caps = [(1, text_fixed_properties,
+ text_allowed_properties)]
+ daap_caps = [
+ (1, text_fixed_properties, text_allowed_properties),
+ (1, daap_fixed_properties, daap_allowed_properties)]
+ xiangqi_caps = [
+ (1, text_fixed_properties, text_allowed_properties),
+ (1, xiangqi_fixed_properties, xiangqi_allowed_properties)]
+ daap_xiangqi_caps = [
+ (1, text_fixed_properties, text_allowed_properties),
+ (1, daap_fixed_properties, daap_allowed_properties),
+ (1, xiangqi_fixed_properties, xiangqi_allowed_properties)]
+ all_tubes_caps = [
+ (1, text_fixed_properties, text_allowed_properties),
+ (1, daap_fixed_properties, daap_allowed_properties),
+ (1, http_fixed_properties, http_allowed_properties),
+ (1, xiangqi_fixed_properties, xiangqi_allowed_properties),
+ (1, go_fixed_properties, go_allowed_properties)]
+
+ conn_caps_iface = dbus.Interface(conn, caps_iface)
+ conn_contacts_iface = dbus.Interface(conn, contacts_iface)
+
+ # Check our own caps
+ caps = conn_caps_iface.GetContactCapabilities([1])
+ assert caps == basic_caps, caps
+ # check the Contacts interface give the same caps
+ caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
+ [1], [caps_iface], False) \
+ [1][caps_iface + '/caps']
+ assert caps_via_contacts_iface == caps, caps_via_contacts_iface
+
+ # Advertise nothing
+ conn_caps_iface.SetSelfCapabilities([])
+
+ # Check our own caps
+ caps = conn_caps_iface.GetContactCapabilities([1])
+ assert len(caps) == 1
+ assert caps == basic_caps, caps
+ # check the Contacts interface give the same caps
+ caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
+ [1], [caps_iface], False) \
+ [1][caps_iface + '/caps']
+ assert caps_via_contacts_iface == caps, caps_via_contacts_iface
+
+ sync_stream(q, stream)
+
+ # Advertise daap
+ ret_caps = conn_caps_iface.SetSelfCapabilities(
+ [daap_fixed_properties])
+
+ # Expect Gabble to reply with the correct caps
+ event, caps_str, signaled_caps = receive_presence_and_ask_caps(q, stream)
+ assert caps_contain(event, ns_tubes) == True, caps_str
+ assert caps_contain(event, ns_tubes + '/stream/daap') == True, caps_str
+ assert caps_contain(event, ns_tubes + '/stream/http') == False, caps_str
+ assert caps_contain(event, ns_tubes + '/dbus/com.example.Go') \
+ == False, caps_str
+ assert caps_contain(event, ns_tubes + '/dbus/com.example.Xiangqi') \
+ == False, caps_str
+ assert len(signaled_caps) == 2, signaled_caps # basic caps + daap
+ assert signaled_caps[1][1] \
+ ['org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service'] \
+ == 'daap'
+
+ # Check our own caps
+ caps = conn_caps_iface.GetContactCapabilities([1])
+ assert len(caps) == 2
+ assert caps == daap_caps, caps
+ # check the Contacts interface give the same caps
+ caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
+ [1], [caps_iface], False) \
+ [1][caps_iface + '/caps']
+ assert caps_via_contacts_iface == caps, caps_via_contacts_iface
+
+ # Advertise xiangqi
+ ret_caps = conn_caps_iface.SetSelfCapabilities(
+ [xiangqi_fixed_properties])
+
+ # Expect Gabble to reply with the correct caps
+ event, caps_str, signaled_caps = receive_presence_and_ask_caps(q, stream)
+ assert caps_contain(event, ns_tubes) == True, caps_str
+ assert caps_contain(event, ns_tubes + '/stream/daap') == False, caps_str
+ assert caps_contain(event, ns_tubes + '/stream/http') == False, caps_str
+ assert caps_contain(event, ns_tubes + '/dbus/com.example.Go') \
+ == False, caps_str
+ assert caps_contain(event, ns_tubes + '/dbus/com.example.Xiangqi') \
+ == True, caps_str
+ assert len(signaled_caps) == 2, signaled_caps # basic caps + daap
+ assert signaled_caps[1][1] \
+ ['org.freedesktop.Telepathy.Channel.Type.DBusTube.DRAFT.ServiceName'] \
+ == 'com.example.Xiangqi'
+
+ # Check our own caps
+ caps = conn_caps_iface.GetContactCapabilities([1])
+ assert len(caps) == 2
+ assert caps == xiangqi_caps, caps
+ # check the Contacts interface give the same caps
+ caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
+ [1], [caps_iface], False) \
+ [1][caps_iface + '/caps']
+ assert caps_via_contacts_iface == caps, caps_via_contacts_iface
+
+ # Advertise daap + xiangqi
+ ret_caps = conn_caps_iface.SetSelfCapabilities(
+ [daap_fixed_properties, xiangqi_fixed_properties])
+
+ # Expect Gabble to reply with the correct caps
+ event, caps_str, signaled_caps = receive_presence_and_ask_caps(q, stream)
+ assert caps_contain(event, ns_tubes) == True, caps_str
+ assert caps_contain(event, ns_tubes + '/stream/daap') == True, caps_str
+ assert caps_contain(event, ns_tubes + '/stream/http') == False, caps_str
+ assert caps_contain(event, ns_tubes + '/dbus/com.example.Go') \
+ == False, caps_str
+ assert caps_contain(event, ns_tubes + '/dbus/com.example.Xiangqi') \
+ == True, caps_str
+ assert len(signaled_caps) == 3, signaled_caps # basic caps + daap+xiangqi
+ assert signaled_caps[1][1] \
+ ['org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service'] \
+ == 'daap'
+ assert signaled_caps[2][1] \
+ ['org.freedesktop.Telepathy.Channel.Type.DBusTube.DRAFT.ServiceName'] \
+ == 'com.example.Xiangqi'
+
+ # Check our own caps
+ caps = conn_caps_iface.GetContactCapabilities([1])
+ assert len(caps) == 3
+ assert caps == daap_xiangqi_caps, caps
+ # check the Contacts interface give the same caps
+ caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
+ [1], [caps_iface], False) \
+ [1][caps_iface + '/caps']
+ assert caps_via_contacts_iface == caps, caps_via_contacts_iface
+
+ # Advertise 4 tubes
+ ret_caps = conn_caps_iface.SetSelfCapabilities(
+ [daap_fixed_properties, http_fixed_properties,
+ go_fixed_properties, xiangqi_fixed_properties])
+
+ # Expect Gabble to reply with the correct caps
+ event, caps_str, signaled_caps = receive_presence_and_ask_caps(q, stream)
+ assert caps_contain(event, ns_tubes) == True, caps_str
+ assert caps_contain(event, ns_tubes + '/stream/daap') == True, caps_str
+ assert caps_contain(event, ns_tubes + '/stream/http') == True, caps_str
+ assert caps_contain(event, ns_tubes + '/dbus/com.example.Go') \
+ == True, caps_str
+ assert caps_contain(event, ns_tubes + '/dbus/com.example.Xiangqi') \
+ == True, caps_str
+ assert len(signaled_caps) == 5, signaled_caps # basic caps + 4 tubes
+ assert signaled_caps[1][1] \
+ ['org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service'] \
+ == 'daap'
+ assert signaled_caps[2][1] \
+ ['org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service'] \
+ == 'http'
+ assert signaled_caps[3][1] \
+ ['org.freedesktop.Telepathy.Channel.Type.DBusTube.DRAFT.ServiceName'] \
+ == 'com.example.Xiangqi'
+ assert signaled_caps[4][1] \
+ ['org.freedesktop.Telepathy.Channel.Type.DBusTube.DRAFT.ServiceName'] \
+ == 'com.example.Go'
+
+ # Check our own caps
+ caps = conn_caps_iface.GetContactCapabilities([1])
+ assert len(caps) == 5
+ assert caps == all_tubes_caps, caps
+ # check the Contacts interface give the same caps
+ caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
+ [1], [caps_iface], False) \
+ [1][caps_iface + '/caps']
+ assert caps_via_contacts_iface == caps, caps_via_contacts_iface
+
+ # Advertise daap + xiangqi
+ ret_caps = conn_caps_iface.SetSelfCapabilities(
+ [daap_fixed_properties, xiangqi_fixed_properties])
+
+ # Expect Gabble to reply with the correct caps
+ event, caps_str, signaled_caps = receive_presence_and_ask_caps(q, stream)
+ assert caps_contain(event, ns_tubes) == True, caps_str
+ assert caps_contain(event, ns_tubes + '/stream/daap') == True, caps_str
+ assert caps_contain(event, ns_tubes + '/stream/http') == False, caps_str
+ assert caps_contain(event, ns_tubes + '/dbus/com.example.Go') \
+ == False, caps_str
+ assert caps_contain(event, ns_tubes + '/dbus/com.example.Xiangqi') \
+ == True, caps_str
+ assert len(signaled_caps) == 3, signaled_caps # basic caps + daap+xiangqi
+ assert signaled_caps[1][1] \
+ ['org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service'] \
+ == 'daap'
+ assert signaled_caps[2][1] \
+ ['org.freedesktop.Telepathy.Channel.Type.DBusTube.DRAFT.ServiceName'] \
+ == 'com.example.Xiangqi'
+
+ # Check our own caps
+ caps = conn_caps_iface.GetContactCapabilities([1])
+ assert len(caps) == 3
+ assert caps == daap_xiangqi_caps, caps
+ # check the Contacts interface give the same caps
+ caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
+ [1], [caps_iface], False) \
+ [1][caps_iface + '/caps']
+ assert caps_via_contacts_iface == caps, caps_via_contacts_iface
+
def test(q, bus, conn, stream):
conn.Connect()
@@ -408,7 +671,10 @@ def test(q, bus, conn, stream):
client = 'http://telepathy.freedesktop.org/fake-client'
- _test_tube_caps(q, bus, conn, stream, 'bilbo1 at foo.com/Foo', 2L, client)
+ test_tube_caps_from_contact(q, bus, conn, stream, 'bilbo1 at foo.com/Foo',
+ 2L, client)
+
+ test_tube_caps_to_contact(q, bus, conn, stream)
conn.Disconnect()
q.expect('dbus-signal', signal='StatusChanged', args=[2, 1])
--
1.5.6.5
More information about the Telepathy-commits
mailing list