telepathy-salut: muc-channel: add way to request single Tube channels

Jonny Lamb jonny at kemper.freedesktop.org
Tue Aug 28 06:30:43 PDT 2012


Module: telepathy-salut
Branch: master
Commit: f60a51b46c64e5db8469cd9e89a7107de4454be3
URL:    http://cgit.freedesktop.org/telepathy/telepathy-salut/commit/?id=f60a51b46c64e5db8469cd9e89a7107de4454be3

Author: Jonny Lamb <jonny.lamb at collabora.co.uk>
Date:   Tue May 29 11:18:06 2012 +0100

muc-channel: add way to request single Tube channels

Signed-off-by: Jonny Lamb <jonny.lamb at collabora.co.uk>

---

 src/muc-channel.c |  152 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/muc-channel.h |    4 ++
 src/muc-manager.c |   21 +++++++
 3 files changed, 177 insertions(+), 0 deletions(-)

diff --git a/src/muc-channel.c b/src/muc-channel.c
index 38bf002..d403a85 100644
--- a/src/muc-channel.c
+++ b/src/muc-channel.c
@@ -53,6 +53,7 @@
 
 #include "text-helper.h"
 #include "tube-stream.h"
+#include "tube-dbus.h"
 
 G_DEFINE_TYPE_WITH_CODE(SalutMucChannel, salut_muc_channel, TP_TYPE_BASE_CHANNEL,
     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP,
@@ -74,6 +75,7 @@ enum
 {
     READY,
     JOIN_ERROR,
+    NEW_TUBE,
     LAST_SIGNAL
 };
 
@@ -100,6 +102,8 @@ struct _SalutMucChannelPrivate
   /* (gchar *) -> (SalutContact *) */
   GHashTable *senders;
   SalutMucManager *muc_manager;
+
+  GHashTable *tubes;
 };
 
 /* Callback functions */
@@ -306,6 +310,9 @@ salut_muc_channel_constructed (GObject *obj)
       TP_CHANNEL_GROUP_FLAG_CAN_ADD |
       TP_CHANNEL_GROUP_FLAG_MESSAGE_ADD,
       0);
+
+  priv->tubes = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+      NULL, (GDestroyNotify) g_object_unref);
 }
 
 static void
@@ -693,6 +700,17 @@ salut_muc_channel_class_init (SalutMucChannelClass *salut_muc_channel_class)
         g_cclosure_marshal_VOID__POINTER,
         G_TYPE_NONE, 1, G_TYPE_POINTER);
 
+  signals[NEW_TUBE] = g_signal_new (
+      "new-tube",
+      G_OBJECT_CLASS_TYPE (salut_muc_channel_class),
+      G_SIGNAL_RUN_LAST,
+      0,
+      NULL, NULL,
+      g_cclosure_marshal_VOID__OBJECT,
+      /* this should be SALUT_TYPE_TUBE_IFACE but GObject
+       * wants a value type, not an interface. */
+      G_TYPE_NONE, 1, TP_TYPE_BASE_CHANNEL);
+
   tp_group_mixin_class_init (object_class,
       G_STRUCT_OFFSET(SalutMucChannelClass, group_class),
       salut_muc_channel_add_member, NULL);
@@ -737,6 +755,8 @@ salut_muc_channel_dispose (GObject *object)
       priv->senders = NULL;
     }
 
+  tp_clear_pointer (&priv->tubes, g_hash_table_unref);
+
   /* release any references held by the object here */
   if (G_OBJECT_CLASS (salut_muc_channel_parent_class)->dispose)
     G_OBJECT_CLASS (salut_muc_channel_parent_class)->dispose (object);
@@ -1146,3 +1166,135 @@ error:
   return;
 }
 
+static void
+tube_closed_cb (SalutTubeIface *tube,
+    SalutMucChannel *self)
+{
+  SalutMucChannelPrivate *priv = self->priv;
+  guint id;
+
+  g_object_get (tube,
+      "id", &id,
+      NULL);
+
+  if (priv->tubes != NULL)
+    g_hash_table_remove (priv->tubes, GUINT_TO_POINTER (id));
+}
+
+static guint
+generate_tube_id (SalutMucChannel *self)
+{
+  SalutMucChannelPrivate *priv = self->priv;
+  guint out;
+
+  /* probably totally overkill */
+  do
+    {
+      out = g_random_int_range (0, G_MAXINT);
+    }
+  while (g_hash_table_lookup (priv->tubes,
+          GUINT_TO_POINTER (out)) != NULL);
+
+  return out;
+}
+
+static SalutTubeIface *
+create_new_tube (SalutMucChannel *self,
+    TpTubeType type,
+    TpHandle initiator,
+    const gchar *service,
+    GHashTable *parameters,
+    guint tube_id,
+    guint portnum,
+    WockyStanza *iq_req,
+    gboolean requested)
+{
+  SalutMucChannelPrivate *priv = self->priv;
+  TpBaseChannel *base = TP_BASE_CHANNEL (self);
+  TpBaseConnection *base_conn = tp_base_channel_get_connection (base);
+  SalutConnection *conn = SALUT_CONNECTION (base_conn);
+  TpHandle self_handle = TP_GROUP_MIXIN (self)->self_handle;
+  TpHandle handle = tp_base_channel_get_target_handle (base);
+  SalutTubeIface *tube;
+
+  switch (type)
+    {
+    case TP_TUBE_TYPE_DBUS:
+      tube = SALUT_TUBE_IFACE (salut_tube_dbus_new (conn, NULL,
+              handle, TP_HANDLE_TYPE_ROOM, self_handle, priv->muc_connection,
+              initiator, service, parameters, tube_id, requested));
+      break;
+    case TP_TUBE_TYPE_STREAM:
+      tube = SALUT_TUBE_IFACE (salut_tube_stream_new (conn, NULL,
+              handle, TP_HANDLE_TYPE_ROOM,
+              self_handle, initiator, FALSE, service,
+              parameters, tube_id, portnum, iq_req, requested));
+      break;
+    default:
+      g_return_val_if_reached (NULL);
+    }
+
+  tp_base_channel_register ((TpBaseChannel *) tube);
+
+  DEBUG ("create tube %u", tube_id);
+  g_hash_table_insert (priv->tubes, GUINT_TO_POINTER (tube_id), tube);
+
+  g_signal_connect (tube, "closed", G_CALLBACK (tube_closed_cb), self);
+
+  return tube;
+}
+
+SalutTubeIface *
+salut_muc_channel_tube_request (SalutMucChannel *self,
+    GHashTable *request_properties)
+{
+  SalutTubeIface *tube;
+  const gchar *channel_type;
+  const gchar *service;
+  GHashTable *parameters = NULL;
+  guint tube_id;
+  TpTubeType type;
+
+  tube_id = generate_tube_id (self);
+
+  channel_type = tp_asv_get_string (request_properties,
+      TP_PROP_CHANNEL_CHANNEL_TYPE);
+
+  if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE))
+    {
+      type = TP_TUBE_TYPE_STREAM;
+      service = tp_asv_get_string (request_properties,
+          TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE);
+
+    }
+  else if (! tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE))
+    {
+      type = TP_TUBE_TYPE_DBUS;
+      service = tp_asv_get_string (request_properties,
+          TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME);
+    }
+  else
+    /* This assertion is safe: this function's caller only calls it in one of
+     * the above cases.
+     * FIXME: but it would be better to pass an enum member or something maybe.
+     */
+    g_assert_not_reached ();
+
+  /* requested tubes have an empty parameters dict */
+  parameters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+      (GDestroyNotify) tp_g_value_slice_free);
+
+  /* if the service property is missing, the requestotron rejects the request
+   */
+  g_assert (service != NULL);
+
+  DEBUG ("Request a tube channel with type='%s' and service='%s'",
+      channel_type, service);
+
+  tube = create_new_tube (self, type, TP_GROUP_MIXIN (self)->self_handle,
+      service, parameters, tube_id, 0, NULL, TRUE);
+  g_hash_table_unref (parameters);
+
+  return tube;
+}
+
diff --git a/src/muc-channel.h b/src/muc-channel.h
index 3bb01f0..79787af 100644
--- a/src/muc-channel.h
+++ b/src/muc-channel.h
@@ -30,6 +30,7 @@
 #include <gibber/gibber-muc-connection.h>
 
 #include "connection.h"
+#include "tube-iface.h"
 
 G_BEGIN_DECLS
 
@@ -89,6 +90,9 @@ gboolean salut_muc_channel_publish_service (SalutMucChannel *self);
 gboolean salut_muc_channel_add_member (GObject *iface, TpHandle handle,
     const gchar *message, GError **error);
 
+SalutTubeIface * salut_muc_channel_tube_request (SalutMucChannel *self,
+    GHashTable *request_properties);
+
 G_END_DECLS
 
 #endif /* #ifndef __SALUT_MUC_CHANNEL_H__*/
diff --git a/src/muc-manager.c b/src/muc-manager.c
index f160a99..6e0b4b4 100644
--- a/src/muc-manager.c
+++ b/src/muc-manager.c
@@ -444,6 +444,26 @@ tubes_channel_closed_cb (SalutTubesChannel *chan,
     }
 }
 
+static void
+muc_channel_tube_closed_cb (SalutTubeIface *tube,
+    SalutMucManager *mgr)
+{
+  tp_channel_manager_emit_channel_closed_for_object (mgr,
+      TP_EXPORTABLE_CHANNEL (tube));
+}
+
+static void
+muc_channel_new_tube_cb (SalutMucChannel *channel,
+    SalutTubeIface *tube,
+    SalutMucManager *mgr)
+{
+  tp_channel_manager_emit_new_channel (mgr,
+      TP_EXPORTABLE_CHANNEL (tube), NULL);
+
+  g_signal_connect (tube, "closed",
+      G_CALLBACK (muc_channel_tube_closed_cb), mgr);
+}
+
 static GibberMucConnection *
 _get_connection (SalutMucManager *mgr,
                  const gchar *protocol,
@@ -490,6 +510,7 @@ salut_muc_manager_new_muc_channel (SalutMucManager *mgr,
   tp_base_channel_register ((TpBaseChannel *) chan);
 
   g_signal_connect (chan, "closed", G_CALLBACK (muc_channel_closed_cb), mgr);
+  g_signal_connect (chan, "new-tube", G_CALLBACK (muc_channel_new_tube_cb), mgr);
 
   g_hash_table_insert (priv->text_channels, GUINT_TO_POINTER (handle), chan);
 



More information about the telepathy-commits mailing list