[Telepathy-commits] [telepathy-salut/master] SalutTubeStream implements the new tube API with the requestotron. Tube test updated.

Alban Crequy alban.crequy at collabora.co.uk
Fri Feb 6 03:14:55 PST 2009


---
 src/salut-connection.c           |    2 -
 src/salut-tubes-channel.c        |   84 +++++--
 src/salut-tubes-channel.h        |    3 +
 src/salut-tubes-manager.c        |    6 +
 src/tube-iface.c                 |    4 +-
 src/tube-stream.c                |  494 +++++++++++++++++++++++++++++++++++++-
 src/tube-stream.h                |   10 +-
 tests/twisted/avahi/test-tube.py |  224 ++++++++++++++++-
 8 files changed, 780 insertions(+), 47 deletions(-)

diff --git a/src/salut-connection.c b/src/salut-connection.c
index ffaaf2e..fbd81f0 100644
--- a/src/salut-connection.c
+++ b/src/salut-connection.c
@@ -2838,8 +2838,6 @@ salut_connection_create_channel_factories (TpBaseConnection *base)
       G_CALLBACK (_olpc_activity_manager_activity_modified_cb), self);
 #endif
 
-  g_ptr_array_add (factories, priv->contact_manager);
-
   return factories;
 }
 
diff --git a/src/salut-tubes-channel.c b/src/salut-tubes-channel.c
index adefa16..0b89499 100644
--- a/src/salut-tubes-channel.c
+++ b/src/salut-tubes-channel.c
@@ -79,7 +79,6 @@ G_DEFINE_TYPE_WITH_CODE (SalutTubesChannel, salut_tubes_channel, G_TYPE_OBJECT,
     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TUBES, tubes_iface_init);
     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP,
         tp_external_group_mixin_iface_init);
-    G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL);
     G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL);
 );
 
@@ -176,7 +175,8 @@ static gboolean extract_tube_information (SalutTubesChannel *self,
     GibberXmppNode *tube_node, TpTubeType *type, TpHandle *initiator_handle,
     const gchar **service, GHashTable **parameters, guint *tube_id);
 static SalutTubeIface * create_new_tube (SalutTubesChannel *self,
-    TpTubeType type, TpHandle initiator, const gchar *service,
+    TpTubeType type, TpHandle initiator, SalutTubeChannelState initial_state,
+    const gchar *service,
     GHashTable *parameters, guint tube_id, guint portnum,
     GibberXmppStanza *iq_req);
 
@@ -857,7 +857,8 @@ salut_tubes_channel_muc_message_received (SalutTubesChannel *self,
                 }
 
               tube = create_new_tube (self, type, initiator_handle,
-                  service, parameters, id, 0, NULL);
+                  SALUT_TUBE_CHANNEL_STATE_LOCAL_PENDING, service, parameters,
+                  tube_id, 0, NULL);
 
               /* the tube has reffed its initiator, no need to keep a ref */
               tp_handle_unref (contact_repo, initiator_handle);
@@ -947,7 +948,8 @@ salut_tubes_channel_message_received (SalutTubesChannel *self,
   tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id));
   if (tube == NULL)
     {
-      tube = create_new_tube (self, tube_type, initiator_handle, service,
+      tube = create_new_tube (self, tube_type, initiator_handle,
+        SALUT_TUBE_CHANNEL_STATE_LOCAL_PENDING, service,
         parameters, tube_id, portnum, iq_req);
     }
 }
@@ -1033,7 +1035,8 @@ salut_tubes_channel_tube_request (SalutTubesChannel *self,
   DEBUG ("Request a tube channel with type='%s' and service='%s'",
       channel_type, service);
 
-  tube = create_new_tube (self, type, priv->self_handle, service,
+  tube = create_new_tube (self, type, priv->self_handle,
+      SALUT_TUBE_CHANNEL_STATE_NOT_OFFERED, service,
       parameters, tube_id, 0, NULL);
 
   return tube;
@@ -1102,7 +1105,7 @@ copy_tube_in_ptr_array (gpointer key,
   TpHandle initiator;
   gchar *service;
   GHashTable *parameters;
-  TpTubeState state;
+  SalutTubeChannelState state;
   TpTubeType type;
   GPtrArray *array = (GPtrArray *) user_data;
   GValue entry = {0,};
@@ -1217,6 +1220,7 @@ static SalutTubeIface *
 create_new_tube (SalutTubesChannel *self,
                  TpTubeType type,
                  TpHandle initiator,
+                 SalutTubeChannelState initial_state,
                  const gchar *service,
                  GHashTable *parameters,
                  guint tube_id,
@@ -1225,7 +1229,7 @@ create_new_tube (SalutTubesChannel *self,
 {
   SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self);
   SalutTubeIface *tube;
-  TpTubeState state;
+  SalutTubeChannelState state;
   GibberMucConnection *muc_connection = NULL;
 
   if (self->muc != NULL)
@@ -1241,8 +1245,8 @@ create_new_tube (SalutTubesChannel *self,
     case TP_TUBE_TYPE_STREAM:
       tube = SALUT_TUBE_IFACE (salut_tube_stream_new (priv->conn, self,
           priv->xmpp_connection_manager, priv->handle, priv->handle_type,
-          priv->self_handle, initiator, service, parameters, tube_id,
-          portnum, iq_req));
+          priv->self_handle, initiator, initial_state, service, parameters,
+          tube_id, portnum, iq_req));
       break;
     default:
       g_assert_not_reached ();
@@ -1460,7 +1464,7 @@ publish_tubes_in_node (gpointer key,
     (struct _i_hate_g_hash_table_foreach *) user_data;
   SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (
       data->self);
-  TpTubeState state;
+  SalutTubeChannelState state;
   GibberXmppNode *tube_node;
   TpTubeType type;
   TpHandle initiator;
@@ -1550,6 +1554,8 @@ salut_tubes_channel_offer_d_bus_tube (TpSvcChannelTypeTubes *iface,
   TpBaseConnection *base;
   guint tube_id;
   SalutTubeIface *tube;
+  GHashTable *parameters_copied;
+  SalutTubeChannelState initial_state;
 
   g_assert (SALUT_IS_TUBES_CHANNEL (self));
 
@@ -1569,8 +1575,14 @@ salut_tubes_channel_offer_d_bus_tube (TpSvcChannelTypeTubes *iface,
 
   tube_id = generate_tube_id ();
 
+  if (priv->handle_type == TP_HANDLE_TYPE_ROOM)
+    initial_state = SALUT_TUBE_CHANNEL_STATE_OPEN;
+  else
+    initial_state = SALUT_TUBE_CHANNEL_STATE_REMOTE_PENDING;
+
   tube = create_new_tube (self, TP_TUBE_TYPE_DBUS, priv->self_handle,
-      service, parameters, tube_id, 0, NULL);
+      initial_state, service, parameters_copied,
+      tube_id, 0, NULL);
 
   tp_svc_channel_type_tubes_return_from_offer_d_bus_tube (context, tube_id);
 }
@@ -1589,7 +1601,7 @@ salut_tubes_channel_accept_d_bus_tube (TpSvcChannelTypeTubes *iface,
   SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface);
   SalutTubesChannelPrivate *priv;
   SalutTubeIface *tube;
-  TpTubeState state;
+  SalutTubeChannelState state;
   TpTubeType type;
   gchar *addr;
 
@@ -1694,7 +1706,7 @@ salut_tubes_channel_get_d_bus_tube_address (TpSvcChannelTypeTubes *iface,
   SalutTubeIface *tube;
   gchar *addr;
   TpTubeType type;
-  TpTubeState state;
+  SalutTubeChannelState state;
 
   g_assert (SALUT_IS_TUBES_CHANNEL (self));
 
@@ -1774,7 +1786,7 @@ salut_tubes_channel_get_d_bus_names (TpSvcChannelTypeTubes *iface,
   GHashTable *names;
   GPtrArray *ret;
   TpTubeType type;
-  TpTubeState state;
+  SalutTubeChannelState state;
   guint i;
 
   g_assert (SALUT_IS_TUBES_CHANNEL (self));
@@ -1882,7 +1894,7 @@ send_channel_iq_tube (gpointer key,
   TpHandle initiator;
   gchar *service;
   GHashTable *parameters;
-  TpTubeState state;
+  SalutTubeChannelState state;
   TpTubeType type;
 
   g_object_get (tube,
@@ -2027,6 +2039,7 @@ salut_tubes_channel_offer_stream_tube (TpSvcChannelTypeTubes *iface,
   guint tube_id;
   SalutTubeIface *tube;
   GError *error = NULL;
+  SalutTubeChannelState initial_state;
 
   priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self);
   base = (TpBaseConnection *) priv->conn;
@@ -2052,8 +2065,13 @@ salut_tubes_channel_offer_stream_tube (TpSvcChannelTypeTubes *iface,
 
   tube_id = generate_tube_id ();
 
+  if (priv->handle_type == TP_HANDLE_TYPE_ROOM)
+    initial_state = SALUT_TUBE_CHANNEL_STATE_OPEN;
+  else
+    initial_state = SALUT_TUBE_CHANNEL_STATE_REMOTE_PENDING;
+
   tube = create_new_tube (self, TP_TUBE_TYPE_STREAM, priv->self_handle,
-      service, parameters, tube_id, 0, NULL);
+      initial_state, service, parameters, tube_id, 0, NULL);
 
   g_object_set (tube,
       "address-type", address_type,
@@ -2091,7 +2109,7 @@ salut_tubes_channel_accept_stream_tube (TpSvcChannelTypeTubes *iface,
   SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface);
   SalutTubesChannelPrivate *priv;
   SalutTubeIface *tube;
-  TpTubeState state;
+  SalutTubeChannelState state;
   TpTubeType type;
   GValue *address;
   GError *error = NULL;
@@ -2195,7 +2213,7 @@ salut_tubes_channel_get_stream_tube_socket_address (TpSvcChannelTypeTubes *iface
   SalutTubesChannelPrivate *priv  = SALUT_TUBES_CHANNEL_GET_PRIVATE (self);
   SalutTubeIface *tube;
   TpTubeType type;
-  TpTubeState state;
+  SalutTubeChannelState state;
   GValue *address;
   TpSocketAddressType address_type;
 
@@ -2504,6 +2522,36 @@ emit_tube_closed_signal (gpointer key,
   tp_svc_channel_type_tubes_emit_tube_closed (self, id);
 }
 
+struct _ForeachData
+{
+  TpExportableChannelFunc foreach;
+  gpointer user_data;
+};
+
+static void
+foreach_slave (gpointer key,
+               gpointer value,
+               gpointer user_data)
+{
+  SalutTubeIface *tube = SALUT_TUBE_IFACE (value);
+  struct _ForeachData *data = (struct _ForeachData *) user_data;
+
+  data->foreach (TP_EXPORTABLE_CHANNEL (tube), data->user_data);
+}
+
+void salut_tubes_channel_foreach (SalutTubesChannel *self,
+    TpExportableChannelFunc foreach, gpointer user_data)
+{
+  struct _ForeachData data;
+  SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self);
+
+  data.user_data = user_data;
+  data.foreach = foreach;
+
+  g_hash_table_foreach (priv->tubes, foreach_slave, &data);
+}
+
+
 void
 salut_tubes_channel_close (SalutTubesChannel *self)
 {
diff --git a/src/salut-tubes-channel.h b/src/salut-tubes-channel.h
index 6a3913e..1bf1945 100644
--- a/src/salut-tubes-channel.h
+++ b/src/salut-tubes-channel.h
@@ -66,6 +66,9 @@ GType salut_tubes_channel_get_type (void);
   (G_TYPE_INSTANCE_GET_CLASS ((obj), SALUT_TYPE_TUBES_CHANNEL, \
                               SalutTubesChannelClass))
 
+void salut_tubes_channel_foreach (SalutTubesChannel *self,
+    TpExportableChannelFunc foreach, gpointer user_data);
+
 void salut_tubes_channel_close (SalutTubesChannel *channel);
 
 void salut_tubes_channel_bytestream_offered (SalutTubesChannel *chanel,
diff --git a/src/salut-tubes-manager.c b/src/salut-tubes-manager.c
index 808481b..1072d46 100644
--- a/src/salut-tubes-manager.c
+++ b/src/salut-tubes-manager.c
@@ -680,7 +680,13 @@ _foreach_slave (gpointer key,
   struct _ForeachData *data = (struct _ForeachData *) user_data;
   TpExportableChannel *chan = TP_EXPORTABLE_CHANNEL (value);
 
+  /* Add channels of type Channel.Type.Tubes */
   data->foreach (chan, data->user_data);
+
+  /* Add channels of type Channel.Type.{Stream|DBus}Tube which live in the
+   * SalutTubesChannel object */
+  salut_tubes_channel_foreach (SALUT_TUBES_CHANNEL (chan), data->foreach,
+      data->user_data);
 }
 
 static void
diff --git a/src/tube-iface.c b/src/tube-iface.c
index 4ea7351..2a752b2 100644
--- a/src/tube-iface.c
+++ b/src/tube-iface.c
@@ -19,6 +19,8 @@
 
 #include "tube-iface.h"
 
+#include <telepathy-glib/gtypes.h>
+
 #include "salut-connection.h"
 #include "salut-tubes-channel.h"
 
@@ -180,7 +182,7 @@ salut_tube_iface_base_init (gpointer klass)
           "parameters",
           "parameters GHashTable",
           "GHashTable containing parameters of this DBUS tube object.",
-          G_TYPE_HASH_TABLE,
+          TP_HASH_TYPE_STRING_VARIANT_MAP,
           G_PARAM_CONSTRUCT_ONLY |
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
       g_object_interface_install_property (klass, param_spec);
diff --git a/src/tube-stream.c b/src/tube-stream.c
index e382ae4..5b7ac72 100644
--- a/src/tube-stream.c
+++ b/src/tube-stream.c
@@ -34,6 +34,16 @@
 #include <glib/gstdio.h>
 #include <telepathy-glib/gtypes.h>
 
+#include <telepathy-glib/channel-iface.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/exportable-channel.h>
+#include <telepathy-glib/gtypes.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/svc-channel.h>
+#include <telepathy-glib/svc-generic.h>
+
+#include <gibber/gibber-xmpp-stanza.h>
+#include <gibber/gibber-namespaces.h>
 #include <gibber/gibber-bytestream-direct.h>
 #include <gibber/gibber-bytestream-iface.h>
 #include <gibber/gibber-bytestream-oob.h>
@@ -54,12 +64,34 @@
 #include "tube-iface.h"
 #include "salut-si-bytestream-manager.h"
 #include "salut-contact-manager.h"
+#include "salut-tubes-channel.h"
 #include "salut-xmpp-connection-manager.h"
 
 static void tube_iface_init (gpointer g_iface, gpointer iface_data);
+static void channel_iface_init (gpointer g_iface, gpointer iface_data);
+static void streamtube_iface_init (gpointer g_iface, gpointer iface_data);
 
 G_DEFINE_TYPE_WITH_CODE (SalutTubeStream, salut_tube_stream, G_TYPE_OBJECT,
-    G_IMPLEMENT_INTERFACE (SALUT_TYPE_TUBE_IFACE, tube_iface_init));
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
+      tp_dbus_properties_mixin_iface_init);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init);
+    G_IMPLEMENT_INTERFACE (SALUT_TYPE_TUBE_IFACE, tube_iface_init);
+    G_IMPLEMENT_INTERFACE (SALUT_TYPE_SVC_CHANNEL_TYPE_STREAM_TUBE,
+      streamtube_iface_init);
+    G_IMPLEMENT_INTERFACE (SALUT_TYPE_SVC_CHANNEL_INTERFACE_TUBE,
+      NULL);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL));
+
+static const gchar *salut_tube_stream_interfaces[] = {
+    TP_IFACE_CHANNEL_INTERFACE_GROUP,
+    /* If more interfaces are added, either keep Tube as the first, or change
+     * the implementations of salut_tube_stream_get_interfaces () and
+     * salut_tube_stream_get_property () too */
+    SALUT_IFACE_CHANNEL_INTERFACE_TUBE,
+    NULL
+};
+
 
 /* Linux glibc bits/socket.h suggests that struct sockaddr_storage is
  * not guaranteed to be big enough for AF_UNIX addresses */
@@ -87,6 +119,7 @@ enum
 {
   PROP_CONNECTION = 1,
   PROP_TUBES_CHANNEL,
+  PROP_INTERFACES,
   PROP_HANDLE,
   PROP_HANDLE_TYPE,
   PROP_SELF_HANDLE,
@@ -103,6 +136,11 @@ enum
   PROP_XMPP_CONNECTION_MANAGER,
   PROP_PORT,
   PROP_IQ_REQ,
+  PROP_CHANNEL_DESTROYED,
+  PROP_CHANNEL_PROPERTIES,
+  PROP_OBJECT_PATH,
+  PROP_CHANNEL_TYPE,
+  PROP_TARGET_ID,
   LAST_PROPERTY
 };
 
@@ -118,6 +156,7 @@ struct _SalutTubeStreamPrivate
   guint port;
   GibberXmppConnection *xmpp_connection;
   GibberXmppStanza *iq_req;
+  gchar *object_path;
 
   /* Bytestreams for MUC tubes (using stream initiation) or 1-1 tubes (using
    * direct TCP connections). One tube can have several bytestreams. The
@@ -144,7 +183,7 @@ struct _SalutTubeStreamPrivate
   TpHandle initiator;
   gchar *service;
   GHashTable *parameters;
-  TpTubeState state;
+  SalutTubeChannelState state;
 
   TpSocketAddressType address_type;
   GValue *address;
@@ -958,6 +997,7 @@ salut_tube_stream_get_property (GObject *object,
 {
   SalutTubeStream *self = SALUT_TUBE_STREAM (object);
   SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self);
+  TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn;
 
   switch (property_id)
     {
@@ -967,6 +1007,24 @@ salut_tube_stream_get_property (GObject *object,
       case PROP_CONNECTION:
         g_value_set_object (value, priv->conn);
         break;
+      case PROP_OBJECT_PATH:
+        g_value_set_string (value, priv->object_path);
+        break;
+      case PROP_INTERFACES:
+        if (priv->handle_type == TP_HANDLE_TYPE_ROOM)
+          {
+            /* MUC tubes */
+            g_value_set_boxed (value, salut_tube_stream_interfaces);
+          }
+        else
+          {
+            /* 1-1 tubes - omit the Group interface */
+            g_value_set_boxed (value, salut_tube_stream_interfaces + 1);
+          }
+        break;
+      case PROP_CHANNEL_TYPE:
+        g_value_set_static_string (value, SALUT_IFACE_CHANNEL_TYPE_STREAM_TUBE);
+        break;
       case PROP_HANDLE:
         g_value_set_uint (value, priv->handle);
         break;
@@ -1015,6 +1073,27 @@ salut_tube_stream_get_property (GObject *object,
       case PROP_IQ_REQ:
         g_value_set_pointer (value, priv->iq_req);
         break;
+      case PROP_CHANNEL_DESTROYED:
+        g_value_set_boolean (value, priv->closed);
+        break;
+      case PROP_CHANNEL_PROPERTIES:
+        g_value_take_boxed (value,
+            tp_dbus_properties_mixin_make_properties_hash (object,
+                TP_IFACE_CHANNEL, "TargetHandle",
+                TP_IFACE_CHANNEL, "TargetHandleType",
+                TP_IFACE_CHANNEL, "ChannelType",
+                TP_IFACE_CHANNEL, "TargetID",
+                NULL));
+        break;
+      case PROP_TARGET_ID:
+          {
+            TpHandleRepoIface *repo = tp_base_connection_get_handles (
+                base_conn, priv->handle_type);
+
+            g_value_set_string (value,
+                tp_handle_inspect (repo, priv->handle));
+          }
+        break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
         break;
@@ -1038,6 +1117,14 @@ salut_tube_stream_set_property (GObject *object,
       case PROP_CONNECTION:
         priv->conn = g_value_get_object (value);
         break;
+      case PROP_OBJECT_PATH:
+        g_free (priv->object_path);
+        priv->object_path = g_value_dup_string (value);
+        break;
+      case PROP_CHANNEL_TYPE:
+      /* this property is writable in the interface, but not actually
+       * meaningfully changeable on this channel, so we do nothing */
+      break;
       case PROP_HANDLE:
         priv->handle = g_value_get_uint (value);
         break;
@@ -1062,6 +1149,11 @@ salut_tube_stream_set_property (GObject *object,
           g_hash_table_destroy (priv->parameters);
         priv->parameters = g_value_dup_boxed (value);
         break;
+      case PROP_STATE:
+        priv->state = g_value_get_uint (value);
+        if (priv->state == SALUT_TUBE_CHANNEL_STATE_OPEN)
+          g_signal_emit (G_OBJECT (self), signals[OPENED], 0);
+        break;
       case PROP_ADDRESS_TYPE:
         g_assert (g_value_get_uint (value) == TP_SOCKET_ADDRESS_TYPE_UNIX ||
             g_value_get_uint (value) == TP_SOCKET_ADDRESS_TYPE_IPV4 ||
@@ -1190,6 +1282,7 @@ salut_tube_stream_constructor (GType type,
   GObject *obj;
   SalutTubeStreamPrivate *priv;
   TpHandleRepoIface *contact_repo;
+  DBusGConnection *bus;
 
   obj = G_OBJECT_CLASS (salut_tube_stream_parent_class)->
            constructor (type, n_props, props);
@@ -1210,18 +1303,20 @@ salut_tube_stream_constructor (GType type,
       if (priv->handle_type == TP_HANDLE_TYPE_CONTACT)
         {
           /* Private tube */
-          priv->offer_needed = TRUE;
-          priv->state = TP_TUBE_STATE_REMOTE_PENDING;
+          g_assert (priv->state == SALUT_TUBE_CHANNEL_STATE_NOT_OFFERED ||
+              priv->state == SALUT_TUBE_CHANNEL_STATE_REMOTE_PENDING);
+          if (priv->state == SALUT_TUBE_CHANNEL_STATE_REMOTE_PENDING)
+            priv->offer_needed = TRUE;
         }
       else
         {
           /* Muc tube */
-          priv->state = TP_TUBE_STATE_OPEN;
+          g_assert (priv->state == SALUT_TUBE_CHANNEL_STATE_OPEN);
         }
     }
   else
     {
-      priv->state = TP_TUBE_STATE_LOCAL_PENDING;
+      g_assert (priv->state == SALUT_TUBE_CHANNEL_STATE_LOCAL_PENDING);
     }
 
   if (priv->handle_type == TP_HANDLE_TYPE_CONTACT)
@@ -1236,12 +1331,88 @@ salut_tube_stream_constructor (GType type,
       g_assert (priv->xmpp_connection_manager == NULL);
     }
 
+  bus = tp_get_bus ();
+  dbus_g_connection_register_g_object (bus, priv->object_path, obj);
+
+  DEBUG ("Registering at '%s'", priv->object_path);
+
   return obj;
 }
 
+static gboolean
+tube_iface_props_setter (GObject *object,
+                         GQuark interface,
+                         GQuark name,
+                         const GValue *value,
+                         gpointer setter_data,
+                         GError **error)
+{
+  SalutTubeStream *self = SALUT_TUBE_STREAM (object);
+  SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self);
+
+  g_return_val_if_fail (interface == SALUT_IFACE_QUARK_CHANNEL_INTERFACE_TUBE,
+      FALSE);
+
+  if (name != g_quark_from_static_string ("Parameters"))
+    {
+      g_object_set_property (object, setter_data, value);
+      return TRUE;
+    }
+
+  if (priv->state != SALUT_TUBE_CHANNEL_STATE_NOT_OFFERED)
+  {
+    g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+        "Can change parameters only if the tube is not offered");
+    return FALSE;
+  }
+
+  priv->parameters = g_value_dup_boxed (value);
+
+  return TRUE;
+}
+
+
 static void
 salut_tube_stream_class_init (SalutTubeStreamClass *salut_tube_stream_class)
 {
+  static TpDBusPropertiesMixinPropImpl channel_props[] = {
+      { "TargetHandleType", "handle-type", NULL },
+      { "TargetHandle", "handle", NULL },
+      { "ChannelType", "channel-type", NULL },
+      { "TargetID", "target-id", NULL },
+      { "Interfaces", "interfaces", NULL },
+      { NULL }
+  };
+  static TpDBusPropertiesMixinPropImpl stream_tube_props[] = {
+      { "Service", "service", NULL },
+      /*{ "AvailableStreamTubeTypes", NULL, NULL },*/
+      { NULL }
+  };
+  static TpDBusPropertiesMixinPropImpl tube_iface_props[] = {
+      { "Initiator", "initiator", NULL },
+      { "Parameters", "parameters", "parameters" },
+      { "Status", "state", NULL },
+      { NULL }
+  };
+  static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+      { TP_IFACE_CHANNEL,
+        tp_dbus_properties_mixin_getter_gobject_properties,
+        NULL,
+        channel_props,
+      },
+      { SALUT_IFACE_CHANNEL_TYPE_STREAM_TUBE,
+        tp_dbus_properties_mixin_getter_gobject_properties,
+        NULL,
+        stream_tube_props,
+      },
+      { SALUT_IFACE_CHANNEL_INTERFACE_TUBE,
+        tp_dbus_properties_mixin_getter_gobject_properties,
+        tube_iface_props_setter,
+        tube_iface_props,
+      },
+      { NULL }
+  };
+
   GObjectClass *object_class = G_OBJECT_CLASS (salut_tube_stream_class);
   GParamSpec *param_spec;
 
@@ -1278,6 +1449,23 @@ salut_tube_stream_class_init (SalutTubeStreamClass *salut_tube_stream_class)
   g_object_class_override_property (object_class, PROP_STATE,
     "state");
 
+  g_object_class_override_property (object_class, PROP_OBJECT_PATH,
+      "object-path");
+  g_object_class_override_property (object_class, PROP_CHANNEL_TYPE,
+      "channel-type");
+
+  g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED,
+      "channel-destroyed");
+  g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES,
+      "channel-properties");
+
+  param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces",
+      "Additional Channel.Interface.* interfaces",
+      G_TYPE_STRV,
+      G_PARAM_READABLE |
+      G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NAME);
+  g_object_class_install_property (object_class, PROP_INTERFACES, param_spec);
+
   param_spec = g_param_spec_uint (
       "address-type",
       "address type",
@@ -1317,6 +1505,13 @@ salut_tube_stream_class_init (SalutTubeStreamClass *salut_tube_stream_class)
   g_object_class_install_property (object_class, PROP_ACCESS_CONTROL_PARAM,
       param_spec);
 
+  param_spec = g_param_spec_string ("target-id", "Target JID",
+      "The string obtained by inspecting the target handle",
+      NULL,
+      G_PARAM_READABLE |
+      G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NAME);
+  g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec);
+
   param_spec = g_param_spec_object (
       "xmpp-connection-manager",
       "SalutXmppConnectionManager object",
@@ -1381,6 +1576,10 @@ salut_tube_stream_class_init (SalutTubeStreamClass *salut_tube_stream_class)
                   NULL, NULL,
                   salut_signals_marshal_VOID__VOID,
                   G_TYPE_NONE, 0);
+
+  salut_tube_stream_class->dbus_props_class.interfaces = prop_interfaces;
+  tp_dbus_properties_mixin_class_init (object_class,
+      G_STRUCT_OFFSET (SalutTubeStreamClass, dbus_props_class));
 }
 
 static void
@@ -1432,26 +1631,39 @@ salut_tube_stream_new (SalutConnection *conn,
                        TpHandleType handle_type,
                        TpHandle self_handle,
                        TpHandle initiator,
+                       SalutTubeChannelState initial_state,
                        const gchar *service,
                        GHashTable *parameters,
                        guint id,
                        guint portnum,
                        GibberXmppStanza *iq_req)
 {
-  return g_object_new (SALUT_TYPE_TUBE_STREAM,
+  SalutTubeStream *obj;
+  char *object_path;
+
+  object_path = g_strdup_printf ("%s/StreamTubeChannel_%u_%u",
+      conn->parent.object_path, handle, id);
+
+  obj = g_object_new (SALUT_TYPE_TUBE_STREAM,
       "connection", conn,
       "tubes-channel", tubes_channel,
+      "object-path", object_path,
       "xmpp-connection-manager", xmpp_connection_manager,
       "handle", handle,
       "handle-type", handle_type,
       "self-handle", self_handle,
       "initiator", initiator,
+      "state", initial_state,
       "service", service,
       "parameters", parameters,
       "id", id,
       "port", portnum,
       "iq-req", iq_req,
       NULL);
+
+  g_free (object_path);
+
+  return obj;
 }
 
 static void
@@ -1502,7 +1714,7 @@ salut_tube_stream_accept (SalutTubeIface *tube,
   SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self);
   GibberXmppStanza *reply;
 
-  if (priv->state != TP_TUBE_STATE_LOCAL_PENDING)
+  if (priv->state != SALUT_TUBE_CHANNEL_STATE_LOCAL_PENDING)
     return TRUE;
 
   if (!tube_stream_open (self, error))
@@ -1526,7 +1738,7 @@ salut_tube_stream_accept (SalutTubeIface *tube,
         }
     }
 
-  priv->state = TP_TUBE_STATE_OPEN;
+  priv->state = SALUT_TUBE_CHANNEL_STATE_OPEN;
   g_signal_emit (G_OBJECT (self), signals[OPENED], 0);
   return TRUE;
 }
@@ -1559,8 +1771,11 @@ salut_tube_stream_offer_needed (SalutTubeIface *tube)
 {
   SalutTubeStream *self = SALUT_TUBE_STREAM (tube);
   SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self);
+  gboolean ret = priv->offer_needed;
 
-  return priv->offer_needed;
+  priv->offer_needed = FALSE;
+
+  return ret;
 }
 
 /* callback for listening connections from the contact's CM */
@@ -1753,10 +1968,10 @@ salut_tube_stream_add_bytestream (SalutTubeIface *tube,
       TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
           (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT);
 
-      if (priv->state == TP_TUBE_STATE_REMOTE_PENDING)
+      if (priv->state == SALUT_TUBE_CHANNEL_STATE_REMOTE_PENDING)
         {
           DEBUG ("Received first connection. Tube is now open");
-          priv->state = TP_TUBE_STATE_OPEN;
+          priv->state = SALUT_TUBE_CHANNEL_STATE_OPEN;
           g_signal_emit (G_OBJECT (self), signals[OPENED], 0);
         }
 
@@ -1956,6 +2171,231 @@ salut_tube_stream_check_params (TpSocketAddressType address_type,
 }
 
 static void
+stream_tube_new_connection_cb (SalutTubesChannel *self,
+                               guint contact,
+                               gpointer user_data)
+{
+  salut_svc_channel_type_stream_tube_emit_stream_tube_new_connection (
+      self, contact);
+}
+
+/**
+ * salut_tube_stream_offer_stream_tube
+ *
+ * Implements D-Bus method OfferStreamTube
+ * on org.freedesktop.Telepathy.Channel.Type.StreamTube
+ */
+static void
+salut_tube_stream_offer_stream_tube (SalutSvcChannelTypeStreamTube *iface,
+                                     guint address_type,
+                                     const GValue *address,
+                                     guint access_control,
+                                     const GValue *access_control_param,
+                                     DBusGMethodInvocation *context)
+{
+  SalutTubeStream *self = SALUT_TUBE_STREAM (iface);
+  SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self);
+  GError *error = NULL;
+
+  if (priv->state != SALUT_TUBE_CHANNEL_STATE_NOT_OFFERED)
+    {
+      g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+          "Tube is not in the not offered state");
+      dbus_g_method_return_error (context, error);
+      g_error_free (error);
+      return;
+    }
+
+  if (!salut_tube_stream_check_params (address_type, address,
+        access_control, access_control_param, &error))
+    {
+      dbus_g_method_return_error (context, error);
+      g_error_free (error);
+      return;
+    }
+
+  g_assert (address_type == TP_SOCKET_ADDRESS_TYPE_UNIX ||
+      address_type == TP_SOCKET_ADDRESS_TYPE_IPV4 ||
+      address_type == TP_SOCKET_ADDRESS_TYPE_IPV6);
+  g_assert (priv->address == NULL);
+  priv->address_type = address_type;
+  priv->address = tp_g_value_slice_dup (address);
+  g_assert (priv->access_control == TP_SOCKET_ACCESS_CONTROL_LOCALHOST);
+  priv->access_control = access_control;
+  g_assert (priv->access_control_param == NULL);
+  priv->access_control_param = tp_g_value_slice_dup (access_control_param);
+
+  if (priv->handle_type == TP_HANDLE_TYPE_CONTACT)
+    {
+      salut_tubes_channel_send_iq_offer (priv->tubes_channel);
+
+      salut_svc_channel_interface_tube_emit_tube_channel_state_changed (
+          self, SALUT_TUBE_CHANNEL_STATE_REMOTE_PENDING);
+    }
+
+  g_signal_connect (self, "new-connection",
+      G_CALLBACK (stream_tube_new_connection_cb), self);
+
+  salut_svc_channel_type_stream_tube_return_from_offer_stream_tube (context);
+}
+
+/**
+ * salut_tube_stream_accept_stream_tube
+ *
+ * Implements D-Bus method AcceptStreamTube
+ * on org.freedesktop.Telepathy.Channel.Type.StreamTube
+ */
+static void
+salut_tube_stream_accept_stream_tube (SalutSvcChannelTypeStreamTube *iface,
+                                      guint address_type,
+                                      guint access_control,
+                                      const GValue *access_control_param,
+                                      DBusGMethodInvocation *context)
+{
+  SalutTubeStream *self = SALUT_TUBE_STREAM (iface);
+  SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self);
+  GError *error = NULL;
+
+  if (address_type != TP_SOCKET_ADDRESS_TYPE_UNIX &&
+      address_type != TP_SOCKET_ADDRESS_TYPE_IPV4 &&
+      address_type != TP_SOCKET_ADDRESS_TYPE_IPV6)
+    {
+      error = g_error_new (TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
+          "Address type %d not implemented", address_type);
+
+      dbus_g_method_return_error (context, error);
+      g_error_free (error);
+      return;
+    }
+
+  if (access_control != TP_SOCKET_ACCESS_CONTROL_LOCALHOST)
+    {
+      GError e = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+          "Unix sockets only support localhost control access" };
+
+      dbus_g_method_return_error (context, &e);
+      return;
+    }
+
+  if (priv->state != SALUT_TUBE_CHANNEL_STATE_LOCAL_PENDING)
+    {
+      GError e = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+          "Tube is not in the local pending state" };
+
+      dbus_g_method_return_error (context, &e);
+      return;
+    }
+
+  if (!salut_tube_stream_accept (SALUT_TUBE_IFACE (self), &error))
+    {
+      dbus_g_method_return_error (context, error);
+      g_error_free (error);
+      return;
+    }
+
+#if 0
+  /* TODO: add a property "muc" and set it at initialization */
+  if (priv->handle_type == TP_HANDLE_TYPE_ROOM)
+    salut_muc_channel_send_presence (self->muc, NULL);
+#endif
+
+  salut_svc_channel_type_stream_tube_return_from_accept_stream_tube (context,
+      priv->address);
+}
+
+/**
+ * salut_tube_stream_get_stream_tube_socket_address
+ *
+ * Implements D-Bus method GetStreamTubeSocketAddress
+ * on org.freedesktop.Telepathy.Channel.Type.StreamTube
+ */
+static void
+salut_tube_stream_get_stream_tube_socket_address (
+    SalutSvcChannelTypeStreamTube *iface,
+    DBusGMethodInvocation *context)
+{
+  SalutTubeStream *self = SALUT_TUBE_STREAM (iface);
+  SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self);
+
+  salut_svc_channel_type_stream_tube_return_from_get_stream_tube_socket_address
+      (context, priv->address_type, priv->address);
+}
+
+/**
+ * salut_tube_stream_close_async:
+ *
+ * Implements D-Bus method Close
+ * on interface org.freedesktop.Telepathy.Channel
+ */
+static void
+salut_tube_stream_close_async (TpSvcChannel *iface,
+                               DBusGMethodInvocation *context)
+{
+  SalutTubeStream *self = SALUT_TUBE_STREAM (iface);
+
+  tp_svc_channel_emit_closed (self);
+  tp_svc_channel_return_from_close (context);
+}
+
+/**
+ * salut_tube_stream_get_channel_type
+ *
+ * Implements D-Bus method GetChannelType
+ * on interface org.freedesktop.Telepathy.Channel
+ */
+static void
+salut_tube_stream_get_channel_type (TpSvcChannel *iface,
+                                    DBusGMethodInvocation *context)
+{
+  tp_svc_channel_return_from_get_channel_type (context,
+      SALUT_IFACE_CHANNEL_TYPE_STREAM_TUBE);
+}
+
+/**
+ * salut_tube_stream_get_handle
+ *
+ * Implements D-Bus method GetHandle
+ * on interface org.freedesktop.Telepathy.Channel
+ */
+static void
+salut_tube_stream_get_handle (TpSvcChannel *iface,
+                              DBusGMethodInvocation *context)
+{
+  SalutTubeStream *self = SALUT_TUBE_STREAM (iface);
+  SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self);
+
+  tp_svc_channel_return_from_get_handle (context, priv->handle_type,
+      priv->handle);
+}
+
+/**
+ * salut_tube_stream_get_interfaces
+ *
+ * Implements D-Bus method GetInterfaces
+ * on interface org.freedesktop.Telepathy.Channel
+ */
+static void
+salut_tube_stream_get_interfaces (TpSvcChannel *iface,
+                                  DBusGMethodInvocation *context)
+{
+  SalutTubeStream *self = SALUT_TUBE_STREAM (iface);
+  SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self);
+
+  if (priv->handle_type == TP_HANDLE_TYPE_CONTACT)
+    {
+      /* omit the Group interface */
+      tp_svc_channel_return_from_get_interfaces (context,
+          salut_tube_stream_interfaces + 1);
+    }
+  else
+    {
+      tp_svc_channel_return_from_get_interfaces (context,
+          salut_tube_stream_interfaces);
+    }
+}
+
+
+static void
 tube_iface_init (gpointer g_iface,
                  gpointer iface_data)
 {
@@ -1968,3 +2408,33 @@ tube_iface_init (gpointer g_iface,
   klass->close = salut_tube_stream_close;
   klass->add_bytestream = salut_tube_stream_add_bytestream;
 }
+
+static void
+streamtube_iface_init (gpointer g_iface,
+                       gpointer iface_data)
+{
+  SalutSvcChannelTypeStreamTubeClass *klass =
+      (SalutSvcChannelTypeStreamTubeClass *) g_iface;
+
+#define IMPLEMENT(x) salut_svc_channel_type_stream_tube_implement_##x (\
+    klass, salut_tube_stream_##x)
+  IMPLEMENT(offer_stream_tube);
+  IMPLEMENT(accept_stream_tube);
+  IMPLEMENT(get_stream_tube_socket_address);
+#undef IMPLEMENT
+}
+
+static void
+channel_iface_init (gpointer g_iface,
+                    gpointer iface_data)
+{
+  TpSvcChannelClass *klass = (TpSvcChannelClass *) g_iface;
+
+#define IMPLEMENT(x, suffix) tp_svc_channel_implement_##x (\
+    klass, salut_tube_stream_##x##suffix)
+  IMPLEMENT(close,_async);
+  IMPLEMENT(get_channel_type,);
+  IMPLEMENT(get_handle,);
+  IMPLEMENT(get_interfaces,);
+#undef IMPLEMENT
+}
diff --git a/src/tube-stream.h b/src/tube-stream.h
index 61804a1..26cbfdb 100644
--- a/src/tube-stream.h
+++ b/src/tube-stream.h
@@ -24,6 +24,7 @@
 
 #include <telepathy-glib/enums.h>
 
+#include "extensions/extensions.h"
 #include "salut-connection.h"
 #include "salut-tubes-channel.h"
 
@@ -34,6 +35,8 @@ typedef struct _SalutTubeStreamClass SalutTubeStreamClass;
 
 struct _SalutTubeStreamClass {
   GObjectClass parent_class;
+
+  TpDBusPropertiesMixinClass dbus_props_class;
 };
 
 struct _SalutTubeStream {
@@ -63,9 +66,10 @@ GType salut_tube_stream_get_type (void);
 SalutTubeStream *salut_tube_stream_new (SalutConnection *conn,
     SalutTubesChannel *tubes_channel,
     SalutXmppConnectionManager *xmpp_connection_manager, TpHandle handle,
-    TpHandleType handle_type, TpHandle self_handle, TpHandle initiator,
-    const gchar *service, GHashTable *parameters, guint id, guint portnum,
-    GibberXmppStanza *iq_req);
+    TpHandleType handle_type, TpHandle self_handle,
+    TpHandle initiator, SalutTubeChannelState initial_state,
+    const gchar *service, GHashTable *parameters, guint id,
+    guint portnum, GibberXmppStanza *iq_req);
 
 gboolean salut_tube_stream_check_params (TpSocketAddressType address_type,
     const GValue *address, TpSocketAccessControl access_control,
diff --git a/tests/twisted/avahi/test-tube.py b/tests/twisted/avahi/test-tube.py
index e2f1d89..363ff3c 100644
--- a/tests/twisted/avahi/test-tube.py
+++ b/tests/twisted/avahi/test-tube.py
@@ -8,7 +8,8 @@ import errno
 import string
 
 from xmppstream import setup_stream_listener, connect_to_stream
-from servicetest import make_channel_proxy, Event
+from servicetest import make_channel_proxy, Event, EventPattern, call_async, \
+         tp_name_prefix
 
 from twisted.words.xish import xpath, domish
 from twisted.internet.protocol import Factory, Protocol, ClientCreator
@@ -33,9 +34,108 @@ sample_parameters = dbus.Dictionary({
 
 test_string = "This string travels on a tube !"
 
-print "FIXME: test-tube.py disabled because 1-1 tubes are disabled for now"
-# exiting 77 causes automake to consider the test to have been skipped
-raise SystemExit(77)
+def check_conn_properties(q, bus, conn, channel_list=None):
+    properties = conn.GetAll(
+            'org.freedesktop.Telepathy.Connection.Interface.Requests',
+            dbus_interface='org.freedesktop.DBus.Properties')
+
+    if channel_list == None:
+        assert properties.get('Channels') == [], properties['Channels']
+    else:
+        for i in channel_list:
+            assert i in properties['Channels'], \
+                (i, properties['Channels'])
+
+    assert ({'org.freedesktop.Telepathy.Channel.ChannelType':
+                'org.freedesktop.Telepathy.Channel.Type.Tubes',
+             'org.freedesktop.Telepathy.Channel.TargetHandleType': 1,
+             },
+             ['org.freedesktop.Telepathy.Channel.TargetHandle',
+             ]
+            ) in properties.get('RequestableChannelClasses'),\
+                     properties['RequestableChannelClasses']
+    assert ({'org.freedesktop.Telepathy.Channel.ChannelType':
+                'org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT',
+             'org.freedesktop.Telepathy.Channel.TargetHandleType': 1,
+             },
+             ['org.freedesktop.Telepathy.Channel.TargetHandle',
+              'org.freedesktop.Telepathy.Channel.Interface.Tube.DRAFT.Parameters',
+              'org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service',
+             ]
+            ) in properties.get('RequestableChannelClasses'),\
+                     properties['RequestableChannelClasses']
+
+def check_channel_properties(q, bus, conn, channel, channel_type,
+        contact_handle, contact_id, state=None):
+    # Exercise basic Channel Properties from spec 0.17.7
+    # on the channel of type channel_type
+    channel_props = channel.GetAll(
+            'org.freedesktop.Telepathy.Channel',
+            dbus_interface='org.freedesktop.DBus.Properties')
+    assert channel_props.get('TargetHandle') == contact_handle,\
+            (channel_props.get('TargetHandle'), contact_handle)
+    assert channel_props.get('TargetHandleType') == 1,\
+            channel_props.get('TargetHandleType')
+    assert channel_props.get('ChannelType') == \
+            'org.freedesktop.Telepathy.Channel.Type.' + channel_type,\
+            channel_props.get('ChannelType')
+    assert 'Interfaces' in channel_props, channel_props
+    assert 'org.freedesktop.Telepathy.Channel.Interface.Group' not in \
+            channel_props['Interfaces'], \
+            channel_props['Interfaces']
+    assert channel_props['TargetID'] == contact_id
+
+    if channel_type == "Tubes":
+        assert state is None
+    else:
+        assert state is not None
+        tube_props = channel.GetAll(
+                'org.freedesktop.Telepathy.Channel.Interface.Tube.DRAFT',
+                dbus_interface='org.freedesktop.DBus.Properties')
+        assert tube_props['Status'] == state
+        # no strict check but at least check the properties exist
+        assert tube_props['Parameters'] is not None
+        assert tube_props['Initiator'] is not None
+
+    self_handle = conn.GetSelfHandle()
+
+    ## Exercise FUTURE properties
+    ## on the channel of type channel_type
+    #future_props = channel.GetAll(
+    #        'org.freedesktop.Telepathy.Channel.FUTURE',
+    #        dbus_interface='org.freedesktop.DBus.Properties')
+    #assert future_props['Requested'] == True
+    #assert future_props['InitiatorID'] == 'test at localhost'
+    #assert future_props['InitiatorHandle'] == self_handle
+
+
+def check_NewChannel_signal(old_sig, channel_type, chan_path, contact_handle):
+    assert old_sig[0] == chan_path
+    assert old_sig[1] == tp_name_prefix + '.Channel.Type.' + channel_type
+    assert old_sig[2] == 1         # contact handle
+    assert old_sig[3] == contact_handle
+    assert old_sig[4] == True      # suppress handler
+
+def check_NewChannels_signal(new_sig, channel_type, chan_path, contact_handle,
+        contact_id, initiator_handle):
+    assert len(new_sig) == 1
+    assert len(new_sig[0]) == 1        # one channel
+    assert len(new_sig[0][0]) == 2     # two struct members
+    assert new_sig[0][0][0] == chan_path
+    emitted_props = new_sig[0][0][1]
+
+    assert emitted_props[tp_name_prefix + '.Channel.ChannelType'] ==\
+            tp_name_prefix + '.Channel.Type.' + channel_type
+    assert emitted_props[tp_name_prefix + '.Channel.TargetHandleType'] == 1
+    assert emitted_props[tp_name_prefix + '.Channel.TargetHandle'] ==\
+            contact_handle
+    assert emitted_props[tp_name_prefix + '.Channel.TargetID'] == \
+            contact_id
+    #assert emitted_props[tp_name_prefix + '.Channel.FUTURE.Requested'] == True
+    #assert emitted_props[tp_name_prefix + '.Channel.FUTURE.InitiatorHandle'] \
+    #        == initiator_handle
+    #assert emitted_props[tp_name_prefix + '.Channel.FUTURE.InitiatorID'] == \
+    #        'test at localhost'
 
 def test(q, bus, conn):
 
@@ -67,11 +167,14 @@ def test(q, bus, conn):
             raise
     l = reactor.listenUNIX(server_socket_address, factory)
 
+
+    check_conn_properties(q, bus, conn)
+
     conn.Connect()
     q.expect('dbus-signal', signal='StatusChanged', args=[0L, 0L])
     basic_txt = { "txtvers": "1", "status": "avail" }
 
-    contact_name = PUBLISHED_NAME + get_host_name()
+    contact_name = PUBLISHED_NAME + "@" + get_host_name()
     listener, port = setup_stream_listener(q, contact_name)
 
     announcer = AvahiAnnouncer(contact_name, "_presence._tcp", port, basic_txt)
@@ -90,9 +193,106 @@ def test(q, bus, conn):
             if name == contact_name:
                 handle = h
 
-    t = conn.RequestChannel(CHANNEL_TYPE_TUBES, HT_CONTACT, handle,
-        True)
-    tubes_channel = make_channel_proxy(conn, t, "Channel.Type.Tubes")
+    # old requestotron
+    call_async(q, conn, 'RequestChannel',
+            CHANNEL_TYPE_TUBES, HT_CONTACT, handle, True);
+
+    ret, old_sig, new_sig = q.expect_many(
+        EventPattern('dbus-return', method='RequestChannel'),
+        EventPattern('dbus-signal', signal='NewChannel'),
+        EventPattern('dbus-signal', signal='NewChannels'),
+        )
+
+    assert len(ret.value) == 1
+    chan_path = ret.value[0]
+
+    check_NewChannel_signal(old_sig.args, "Tubes", chan_path, handle)
+    check_NewChannels_signal(new_sig.args, "Tubes", chan_path,
+            handle, contact_name, conn.GetSelfHandle())
+    old_tubes_channel_properties = new_sig.args[0][0]
+
+    check_conn_properties(q, bus, conn, [old_tubes_channel_properties])
+
+    # new requestotron
+    requestotron = dbus.Interface(conn,
+            'org.freedesktop.Telepathy.Connection.Interface.Requests')
+
+    # Try to CreateChannel with unknown properties
+    # Salut must return an error
+    call_async(q, requestotron, 'CreateChannel',
+            {'org.freedesktop.Telepathy.Channel.ChannelType':
+                'org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT',
+             'org.freedesktop.Telepathy.Channel.TargetHandleType':
+                1,
+             'org.freedesktop.Telepathy.Channel.TargetHandle':
+                handle,
+             'this.property.does.not.exist':
+                'this.value.should.not.exist'
+            });
+    ret = q.expect_many(EventPattern('dbus-error', method='CreateChannel'))
+    # CreateChannel failed, we expect no new channel
+    check_conn_properties(q, bus, conn, [old_tubes_channel_properties])
+
+    # Try to CreateChannel with missing properties ("Service")
+    # Salut must return an error
+    call_async(q, requestotron, 'CreateChannel',
+            {'org.freedesktop.Telepathy.Channel.ChannelType':
+                'org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT',
+             'org.freedesktop.Telepathy.Channel.TargetHandleType':
+                1,
+             'org.freedesktop.Telepathy.Channel.TargetHandle':
+                handle
+            });
+    ret = q.expect_many(EventPattern('dbus-error', method='CreateChannel'))
+    # CreateChannel failed, we expect no new channel
+    check_conn_properties(q, bus, conn, [old_tubes_channel_properties])
+
+    # Try to CreateChannel with correct properties
+    # Salut must succeed
+    call_async(q, requestotron, 'CreateChannel',
+            {'org.freedesktop.Telepathy.Channel.ChannelType':
+                'org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT',
+             'org.freedesktop.Telepathy.Channel.TargetHandleType':
+                1,
+             'org.freedesktop.Telepathy.Channel.TargetHandle':
+                handle,
+             'org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service':
+                "newecho",
+             'org.freedesktop.Telepathy.Channel.Interface.Tube.DRAFT.Parameters':
+                dbus.Dictionary({'foo': 'bar'}, signature='sv'),
+            });
+    ret, old_sig, new_sig = q.expect_many(
+        EventPattern('dbus-return', method='CreateChannel'),
+        EventPattern('dbus-signal', signal='NewChannel'),
+        EventPattern('dbus-signal', signal='NewChannels'),
+        )
+
+    assert len(ret.value) == 2 # CreateChannel returns 2 values: o, a{sv}
+    new_chan_path = ret.value[0]
+    new_chan_prop_asv = ret.value[1]
+    assert new_chan_path.find("StreamTube") != -1, new_chan_path
+    assert new_chan_path.find("SITubesChannel") == -1, new_chan_path
+    # The path of the Channel.Type.Tubes object MUST be different to the path
+    # of the Channel.Type.StreamTube object !
+    assert chan_path != new_chan_path
+
+    check_NewChannel_signal(old_sig.args, "StreamTube.DRAFT", \
+            new_chan_path, handle)
+    check_NewChannels_signal(new_sig.args, "StreamTube.DRAFT", new_chan_path, \
+            handle, contact_name, conn.GetSelfHandle())
+    stream_tube_channel_properties = new_sig.args[0][0]
+
+    check_conn_properties(q, bus, conn,
+            [old_tubes_channel_properties, stream_tube_channel_properties])
+
+    # continue
+    tubes_channel = make_channel_proxy(conn, chan_path, "Channel.Type.Tubes")
+    tube_channel = make_channel_proxy(conn, new_chan_path,
+            "Channel.Type.StreamTube.DRAFT")
+    check_channel_properties(q, bus, conn, tubes_channel, "Tubes", handle,
+            contact_name)
+    check_channel_properties(q, bus, conn, tube_channel, "StreamTube.DRAFT",
+            handle, contact_name, 3)
 
     tube_id = tubes_channel.OfferStreamTube("http", sample_parameters,
             SOCKET_ADDRESS_TYPE_UNIX, dbus.ByteArray(server_socket_address),
@@ -102,7 +302,8 @@ def test(q, bus, conn):
     iq_tube = xpath.queryForNodes('/iq/tube', e.stanza)[0]
     transport = xpath.queryForNodes('/iq/tube/transport', e.stanza)[0]
     assert iq_tube.attributes['type'] == 'stream'
-    assert iq_tube.attributes['service'] == 'http'
+    assert iq_tube.attributes['service'] == 'http', \
+        iq_tube.attributes['service']
     assert iq_tube.attributes['id'] is not None
     port = transport.attributes['port']
     assert port is not None
@@ -146,8 +347,9 @@ def test(q, bus, conn):
     e = q.expect('client-data-received')
     assert e.data == string.swapcase(test_string)
 
-    # Close the tube propertly
-    tubes_channel.CloseTube(tube_id)
+    # Close the tubes propertly
+    for i in tubes_channel.ListTubes():
+        tubes_channel.CloseTube(i[0])
     conn.Disconnect()
 
 if __name__ == '__main__':
-- 
1.5.6.5




More information about the telepathy-commits mailing list