[Telepathy-commits] [telepathy-gabble/master] Channel.Type.{Stream|DBus}Tube are requestable with the new requestotron.

Alban Crequy alban.crequy at collabora.co.uk
Mon Nov 3 11:20:57 PST 2008


- GabblePrivateTubesFactory is a Channel Factory for both
  Channel.Type.Tubes and the new Channel.Type.{Stream|DBus}Tube
  objects.

- GabbleTubeStream implements the Channel.FUTURE properties

- GabbleTubesChannel object has an helper function
  gabble_tubes_channel_tube_request for the factory. The function
  creates the tube channel with the new API.

- The unit test test-si-tubes.py request a stream tube channel
  with the new API.
---
 src/private-tubes-factory.c          |   83 +++++++++++++++++++-----
 src/tube-stream.c                    |   72 +++++++++++++++++++++
 src/tubes-channel.c                  |   45 +++++++++++++
 src/tubes-channel.h                  |    5 ++
 tests/twisted/tubes/test-si-tubes.py |  115 +++++++++++++++++++++++++++++----
 5 files changed, 289 insertions(+), 31 deletions(-)

diff --git a/src/private-tubes-factory.c b/src/private-tubes-factory.c
index 6004e9d..1a75a19 100644
--- a/src/private-tubes-factory.c
+++ b/src/private-tubes-factory.c
@@ -640,10 +640,15 @@ gabble_private_tubes_factory_requestotron (GabblePrivateTubesFactory *self,
       base_conn, TP_HANDLE_TYPE_CONTACT);
   TpHandle handle;
   GError *error = NULL;
-  GabbleExportableChannel *channel;
+  const gchar *channel_type;
+  GabbleTubesChannel *channel;
 
-  if (tp_strdiff (tp_asv_get_string (request_properties,
-          TP_IFACE_CHANNEL ".ChannelType"), TP_IFACE_CHANNEL_TYPE_TUBES))
+  channel_type = tp_asv_get_string (request_properties,
+            TP_IFACE_CHANNEL ".ChannelType");
+
+  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 FALSE;
 
   if (tp_asv_get_uint32 (request_properties,
@@ -659,30 +664,74 @@ gabble_private_tubes_factory_requestotron (GabblePrivateTubesFactory *self,
   /* Don't support opening a channel to our self handle */
   if (handle == base_conn->self_handle)
     {
-     g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-         "Can't open a channel to your self handle");
-     goto error;
+      g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+          "Can't open a channel to your self handle");
+      goto error;
     }
 
   channel = g_hash_table_lookup (self->priv->channels,
       GUINT_TO_POINTER (handle));
 
-  if (channel == NULL)
+  if (! tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES))
     {
-      new_tubes_channel (self, handle, base_conn->self_handle, request_token);
+      if (channel == NULL)
+        {
+          channel = new_tubes_channel (self, handle, base_conn->self_handle,
+              request_token);
+          return TRUE;
+        }
+
+      if (require_new)
+        {
+          g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+              "Already chatting with contact #%u in another channel", handle);
+          DEBUG ("Already chatting with contact #%u in another channel",
+              handle);
+          goto error;
+        }
+
+      gabble_channel_manager_emit_request_already_satisfied (self,
+          request_token, GABBLE_EXPORTABLE_CHANNEL (channel));
       return TRUE;
     }
-
-  if (require_new)
+  else
     {
-      g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-          "Already chatting with contact #%u in another channel", handle);
-      goto error;
-    }
+      GabbleTubeIface *new_channel;
 
-  gabble_channel_manager_emit_request_already_satisfied (self, request_token,
-      channel);
-  return TRUE;
+      if (channel == NULL)
+        {
+          channel = new_tubes_channel (self, handle, base_conn->self_handle,
+              request_token);
+        }
+      g_assert (channel != NULL);
+
+      new_channel = gabble_tubes_channel_tube_request (channel, request_token,
+          request_properties, require_new);
+      if (new_channel != NULL)
+        {
+          GSList *request_tokens;
+
+          tp_channel_factory_iface_emit_new_channel (self,
+              TP_CHANNEL_IFACE (new_channel), request_token);
+
+          if (request_token != NULL)
+            request_tokens = g_slist_prepend (NULL, request_token);
+          else
+            request_tokens = NULL;
+
+          gabble_channel_manager_emit_new_channel (self,
+              GABBLE_EXPORTABLE_CHANNEL (new_channel), request_tokens);
+
+          g_slist_free (request_tokens);
+        }
+      else
+        {
+          gabble_channel_manager_emit_request_already_satisfied (self,
+              request_token, GABBLE_EXPORTABLE_CHANNEL (channel));
+        }
+
+      return TRUE;
+    }
 
 error:
   gabble_channel_manager_emit_request_failed (self, request_token,
diff --git a/src/tube-stream.c b/src/tube-stream.c
index e24f9d9..ea23a87 100644
--- a/src/tube-stream.c
+++ b/src/tube-stream.c
@@ -128,6 +128,10 @@ enum
   PROP_ACCESS_CONTROL_PARAM,
   PROP_CHANNEL_DESTROYED,
   PROP_CHANNEL_PROPERTIES,
+  PROP_REQUESTED,
+  PROP_TARGET_ID,
+  PROP_INITIATOR_HANDLE,
+  PROP_INITIATOR_ID,
   LAST_PROPERTY
 };
 
@@ -975,6 +979,7 @@ gabble_tube_stream_get_property (GObject *object,
 {
   GabbleTubeStream *self = GABBLE_TUBE_STREAM (object);
   GabbleTubeStreamPrivate *priv = GABBLE_TUBE_STREAM_GET_PRIVATE (self);
+  TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn;
 
   switch (property_id)
     {
@@ -1042,6 +1047,36 @@ gabble_tube_stream_get_property (GObject *object,
                 GABBLE_IFACE_CHANNEL_FUTURE, "Requested",
                 NULL));
         break;
+      case PROP_REQUESTED:
+        g_value_set_boolean (value,
+            (priv->initiator == priv->self_handle));
+        break;
+      case PROP_INITIATOR_ID:
+        if (priv->initiator == 0)
+          {
+            g_value_set_static_string (value, "");
+          }
+        else
+          {
+            TpHandleRepoIface *repo = tp_base_connection_get_handles (
+                base_conn, TP_HANDLE_TYPE_CONTACT);
+
+            g_value_set_string (value,
+                tp_handle_inspect (repo, priv->initiator));
+          }
+        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;
+      case PROP_INITIATOR_HANDLE:
+        g_value_set_uint (value, priv->initiator);
+        break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
         break;
@@ -1118,6 +1153,13 @@ gabble_tube_stream_set_property (GObject *object,
                 g_value_get_pointer (value));
           }
         break;
+      case PROP_INITIATOR_HANDLE:
+        /* PROP_INITIATOR_HANDLE and PROP_INITIATOR are the same property from
+         * two different interfaces (Channel.FUTURE and
+         * Channel.Interface.Tube.DRAFT). In case of tube channels, this can
+         * never be 0. The value is stored in priv->initiator. The object is
+         * created only with PROP_INITIATOR set, so do nothing here. */
+        break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
         break;
@@ -1319,6 +1361,36 @@ gabble_tube_stream_class_init (GabbleTubeStreamClass *gabble_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_uint ("initiator-handle", "Initiator's handle",
+      "The contact who initiated the channel",
+      0, G_MAXUINT32, 0,
+      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
+      G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NAME);
+  g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE,
+      param_spec);
+
+  param_spec = g_param_spec_string ("initiator-id", "Initiator's bare JID",
+      "The string obtained by inspecting the initiator-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_INITIATOR_ID,
+      param_spec);
+
+  param_spec = g_param_spec_boolean ("requested", "Requested?",
+      "True if this channel was requested by the local user",
+      FALSE,
+      G_PARAM_READABLE |
+      G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NAME);
+  g_object_class_install_property (object_class, PROP_REQUESTED, param_spec);
+
   signals[OPENED] =
     g_signal_new ("tube-opened",
                   G_OBJECT_CLASS_TYPE (gabble_tube_stream_class),
diff --git a/src/tubes-channel.c b/src/tubes-channel.c
index 901f7e4..c1bc420 100644
--- a/src/tubes-channel.c
+++ b/src/tubes-channel.c
@@ -1582,6 +1582,51 @@ generate_tube_id (void)
   return g_random_int_range (0, G_MAXINT);
 }
 
+GabbleTubeIface *gabble_tubes_channel_tube_request (GabbleTubesChannel *self,
+    gpointer request_token, GHashTable *request_properties,
+    gboolean require_new)
+{
+  GabbleTubesChannelPrivate *priv = GABBLE_TUBES_CHANNEL_GET_PRIVATE (self);
+  GabbleTubeIface *tube;
+  const gchar *channel_type;
+  const gchar *service;
+  GHashTable *parameters = NULL;
+  guint tube_id;
+  TpTubeType type;
+
+  tube_id = generate_tube_id ();
+
+  parameters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+      (GDestroyNotify) tp_g_value_slice_free);
+
+  channel_type = tp_asv_get_string (request_properties,
+            TP_IFACE_CHANNEL ".ChannelType");
+
+  if (! tp_strdiff (channel_type, GABBLE_IFACE_CHANNEL_TYPE_STREAM_TUBE))
+    {
+      type = TP_TUBE_TYPE_STREAM;
+      service = tp_asv_get_string (request_properties,
+                GABBLE_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service");
+
+    }
+  else if (! tp_strdiff (channel_type, GABBLE_IFACE_CHANNEL_TYPE_DBUS_TUBE))
+    {
+      type = TP_TUBE_TYPE_DBUS;
+      service = tp_asv_get_string (request_properties,
+                GABBLE_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName");
+    }
+  else
+    g_assert_not_reached ();
+
+  DEBUG ("Request a tube channel with type='%s' and service='%s'",
+      channel_type, service);
+
+  tube = create_new_tube (self, type, priv->self_handle, service,
+      parameters, NULL, tube_id, NULL);
+
+  return tube;
+}
+
 /**
  * gabble_tubes_channel_offer_d_bus_tube
  *
diff --git a/src/tubes-channel.h b/src/tubes-channel.h
index 2f71b19..92f25a9 100644
--- a/src/tubes-channel.h
+++ b/src/tubes-channel.h
@@ -28,6 +28,7 @@
 #include "bytestream-iface.h"
 #include "exportable-channel.h"
 #include "muc-channel.h"
+#include "tube-iface.h"
 
 G_BEGIN_DECLS
 
@@ -71,6 +72,10 @@ GType gabble_tubes_channel_get_type (void);
 void gabble_tubes_channel_foreach (GabbleTubesChannel *self,
     GabbleExportableChannelFunc foreach, gpointer user_data);
 
+GabbleTubeIface *gabble_tubes_channel_tube_request (GabbleTubesChannel *self,
+    gpointer request_token, GHashTable *request_properties,
+    gboolean require_new);
+
 void gabble_tubes_channel_presence_updated (GabbleTubesChannel *chan,
     TpHandle contact, LmMessage *presence);
 
diff --git a/tests/twisted/tubes/test-si-tubes.py b/tests/twisted/tubes/test-si-tubes.py
index 23371a6..4f569c7 100644
--- a/tests/twisted/tubes/test-si-tubes.py
+++ b/tests/twisted/tubes/test-si-tubes.py
@@ -63,6 +63,14 @@ def test(q, bus, conn, stream):
              []
              ) 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'],
+             []
+             ) in properties.get('RequestableChannelClasses'),\
+                     properties['RequestableChannelClasses']
 
     _, vcard_event, roster_event = q.expect_many(
         EventPattern('dbus-signal', signal='StatusChanged', args=[0, 1]),
@@ -101,6 +109,7 @@ def test(q, bus, conn, stream):
 
     bob_handle = conn.RequestHandles(1, ['bob at localhost'])[0]
 
+    # old requestotron
     call_async(q, conn, 'RequestChannel',
             tp_name_prefix + '.Channel.Type.Tubes', 1, bob_handle, True);
 
@@ -110,7 +119,6 @@ def test(q, bus, conn, stream):
         EventPattern('dbus-signal', signal='NewChannels'),
         )
 
-
     assert len(ret.value) == 1
     chan_path = ret.value[0]
 
@@ -146,6 +154,85 @@ def test(q, bus, conn, stream):
     assert new_sig.args[0][0] in properties['Channels'], \
             (new_sig.args[0][0], properties['Channels'])
 
+    # new requestotron
+    requestotron = dbus.Interface(conn,
+            'org.freedesktop.Telepathy.Connection.Interface.Requests.DRAFT')
+
+#    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':
+#                bob_handle
+#            });
+#    # some properties are missing in the request, we expect gabble to return
+#    # the relevent error
+#    ret = q.expect_many(EventPattern('dbus-error', method='CreateChannel'))
+
+    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':
+                bob_handle,
+             'org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service':
+                "newecho",
+            });
+
+    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
+
+    print "new_chan_path = " + new_chan_path
+    print "chan_path = " + chan_path
+
+    assert old_sig.args[0] == new_chan_path
+    assert old_sig.args[1] == tp_name_prefix + '.Channel.Type.StreamTube.DRAFT', old_sig.args[1]
+    assert old_sig.args[2] == 1         # contact handle
+    assert old_sig.args[3] == bob_handle
+    assert old_sig.args[4] == True      # suppress handler
+
+    assert len(new_sig.args) == 1
+    assert len(new_sig.args[0]) == 1        # one channel
+    assert len(new_sig.args[0][0]) == 2     # two struct members
+    assert new_sig.args[0][0][0] == ret.value[0]
+    emitted_props = new_sig.args[0][0][1]
+    print str(emitted_props)
+
+    assert emitted_props[tp_name_prefix + '.Channel.ChannelType'] ==\
+            tp_name_prefix + '.Channel.Type.StreamTube.DRAFT'
+    assert emitted_props[tp_name_prefix + '.Channel.TargetHandleType'] == 1
+    assert emitted_props[tp_name_prefix + '.Channel.TargetHandle'] ==\
+            bob_handle
+    assert emitted_props[tp_name_prefix + '.Channel.FUTURE.Requested'] == True
+    assert emitted_props[tp_name_prefix + '.Channel.FUTURE.TargetID'] == \
+            'bob at localhost', emitted_props[tp_name_prefix + '.Channel.FUTURE.TargetID']
+    assert emitted_props[tp_name_prefix + '.Channel.FUTURE.InitiatorHandle'] \
+            == conn.GetSelfHandle()
+    assert emitted_props[tp_name_prefix + '.Channel.FUTURE.InitiatorID'] == \
+            'test at localhost'
+
+    properties = conn.GetAll(
+            'org.freedesktop.Telepathy.Connection.Interface.Requests.DRAFT',
+            dbus_interface='org.freedesktop.DBus.Properties')
+
+    assert new_sig.args[0][0] in properties['Channels'], \
+            (new_sig.args[0][0], properties['Channels'])
+
+    ## following
     tubes_chan = bus.get_object(conn.bus_name, chan_path)
     tubes_iface = dbus.Interface(tubes_chan,
         tp_name_prefix + '.Channel.Type.Tubes')
@@ -208,18 +295,15 @@ def test(q, bus, conn, stream):
                       'u': ('uint', '123'),
                      }
 
-    # We offered a tube using the old tube API. Check the new tube API works
+    # We offered a tube using the old tube API and with the new API, so there
+    # is 2 tubes. Check the new tube API works
     assert len(filter(lambda x:
                   x[1] == "org.freedesktop.Telepathy.Channel.Type.Tubes",
                   conn.ListChannels())) == 1
-    assert len(filter(lambda x:
-      x[1] == "org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT",
-      conn.ListChannels())) == 1
-
     channels = filter(lambda x: x[1]
       == "org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT",
       conn.ListChannels())
-    assert len(channels) == 1
+    assert len(channels) == 2
 
     tube_chan = bus.get_object(conn.bus_name, channels[0][0])
     tube_iface = dbus.Interface(tubes_chan,
@@ -228,7 +312,7 @@ def test(q, bus, conn, stream):
     stream_tube_props = tube_chan.GetAll(
             'org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT',
             dbus_interface='org.freedesktop.DBus.Properties')
-    assert stream_tube_props.get("Service") == "echo"
+    assert stream_tube_props.get("Service") == "newecho", stream_tube_props
 
     tube_props = tube_chan.GetAll(
             'org.freedesktop.Telepathy.Channel.Interface.Tube.DRAFT',
@@ -240,7 +324,9 @@ def test(q, bus, conn, stream):
     #                  'i': ('int', '-123'),
     #                  'u': ('uint', '123'),
     #                 }
-    assert tube_props.get("Status") == 1 # Tube_Channel_State_Remote_Pending
+
+    # 3 == Tube_Channel_State_Not_Offered
+    assert tube_props.get("Status") == 3, tube_props
 
     # The CM is the server, so fake a client wanting to talk to it
     iq = IQ(stream, 'set')
@@ -281,14 +367,14 @@ def test(q, bus, conn, stream):
         args=[stream_tube_id, bob_handle])
 
     tubes = tubes_iface.ListTubes(byte_arrays=True)
-    assert tubes == [(
+    assert (
         stream_tube_id,
         self_handle,
         1,      # Unix stream
         'echo',
         sample_parameters,
         2,      # OPEN
-        )]
+        ) in tubes
 
     # have the fake client open the stream
     iq = IQ(stream, 'set')
@@ -400,21 +486,22 @@ def test(q, bus, conn, stream):
         args=[dbus_tube_id, 2]) # 2 == OPEN
 
     tubes = tubes_iface.ListTubes(byte_arrays=True)
-    assert sorted(tubes) == sorted([(
+    assert (
         dbus_tube_id,
         self_handle,
         0,      # DBUS
         'com.example.TestCase',
         sample_parameters,
         2,      # OPEN
-        ),(
+        ) in tubes
+    assert (
         stream_tube_id,
         self_handle,
         1,      # stream
         'echo',
         sample_parameters,
         2,      # OPEN
-        )])
+        ) in tubes
 
     dbus_tube_adr = tubes_iface.GetDBusTubeAddress(dbus_tube_id)
     dbus_tube_conn = Connection(dbus_tube_adr)
-- 
1.5.6.5




More information about the Telepathy-commits mailing list