[Telepathy-commits] [telepathy-sofiasip/master] Reimplemented TpsipMediaFactory as an implementation of TpChannelManager

Mikhail Zabaluev mikhail.zabaluev at nokia.com
Thu Nov 6 04:51:11 PST 2008


TpsipMediaChannel changed to comply.
---
 src/media-factory.c     |  540 ++++++++++++++++++++++++++++++-----------------
 src/sip-media-channel.c |   55 +++++-
 2 files changed, 394 insertions(+), 201 deletions(-)

diff --git a/src/media-factory.c b/src/media-factory.c
index 203252e..8350ccb 100644
--- a/src/media-factory.c
+++ b/src/media-factory.c
@@ -1,6 +1,6 @@
 /*
  * media-factory.c - Media channel factory for SIP connection manager
- * Copyright (C) 2007 Collabora Ltd.
+ * Copyright (C) 2007-2008 Collabora Ltd.
  * Copyright (C) 2007-2008 Nokia Corporation
  *
  * This work is free software; you can redistribute it and/or
@@ -22,7 +22,8 @@
 
 #include <string.h>
 
-#include <telepathy-glib/svc-connection.h>
+#include <telepathy-glib/channel-manager.h>
+#include <telepathy-glib/dbus.h>
 #include <telepathy-glib/interfaces.h>
 
 #include "sip-connection.h"
@@ -33,12 +34,14 @@
 #define DEBUG_FLAG TPSIP_DEBUG_CONNECTION
 #include "debug.h"
 
-static void factory_iface_init (gpointer, gpointer);
+static void channel_manager_iface_init (gpointer, gpointer);
+static void tpsip_media_factory_constructed (GObject *object);
+static void tpsip_media_factory_close_all (TpsipMediaFactory *fac);
 
 G_DEFINE_TYPE_WITH_CODE (TpsipMediaFactory, tpsip_media_factory,
     G_TYPE_OBJECT,
-    G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_FACTORY_IFACE,
-      factory_iface_init))
+    G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
+        channel_manager_iface_init))
 
 enum
 {
@@ -58,6 +61,9 @@ struct _TpsipMediaFactoryPrivate
   /* for unique channel object paths, currently always increments */
   guint channel_index;
 
+  gulong status_changed_id;
+  gulong invite_received_id;
+
   gchar *stun_server;
   guint16 stun_port;
 
@@ -88,17 +94,23 @@ tpsip_media_factory_dispose (GObject *object)
 
   priv->dispose_has_run = TRUE;
 
-  tp_channel_factory_iface_close_all (TP_CHANNEL_FACTORY_IFACE (object));
-
+  tpsip_media_factory_close_all (fac);
   g_assert (priv->channels == NULL);
 
-  g_free (priv->stun_server);
-
   if (G_OBJECT_CLASS (tpsip_media_factory_parent_class)->dispose)
     G_OBJECT_CLASS (tpsip_media_factory_parent_class)->dispose (object);
 }
 
 static void
+tpsip_media_factory_finalize (GObject *object)
+{
+  TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (object);
+  TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac);
+
+  g_free (priv->stun_server);
+}
+
+static void
 tpsip_media_factory_get_property (GObject *object,
                                guint property_id,
                                GValue *value,
@@ -157,9 +169,11 @@ tpsip_media_factory_class_init (TpsipMediaFactoryClass *klass)
 
   g_type_class_add_private (klass, sizeof (TpsipMediaFactoryPrivate));
 
+  object_class->constructed = tpsip_media_factory_constructed;
   object_class->get_property = tpsip_media_factory_get_property;
   object_class->set_property = tpsip_media_factory_set_property;
   object_class->dispose = tpsip_media_factory_dispose;
+  object_class->finalize = tpsip_media_factory_finalize;
 
   param_spec = g_param_spec_object ("connection", "TpsipConnection object",
       "SIP connection that owns this media channel factory",
@@ -182,68 +196,49 @@ tpsip_media_factory_class_init (TpsipMediaFactoryClass *klass)
 }
 
 static void
-tpsip_media_factory_close_one (gpointer data, gpointer user_data)
+tpsip_media_factory_close_all (TpsipMediaFactory *fac)
 {
-  tpsip_media_channel_close (TPSIP_MEDIA_CHANNEL(data));
-  g_object_unref (data);
-}
-
-static void
-tpsip_media_factory_close_all (TpChannelFactoryIface *iface)
-{
-  TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (iface);
   TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac);
-  GPtrArray *channels;
 
-  channels = priv->channels;
-  priv->channels = NULL;
-  if (channels)
+  if (priv->status_changed_id != 0)
     {
-      g_ptr_array_foreach (channels, tpsip_media_factory_close_one, NULL);
-      g_ptr_array_free (channels, TRUE);
+      g_signal_handler_disconnect (priv->conn,
+          priv->status_changed_id);
+      priv->status_changed_id = 0;
     }
-}
-
-struct _ForeachData
-{
-  TpChannelFunc foreach;
-  gpointer user_data;
-};
-
-static void
-_foreach_slave (gpointer channel, gpointer user_data)
-{
-  struct _ForeachData *data = (struct _ForeachData *)user_data;
-  TpChannelIface *chan = TP_CHANNEL_IFACE (channel);
 
-  data->foreach (chan, data->user_data);
-}
+  if (priv->channels != NULL)
+    {
+      GPtrArray *channels;
+      guint i;
 
-static void
-tpsip_media_factory_foreach (TpChannelFactoryIface *iface,
-                          TpChannelFunc foreach,
-                          gpointer user_data)
-{
-  TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (iface);
-  TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac);
+      channels = priv->channels;
+      priv->channels = NULL;
 
-  struct _ForeachData data = { foreach, user_data };
+      for (i = 0; i < channels->len; i++)
+        {
+          TpsipMediaChannel *chan = g_ptr_array_index (channels, i);
+          g_object_unref (chan);
+        }
 
-  g_ptr_array_foreach (priv->channels, _foreach_slave, &data);
+      g_ptr_array_free (channels, TRUE);
+    }
 }
 
 /**
- * channel_closed:
- *
+ * media_channel_closed_cb:
  * Signal callback for when a media channel is closed. Removes the references
  * that #TpsipMediaFactory holds to them.
  */
 static void
-channel_closed (TpsipMediaChannel *chan, gpointer user_data)
+media_channel_closed_cb (TpsipMediaChannel *chan, gpointer user_data)
 {
   TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (user_data);
   TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac);
 
+  tp_channel_manager_emit_channel_closed_for_object (fac,
+      TP_EXPORTABLE_CHANNEL (chan));
+
   if (priv->channels)
     {
       g_ptr_array_remove_fast (priv->channels, chan);
@@ -257,12 +252,9 @@ channel_closed (TpsipMediaChannel *chan, gpointer user_data)
  * Creates a new empty TpsipMediaChannel.
  */
 static TpsipMediaChannel *
-tpsip_media_factory_new_channel (TpsipMediaFactory *fac,
-                                 gpointer request,
-                                 TpHandleType handle_type,
-                                 TpHandle handle,
-                                 TpHandle initiator,
-                                 GError **error)
+new_media_channel (TpsipMediaFactory *fac,
+                   TpHandle initiator,
+                   TpHandle maybe_peer)
 {
   TpsipMediaFactoryPrivate *priv;
   TpsipMediaChannel *chan = NULL;
@@ -275,29 +267,6 @@ tpsip_media_factory_new_channel (TpsipMediaFactory *fac,
   priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac);
   conn = (TpBaseConnection *)priv->conn;
 
-  switch (handle_type)
-    {
-    case TP_HANDLE_TYPE_CONTACT:
-      if (!tp_handle_is_valid (
-              tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT),
-              handle, error))
-        goto err;
-      break;
-    case TP_HANDLE_TYPE_NONE:
-      if (handle != 0)
-        {
-          g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
-              "TargetHandle must be zero or omitted if TargetHandleType is "
-              "NONE");
-          goto err;
-        }
-      break;
-    default:
-      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-          "SIP media channels can not be created with this handle type");
-      goto err;
-    }
-
   object_path = g_strdup_printf ("%s/MediaChannel%u", conn->object_path,
       priv->channel_index++);
 
@@ -311,7 +280,7 @@ tpsip_media_factory_new_channel (TpsipMediaFactory *fac,
   chan = g_object_new (TPSIP_TYPE_MEDIA_CHANNEL,
                        "connection", priv->conn,
                        "object-path", object_path,
-                       "handle", handle,
+                       "handle", maybe_peer,
                        "initiator", initiator,
                        "nat-traversal", nat_traversal,
                        NULL);
@@ -325,86 +294,11 @@ tpsip_media_factory_new_channel (TpsipMediaFactory *fac,
         g_object_set ((GObject *) chan, "stun-port", priv->stun_port, NULL);
     }
 
-  if (handle_type == TP_HANDLE_TYPE_CONTACT && handle != initiator)
-    {
-      g_assert (initiator == conn->self_handle);
-
-      if (!_tpsip_media_channel_add_member ((GObject *) chan,
-               handle, "", error))
-        goto err;
-    }
-
-  g_signal_connect (chan, "closed", (GCallback) channel_closed, fac);
+  g_signal_connect (chan, "closed", G_CALLBACK (media_channel_closed_cb), fac);
 
   g_ptr_array_add (priv->channels, chan);
 
-  tp_channel_factory_iface_emit_new_channel (fac, (TpChannelIface *)chan,
-      request);
-
   return chan;
-
-err:
-  if (chan != NULL)
-    g_object_unref (chan);
-  return NULL;
-}
-
-static TpChannelFactoryRequestStatus
-tpsip_media_factory_request (TpChannelFactoryIface *iface,
-                             const gchar *chan_type,
-                             TpHandleType handle_type,
-                             TpHandle handle,
-                             gpointer request,
-                             TpChannelIface **ret,
-                             GError **error_ret)
-{
-  TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (iface);
-  TpsipMediaFactoryPrivate *priv;
-  TpChannelIface *chan;
-  TpChannelFactoryRequestStatus status = TP_CHANNEL_FACTORY_REQUEST_STATUS_ERROR;
-  TpBaseConnection *base_conn;
-  GError *error = NULL;
-
-  if (strcmp (chan_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA))
-    {
-      return TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_IMPLEMENTED;
-    }
-
-  priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac);
-  base_conn = (TpBaseConnection *)priv->conn;
-
-  chan = (TpChannelIface *) tpsip_media_factory_new_channel (fac,
-                                                             request,
-                                                             handle_type,
-                                                             handle,
-                                                             base_conn->self_handle,
-                                                             &error);
-  if (chan != NULL)
-    {
-      *ret = chan;
-      status = TP_CHANNEL_FACTORY_REQUEST_STATUS_CREATED;
-    }
-  else
-    {
-      g_assert (error != NULL);
-      switch (error->code)
-        {
-        case TP_ERROR_INVALID_HANDLE:
-        case TP_ERROR_INVALID_ARGUMENT:
-          status = TP_CHANNEL_FACTORY_REQUEST_STATUS_INVALID_HANDLE;
-          break;
-        case TP_ERROR_NOT_AVAILABLE:
-          status = TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_AVAILABLE;
-          break;
-        default:
-          status = TP_CHANNEL_FACTORY_REQUEST_STATUS_ERROR;
-        }
-      if (error_ret != NULL)
-        *error_ret = error;
-      else
-        g_error_free (error);
-    }
-  return status;
 }
 
 static gboolean
@@ -416,7 +310,6 @@ tpsip_nua_i_invite_cb (TpBaseConnection    *conn,
   TpsipMediaChannel *channel;
   TpHandleRepoIface *contact_repo;
   TpHandle handle;
-  GError *error = NULL;
 
   /* figure out a handle for the identity */
 
@@ -433,23 +326,9 @@ tpsip_nua_i_invite_cb (TpBaseConnection    *conn,
   DEBUG("Got incoming invite from <%s>",
         tp_handle_inspect (contact_repo, handle));
 
-  channel = tpsip_media_factory_new_channel (
-                fac,
-                NULL,
-                TP_HANDLE_TYPE_CONTACT,
-                handle,
-                handle,
-                &error);
-  if (channel)
-    {
-      tpsip_media_channel_receive_invite (channel, ev->nua_handle);
-    }
-  else
-    {
-      g_warning ("creation of SIP media channel failed: %s", error->message);
-      g_error_free (error);
-      nua_respond (ev->nua_handle, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
-    }
+  channel = new_media_channel (fac, handle, handle);
+
+  tpsip_media_channel_receive_invite (channel, ev->nua_handle);
 
   tp_handle_unref (contact_repo, handle);
 
@@ -457,38 +336,305 @@ tpsip_nua_i_invite_cb (TpBaseConnection    *conn,
 }
 
 static void
-tpsip_media_factory_connected (TpChannelFactoryIface *iface)
+connection_status_changed_cb (TpsipConnection *conn,
+                              guint status,
+                              guint reason,
+                              TpsipMediaFactory *self)
 {
-  TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (iface);
-  TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac);
+  TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (self);
 
-  g_signal_connect (priv->conn,
-       "nua-event::nua_i_invite",
-       G_CALLBACK (tpsip_nua_i_invite_cb),
-       fac);
+  switch (status)
+    {
+    case TP_CONNECTION_STATUS_CONNECTED:
+
+      priv->invite_received_id = g_signal_connect (conn,
+          "nua-event::nua_i_invite",
+          G_CALLBACK (tpsip_nua_i_invite_cb), self);
+
+      break;
+    case TP_CONNECTION_STATUS_DISCONNECTED:
+
+      tpsip_media_factory_close_all (self);
+
+      g_signal_handler_disconnect (conn, priv->invite_received_id);
+      priv->invite_received_id = 0;
+
+      break;
+    default:
+      break;
+    }
 }
 
 static void
-tpsip_media_factory_disconnected (TpChannelFactoryIface *iface)
+tpsip_media_factory_constructed (GObject *object)
 {
-  TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (iface);
+  TpsipMediaFactory *self = TPSIP_MEDIA_FACTORY (object);
+  TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (self);
+  GObjectClass *parent_object_class =
+      G_OBJECT_CLASS (tpsip_media_factory_parent_class);
+
+  if (parent_object_class->constructed != NULL)
+    parent_object_class->constructed (object);
+
+  priv->status_changed_id = g_signal_connect (priv->conn,
+      "status-changed", (GCallback) connection_status_changed_cb, object);
+}
+
+static void
+tpsip_media_factory_foreach_channel (TpChannelManager *manager,
+                                     TpExportableChannelFunc foreach,
+                                     gpointer user_data)
+{
+  TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (manager);
   TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac);
+  guint i;
+
+  for (i = 0; i < priv->channels->len; i++)
+    {
+      TpExportableChannel *channel = TP_EXPORTABLE_CHANNEL (
+          g_ptr_array_index (priv->channels, i));
+
+      foreach (channel, user_data);
+    }
+}
+
+static const gchar * const media_channel_fixed_properties[] = {
+    TP_IFACE_CHANNEL ".ChannelType",
+    TP_IFACE_CHANNEL ".TargetHandleType",
+    NULL
+};
+
+static const gchar * const named_channel_allowed_properties[] = {
+    TP_IFACE_CHANNEL ".TargetHandle",
+    TP_IFACE_CHANNEL ".TargetID",
+    NULL
+};
+
+static const gchar * const anon_channel_allowed_properties[] = {
+    NULL
+};
+
+static void
+tpsip_media_factory_foreach_channel_class (TpChannelManager *manager,
+    TpChannelManagerChannelClassFunc func,
+    gpointer user_data)
+{
+  GHashTable *table = g_hash_table_new_full (g_str_hash, g_str_equal,
+      NULL, (GDestroyNotify) tp_g_value_slice_free);
+  GValue *value, *handle_type_value;
+
+  value = tp_g_value_slice_new (G_TYPE_STRING);
+  g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA);
+  g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType", value);
+
+  handle_type_value = tp_g_value_slice_new (G_TYPE_UINT);
+  /* no uint value yet - we'll change it for each channel class */
+  g_hash_table_insert (table, TP_IFACE_CHANNEL ".TargetHandleType",
+      handle_type_value);
+
+  g_value_set_uint (handle_type_value, TP_HANDLE_TYPE_NONE);
+  func (manager, table, anon_channel_allowed_properties, user_data);
+
+  g_value_set_uint (handle_type_value, TP_HANDLE_TYPE_CONTACT);
+  func (manager, table, named_channel_allowed_properties, user_data);
+
+  g_hash_table_destroy (table);
+}
+
+typedef enum
+{
+  METHOD_REQUEST,
+  METHOD_CREATE,
+  METHOD_ENSURE,
+} RequestMethod;
+
+static gboolean
+tpsip_media_factory_requestotron (TpChannelManager *manager,
+                                  gpointer request_token,
+                                  GHashTable *request_properties,
+                                  RequestMethod method)
+{
+  TpsipMediaFactory *self = TPSIP_MEDIA_FACTORY (manager);
+  TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (self);
+  TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
+  TpHandleType handle_type;
+  TpHandle handle;
+  TpsipMediaChannel *channel = NULL;
+  GError *error = NULL;
+  GSList *request_tokens;
+  gboolean require_target_handle;
+  gboolean add_peer_to_remote_pending;
+
+  /* Supported modes of operation:
+   * - RequestChannel(None, 0):
+   *     channel is anonymous;
+   *     caller uses RequestStreams to set the peer and start the call.
+   * - RequestChannel(Contact, n) where n != 0:
+   *     channel has TargetHandle=n;
+   *     n is in remote pending;
+   *     call is started when caller calls RequestStreams.
+   * - CreateChannel({THT: Contact, TH: n}):
+   *     channel has TargetHandle=n
+   *     n is not in the group interface at all
+   *     call is started when caller calls RequestStreams.
+   * - EnsureChannel({THT: Contact, TH: n}):
+   *     look for a channel whose peer is n, and return that if found with
+   *       whatever properties and group membership it has;
+   *     otherwise the same as into CreateChannel
+   */
+  switch (method)
+    {
+    case METHOD_REQUEST:
+      require_target_handle = FALSE;
+      add_peer_to_remote_pending = TRUE;
+      break;
+    case METHOD_CREATE:
+    case METHOD_ENSURE:
+      require_target_handle = TRUE;
+      add_peer_to_remote_pending = FALSE;
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+
+  if (tp_strdiff (tp_asv_get_string (request_properties,
+          TP_IFACE_CHANNEL ".ChannelType"),
+        TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA))
+    return FALSE;
+
+  handle_type = tp_asv_get_uint32 (request_properties,
+      TP_IFACE_CHANNEL ".TargetHandleType", NULL);
+
+  handle = tp_asv_get_uint32 (request_properties,
+      TP_IFACE_CHANNEL ".TargetHandle", NULL);
+
+  switch (handle_type)
+    {
+    case TP_HANDLE_TYPE_NONE:
+      if (handle != 0)
+        {
+          g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+              "TargetHandle must be zero or omitted if TargetHandleType is "
+              "NONE");
+          goto error;
+        }
+
+      if (require_target_handle)
+        {
+          g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
+              "A valid Contact handle must be provided when requesting a media "
+              "channel");
+          goto error;
+        }
+
+      if (tp_channel_manager_asv_has_unknown_properties (request_properties,
+              media_channel_fixed_properties, anon_channel_allowed_properties,
+              &error))
+        goto error;
 
-  g_signal_handlers_disconnect_by_func (priv->conn,
-       G_CALLBACK (tpsip_nua_i_invite_cb),
-       fac);
+      channel = new_media_channel (self, conn->self_handle, 0);
+      break;
+
+    case TP_HANDLE_TYPE_CONTACT:
+      if (!tp_handle_is_valid (
+            tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT),
+            handle, &error))
+        goto error;
+
+      if (tp_channel_manager_asv_has_unknown_properties (request_properties,
+              media_channel_fixed_properties, named_channel_allowed_properties,
+              &error))
+        goto error;
+
+      if (method == METHOD_ENSURE)
+        {
+          guint i;
+          TpHandle peer = 0;
+
+          for (i = 0; i < priv->channels->len; i++)
+            {
+              channel = g_ptr_array_index (priv->channels, i);
+              g_object_get (channel, "peer", &peer, NULL);
+
+              if (peer == handle)
+                {
+                  tp_channel_manager_emit_request_already_satisfied (self,
+                      request_token, TP_EXPORTABLE_CHANNEL (channel));
+                  return TRUE;
+                }
+            }
+        }
+
+      channel = new_media_channel (self, conn->self_handle, handle);
+
+      if (add_peer_to_remote_pending)
+        {
+          if (!_tpsip_media_channel_add_member ((GObject *) channel, handle,
+                "", &error))
+            {
+              tpsip_media_channel_close (channel);
+              goto error;
+            }
+        }
+
+      break;
+
+    default:
+      return FALSE;
+    }
+
+  g_assert (channel != NULL);
+
+  request_tokens = g_slist_prepend (NULL, request_token);
+  tp_channel_manager_emit_new_channel (self,
+      TP_EXPORTABLE_CHANNEL (channel), request_tokens);
+  g_slist_free (request_tokens);
+
+  return TRUE;
+
+error:
+  tp_channel_manager_emit_request_failed (self, request_token,
+      error->domain, error->code, error->message);
+  g_error_free (error);
+  return TRUE;
+}
+
+static gboolean
+tpsip_media_factory_request_channel (TpChannelManager *manager,
+                                     gpointer request_token,
+                                     GHashTable *request_properties)
+{
+  return tpsip_media_factory_requestotron (manager, request_token,
+      request_properties, METHOD_REQUEST);
+}
+
+static gboolean
+tpsip_media_factory_create_channel (TpChannelManager *manager,
+                                    gpointer request_token,
+                                    GHashTable *request_properties)
+{
+  return tpsip_media_factory_requestotron (manager, request_token,
+      request_properties, METHOD_CREATE);
+}
+
+static gboolean
+tpsip_media_factory_ensure_channel (TpChannelManager *manager,
+                                    gpointer request_token,
+                                    GHashTable *request_properties)
+{
+  return tpsip_media_factory_requestotron (manager, request_token,
+      request_properties, METHOD_ENSURE);
 }
 
 static void
-factory_iface_init (gpointer g_iface, gpointer iface_data)
+channel_manager_iface_init (gpointer g_iface,
+                            gpointer iface_data)
 {
-  TpChannelFactoryIfaceClass *klass = (TpChannelFactoryIfaceClass *) g_iface;
-
-#define IMPLEMENT(x) klass->x = tpsip_media_factory_##x
-  IMPLEMENT(close_all);
-  IMPLEMENT(foreach);
-  IMPLEMENT(request);
-  IMPLEMENT(connected);
-  IMPLEMENT(disconnected);
-#undef IMPLEMENT
+  TpChannelManagerIface *iface = g_iface;
+
+  iface->foreach_channel = tpsip_media_factory_foreach_channel;
+  iface->foreach_channel_class = tpsip_media_factory_foreach_channel_class;
+  iface->request_channel = tpsip_media_factory_request_channel;
+  iface->create_channel = tpsip_media_factory_create_channel;
+  iface->ensure_channel = tpsip_media_factory_ensure_channel;
 }
diff --git a/src/sip-media-channel.c b/src/sip-media-channel.c
index 57012f1..eb57ad5 100644
--- a/src/sip-media-channel.c
+++ b/src/sip-media-channel.c
@@ -31,9 +31,8 @@
 #include <telepathy-glib/channel-iface.h>
 #include <telepathy-glib/dbus.h>
 #include <telepathy-glib/errors.h>
-#include <telepathy-glib/gtypes.h>
+#include <telepathy-glib/exportable-channel.h>
 #include <telepathy-glib/interfaces.h>
-#include <telepathy-glib/intset.h>
 #include <telepathy-glib/svc-channel.h>
 
 #include <tpsip/event-target.h>
@@ -72,6 +71,7 @@ G_DEFINE_TYPE_WITH_CODE (TpsipMediaChannel, tpsip_media_channel,
       hold_iface_init);
     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_STREAMED_MEDIA,
       streamed_media_iface_init);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL);
     G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL));
 
 static const gchar *tpsip_media_channel_interfaces[] = {
@@ -95,8 +95,11 @@ enum
   PROP_TARGET_ID,
   PROP_INITIATOR,
   PROP_INITIATOR_ID,
+  PROP_PEER,
   PROP_REQUESTED,
   PROP_INTERFACES,
+  PROP_CHANNEL_DESTROYED,
+  PROP_CHANNEL_PROPERTIES,
   /* Telepathy properties (see below too) */
   PROP_NAT_TRAVERSAL,
   PROP_STUN_SERVER,
@@ -113,7 +116,7 @@ enum
   NUM_TP_PROPS
 };
 
-const TpPropertySignature media_channel_property_signatures[NUM_TP_PROPS] =
+static const TpPropertySignature media_channel_property_signatures[NUM_TP_PROPS] =
 {
     { "nat-traversal",          G_TYPE_STRING },
     { "stun-server",            G_TYPE_STRING },
@@ -277,6 +280,11 @@ tpsip_media_channel_class_init (TpsipMediaChannelClass *klass)
   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_object ("connection", "TpsipConnection object",
       "SIP connection object that owns this SIP media channel object.",
       TPSIP_TYPE_CONNECTION,
@@ -376,8 +384,30 @@ tpsip_media_channel_get_property (GObject    *object,
           TP_HANDLE_TYPE_CONTACT : TP_HANDLE_TYPE_NONE);
       break;
     case PROP_TARGET_ID:
-      g_value_set_static_string (value, "");
+      if (priv->handle != 0)
+        {
+          TpHandleRepoIface *repo = tp_base_connection_get_handles (
+              base_conn, TP_HANDLE_TYPE_CONTACT);
+
+          g_value_set_string (value, tp_handle_inspect (repo, priv->initiator));
+        }
+      else
+        g_value_set_static_string (value, "");
       break;
+    case PROP_PEER:
+      {
+        TpHandle peer = 0;
+
+        if (priv->handle != 0)
+          peer = priv->handle;
+        else if (priv->session != NULL)
+          g_object_get (priv->session,
+              "peer", &peer,
+              NULL);
+
+        g_value_set_uint (value, peer);
+        break;
+      }
     case PROP_INITIATOR:
       g_value_set_uint (value, priv->initiator);
       break;
@@ -395,6 +425,21 @@ tpsip_media_channel_get_property (GObject    *object,
     case PROP_INTERFACES:
       g_value_set_static_boxed (value, tpsip_media_channel_interfaces);
       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, "ChannelType",
+              TP_IFACE_CHANNEL, "TargetHandleType",
+              TP_IFACE_CHANNEL, "TargetHandle",
+              TP_IFACE_CHANNEL, "TargetID",
+              TP_IFACE_CHANNEL, "InitiatorHandle",
+              TP_IFACE_CHANNEL, "InitiatorID",
+              TP_IFACE_CHANNEL, "Requested",
+              NULL));
+      break;
     default:
       /* Some properties live in the mixin */
       {
@@ -445,6 +490,8 @@ tpsip_media_channel_set_property (GObject     *object,
       priv->object_path = g_value_dup_string (value);
       break;
     case PROP_HANDLE:
+      /* XXX: this property is defined as writable,
+       * but don't set it after construction, mmkay? */
       /* we don't ref it here because we don't necessarily have access to the
        * contact repo yet - instead we ref it in constructed. */
       priv->handle = g_value_get_uint (value);
-- 
1.5.6.5




More information about the Telepathy-commits mailing list