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

Mikhail Zabaluev mikhail.zabaluev at nokia.com
Fri Nov 7 07:36:31 PST 2008


Implemented ExportableChannel on text channel.
---
 src/sip-text-channel.c |   27 +++-
 src/text-factory.c     |  307 +++++++++++++++++++++++++++++++++++-------------
 src/text-factory.h     |    4 +-
 3 files changed, 245 insertions(+), 93 deletions(-)

diff --git a/src/sip-text-channel.c b/src/sip-text-channel.c
index 734b5cc..9099aa7 100644
--- a/src/sip-text-channel.c
+++ b/src/sip-text-channel.c
@@ -64,6 +64,7 @@ G_DEFINE_TYPE_WITH_CODE (TpsipTextChannel, tpsip_text_channel, G_TYPE_OBJECT,
       tp_dbus_properties_mixin_iface_init);
     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init);
     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT, text_iface_init);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL);
     G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL));
 
 static const char *tpsip_text_channel_interfaces[] = {
@@ -85,6 +86,7 @@ enum
   PROP_REQUESTED,
   PROP_INTERFACES,
   PROP_CHANNEL_DESTROYED,
+  PROP_CHANNEL_PROPERTIES,
   LAST_PROPERTY
 };
 
@@ -259,6 +261,11 @@ tpsip_text_channel_class_init(TpsipTextChannelClass *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,
@@ -296,13 +303,6 @@ tpsip_text_channel_class_init(TpsipTextChannelClass *klass)
       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
   g_object_class_install_property (object_class, PROP_REQUESTED, param_spec);
 
-  param_spec = g_param_spec_boolean ("channel-destroyed", "Destroyed?",
-      "If true, the channel has *really* closed, rather than just "
-      "appearing to do so",
-      FALSE,
-      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-  g_object_class_install_property (object_class, PROP_CHANNEL_DESTROYED, param_spec);
-
   klass->dbus_props_class.interfaces =
       prop_interfaces;
   tp_dbus_properties_mixin_class_init (object_class,
@@ -373,6 +373,19 @@ tpsip_text_channel_get_property(GObject *object,
       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;
+
     case PROP_INTERFACES:
       g_value_set_static_boxed (value, tpsip_text_channel_interfaces);
       break;
diff --git a/src/text-factory.c b/src/text-factory.c
index 2ff0cb4..afdd312 100644
--- a/src/text-factory.c
+++ b/src/text-factory.c
@@ -1,6 +1,6 @@
 /* 
  * text-factory.c - Text 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,9 +22,11 @@
 
 #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-text-channel.h"
 #include "sip-connection.h"
 #include "sip-connection-helpers.h"
 
@@ -36,12 +38,15 @@
 #include "debug.h"
 
 
-static void factory_iface_init (gpointer, gpointer);
+static void channel_manager_iface_init (gpointer g_iface, gpointer iface_data);
+static void connection_status_changed_cb (TpsipConnection *conn,
+    guint status, guint reason, TpsipTextFactory *self);
+static void tpsip_text_factory_close_all (TpsipTextFactory *self);
 
 G_DEFINE_TYPE_WITH_CODE (TpsipTextFactory, tpsip_text_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
 {
@@ -56,6 +61,9 @@ struct _TpsipTextFactoryPrivate
   /* guint handle => TpsipTextChannel *channel */
   GHashTable *channels;
 
+  gulong status_changed_id;
+  gulong message_received_id;
+
   gboolean dispose_has_run;
 };
 
@@ -74,6 +82,21 @@ tpsip_text_factory_init (TpsipTextFactory *fac)
 }
 
 static void
+tpsip_text_factory_constructed (GObject *object)
+{
+  TpsipTextFactory *fac = TPSIP_TEXT_FACTORY (object);
+  TpsipTextFactoryPrivate *priv = TPSIP_TEXT_FACTORY_GET_PRIVATE (fac);
+  GObjectClass *parent_object_class =
+      G_OBJECT_CLASS (tpsip_text_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_text_factory_dispose (GObject *object)
 {
   TpsipTextFactory *fac = TPSIP_TEXT_FACTORY (object);
@@ -84,8 +107,7 @@ tpsip_text_factory_dispose (GObject *object)
 
   priv->dispose_has_run = TRUE;
 
-  tp_channel_factory_iface_close_all (TP_CHANNEL_FACTORY_IFACE (object));
-
+  tpsip_text_factory_close_all (fac);
   g_assert (priv->channels == NULL);
 
   if (G_OBJECT_CLASS (tpsip_text_factory_parent_class)->dispose)
@@ -138,6 +160,7 @@ tpsip_text_factory_class_init (TpsipTextFactoryClass *klass)
 
   g_type_class_add_private (klass, sizeof (TpsipTextFactoryPrivate));
 
+  object_class->constructed = tpsip_text_factory_constructed;
   object_class->get_property = tpsip_text_factory_get_property;
   object_class->set_property = tpsip_text_factory_set_property;
   object_class->dispose = tpsip_text_factory_dispose;
@@ -150,12 +173,18 @@ tpsip_text_factory_class_init (TpsipTextFactoryClass *klass)
 }
 
 static void
-tpsip_text_factory_close_all (TpChannelFactoryIface *iface)
+tpsip_text_factory_close_all (TpsipTextFactory *fac)
 {
-  TpsipTextFactory *fac = TPSIP_TEXT_FACTORY (iface);
   TpsipTextFactoryPrivate *priv = TPSIP_TEXT_FACTORY_GET_PRIVATE (fac);
   GHashTable *channels;
 
+  if (priv->status_changed_id != 0)
+    {
+      g_signal_handler_disconnect (priv->conn,
+          priv->status_changed_id);
+      priv->status_changed_id = 0;
+    }
+
   if (!priv->channels)
     return;
 
@@ -167,7 +196,7 @@ tpsip_text_factory_close_all (TpChannelFactoryIface *iface)
 
 struct _ForeachData
 {
-  TpChannelFunc foreach;
+  TpExportableChannelFunc func;
   gpointer user_data;
 };
 
@@ -175,19 +204,22 @@ static void
 _foreach_slave (gpointer key, gpointer value, gpointer user_data)
 {
   struct _ForeachData *data = (struct _ForeachData *)user_data;
-  TpChannelIface *chan = TP_CHANNEL_IFACE (value);
+  TpExportableChannel *chan = TP_EXPORTABLE_CHANNEL (value);
 
-  data->foreach (chan, data->user_data);
+  data->func (chan, data->user_data);
 }
 
 static void
-tpsip_text_factory_foreach (TpChannelFactoryIface *iface,
-                          TpChannelFunc foreach,
-                          gpointer user_data)
+tpsip_text_factory_foreach_channel (TpChannelManager *manager,
+                                    TpExportableChannelFunc func,
+                                    gpointer user_data)
 {
-  struct _ForeachData data = { foreach, user_data };
-  TpsipTextFactory *fac = TPSIP_TEXT_FACTORY (iface);
+  TpsipTextFactory *fac = TPSIP_TEXT_FACTORY (manager);
   TpsipTextFactoryPrivate *priv = TPSIP_TEXT_FACTORY_GET_PRIVATE (fac);
+  struct _ForeachData data;
+
+  data.func = func;
+  data.user_data = user_data;
 
   g_hash_table_foreach (priv->channels, _foreach_slave, &data);
 }
@@ -201,11 +233,14 @@ tpsip_text_factory_foreach (TpChannelFactoryIface *iface,
 static void
 channel_closed (TpsipTextChannel *chan, gpointer user_data)
 {
-  TpsipTextFactory *fac = TPSIP_TEXT_FACTORY (user_data);
-  TpsipTextFactoryPrivate *priv = TPSIP_TEXT_FACTORY_GET_PRIVATE (fac);
+  TpsipTextFactory *self = TPSIP_TEXT_FACTORY (user_data);
+  TpsipTextFactoryPrivate *priv = TPSIP_TEXT_FACTORY_GET_PRIVATE (self);
   TpHandle contact_handle;
   gboolean really_destroyed = TRUE;
 
+  tp_channel_manager_emit_channel_closed_for_object (self,
+      (TpExportableChannel *) chan);
+
   if (priv->channels == NULL)
     return;
 
@@ -223,8 +258,8 @@ channel_closed (TpsipTextChannel *chan, gpointer user_data)
     {
       DEBUG ("reopening channel with handle %u due to pending messages",
              contact_handle);
-      tp_channel_factory_iface_emit_new_channel (
-          (TpChannelFactoryIface *) fac, (TpChannelIface *)chan, NULL);
+      tp_channel_manager_emit_new_channel (self,
+          (TpExportableChannel *) chan, NULL);
     }
 }
 
@@ -237,12 +272,13 @@ static TpsipTextChannel *
 tpsip_text_factory_new_channel (TpsipTextFactory *fac,
                                 TpHandle handle,
                                 TpHandle initiator,
-                                gpointer request)
+                                gpointer request_token)
 {
   TpsipTextFactoryPrivate *priv;
   TpsipTextChannel *chan;
   gchar *object_path;
   TpBaseConnection *conn;
+  GSList *request_tokens;
 
   priv = TPSIP_TEXT_FACTORY_GET_PRIVATE (fac);
   conn = (TpBaseConnection *)(priv->conn);
@@ -265,59 +301,159 @@ tpsip_text_factory_new_channel (TpsipTextFactory *fac,
 
   g_hash_table_insert (priv->channels, GUINT_TO_POINTER (handle), chan);
 
-  tp_channel_factory_iface_emit_new_channel (fac, (TpChannelIface *)chan,
-      request);
+  if (request_token != NULL)
+    request_tokens = g_slist_prepend (NULL, request_token);
+  else
+    request_tokens = NULL;
+
+  tp_channel_manager_emit_new_channel (fac,
+      (TpExportableChannel *) chan, request_tokens);
+
+  g_slist_free (request_tokens);
 
   return chan;
 }
 
-static inline TpsipTextChannel *
-tpsip_text_factory_lookup_channel (TpsipTextFactory *fac,
-                                   TpHandle handle)
+
+static const gchar * const text_channel_fixed_properties[] = {
+    TP_IFACE_CHANNEL ".ChannelType",
+    TP_IFACE_CHANNEL ".TargetHandleType",
+    NULL
+};
+
+static const gchar * const text_channel_allowed_properties[] = {
+    TP_IFACE_CHANNEL ".TargetHandle",
+    TP_IFACE_CHANNEL ".TargetID",
+    NULL
+};
+
+static void
+tpsip_text_factory_foreach_channel_class (TpChannelManager *manager,
+    TpChannelManagerChannelClassFunc func,
+    gpointer user_data)
 {
-  TpsipTextFactoryPrivate *priv = TPSIP_TEXT_FACTORY_GET_PRIVATE (fac);
+  GHashTable *table = g_hash_table_new_full (g_str_hash, g_str_equal,
+      NULL, (GDestroyNotify) tp_g_value_slice_free);
+  GValue *value;
 
-  return (TpsipTextChannel *)g_hash_table_lookup (priv->channels,
-      GUINT_TO_POINTER(handle));
+  value = tp_g_value_slice_new (G_TYPE_STRING);
+  g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TEXT);
+  g_hash_table_insert (table, (gchar *) text_channel_fixed_properties[0],
+      value);
+
+  value = tp_g_value_slice_new (G_TYPE_UINT);
+  g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT);
+  g_hash_table_insert (table, (gchar *) text_channel_fixed_properties[1],
+      value);
+
+  func (manager, table, text_channel_allowed_properties, user_data);
+
+  g_hash_table_destroy (table);
 }
 
-static TpChannelFactoryRequestStatus
-tpsip_text_factory_request (TpChannelFactoryIface *iface,
-                            const gchar *chan_type,
-                            TpHandleType handle_type,
-                            guint handle,
-                            gpointer request,
-                            TpChannelIface **ret,
-                            GError **error)
+
+static gboolean
+tpsip_text_factory_requestotron (TpsipTextFactory *self,
+                                 gpointer request_token,
+                                 GHashTable *request_properties,
+                                 gboolean require_new)
 {
-  TpsipTextFactory *fac = TPSIP_TEXT_FACTORY (iface);
-  TpsipTextFactoryPrivate *priv = TPSIP_TEXT_FACTORY_GET_PRIVATE (fac);
-  TpChannelIface *chan;
-  TpChannelFactoryRequestStatus status;
+  TpsipTextFactoryPrivate *priv = TPSIP_TEXT_FACTORY_GET_PRIVATE (self);
+  TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn;
+  TpHandle handle;
+  GError *error = NULL;
+  TpExportableChannel *channel;
+
+  if (tp_strdiff (tp_asv_get_string (request_properties,
+          TP_IFACE_CHANNEL ".ChannelType"), TP_IFACE_CHANNEL_TYPE_TEXT))
+    return FALSE;
 
-  if (strcmp (chan_type, TP_IFACE_CHANNEL_TYPE_TEXT))
+  if (tp_asv_get_uint32 (request_properties,
+        TP_IFACE_CHANNEL ".TargetHandleType", NULL) != TP_HANDLE_TYPE_CONTACT)
+    return FALSE;
+
+  /* validity already checked by TpBaseConnection */
+  handle = tp_asv_get_uint32 (request_properties,
+      TP_IFACE_CHANNEL ".TargetHandle", NULL);
+  g_assert (handle != 0);
+
+  if (tp_channel_manager_asv_has_unknown_properties (request_properties,
+          text_channel_fixed_properties, text_channel_allowed_properties,
+          &error))
+    goto error;
+
+  channel = g_hash_table_lookup (priv->channels,
+      GUINT_TO_POINTER (handle));
+
+  if (channel == NULL)
     {
-      return TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_IMPLEMENTED;
+      tpsip_text_factory_new_channel (self,
+          handle, base_conn->self_handle, request_token);
+      return TRUE;
     }
 
-  if (handle_type != TP_HANDLE_TYPE_CONTACT)
+  if (require_new)
     {
-      return TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_AVAILABLE;
+      g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+          "Already chatting with contact #%u in another channel", handle);
+      goto error;
     }
 
-  status = TP_CHANNEL_FACTORY_REQUEST_STATUS_EXISTING;
-  chan = g_hash_table_lookup (priv->channels, GINT_TO_POINTER (handle));
-  if (!chan)
-    {
-      TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn; 
+  tp_channel_manager_emit_request_already_satisfied (self, request_token,
+      channel);
+  return TRUE;
+
+error:
+  tp_channel_manager_emit_request_failed (self, request_token,
+      error->domain, error->code, error->message);
+  g_error_free (error);
+  return TRUE;
+}
 
-      chan = (TpChannelIface *)tpsip_text_factory_new_channel (fac,
-          handle, base_conn->self_handle, request);
 
-      status = TP_CHANNEL_FACTORY_REQUEST_STATUS_CREATED;
-    }
-  *ret = chan;
-  return status;
+static gboolean
+tpsip_text_factory_create_channel (TpChannelManager *manager,
+                                   gpointer request_token,
+                                   GHashTable *request_properties)
+{
+  TpsipTextFactory *self = TPSIP_TEXT_FACTORY (manager);
+
+  return tpsip_text_factory_requestotron (self, request_token,
+      request_properties, TRUE);
+}
+
+
+static gboolean
+tpsip_text_factory_request_channel (TpChannelManager *manager,
+                                    gpointer request_token,
+                                    GHashTable *request_properties)
+{
+  TpsipTextFactory *self = TPSIP_TEXT_FACTORY (manager);
+
+  return tpsip_text_factory_requestotron (self, request_token,
+      request_properties, FALSE);
+}
+
+
+static gboolean
+tpsip_text_factory_ensure_channel (TpChannelManager *manager,
+                                   gpointer request_token,
+                                   GHashTable *request_properties)
+{
+  TpsipTextFactory *self = TPSIP_TEXT_FACTORY (manager);
+
+  return tpsip_text_factory_requestotron (self, request_token,
+      request_properties, FALSE);
+}
+
+static inline TpsipTextChannel *
+tpsip_text_factory_lookup_channel (TpsipTextFactory *fac,
+                                   TpHandle handle)
+{
+  TpsipTextFactoryPrivate *priv = TPSIP_TEXT_FACTORY_GET_PRIVATE (fac);
+
+  return (TpsipTextChannel *)g_hash_table_lookup (priv->channels,
+      GUINT_TO_POINTER(handle));
 }
 
 static gboolean
@@ -462,38 +598,43 @@ end:
 }
 
 static void
-tpsip_text_factory_connected (TpChannelFactoryIface *iface)
+connection_status_changed_cb (TpsipConnection *conn,
+                              guint status,
+                              guint reason,
+                              TpsipTextFactory *self)
 {
-  TpsipTextFactory *fac = TPSIP_TEXT_FACTORY (iface);
-  TpsipTextFactoryPrivate *priv = TPSIP_TEXT_FACTORY_GET_PRIVATE (fac);
+  TpsipTextFactoryPrivate *priv = TPSIP_TEXT_FACTORY_GET_PRIVATE (self);
 
-  g_signal_connect (priv->conn,
-       "nua-event::nua_i_message",
-       G_CALLBACK (tpsip_nua_i_message_cb),
-       fac);
-}
+  switch (status)
+    {
+    case TP_CONNECTION_STATUS_CONNECTING:
 
-static void
-tpsip_text_factory_disconnected (TpChannelFactoryIface *iface)
-{
-  TpsipTextFactory *fac = TPSIP_TEXT_FACTORY (iface);
-  TpsipTextFactoryPrivate *priv = TPSIP_TEXT_FACTORY_GET_PRIVATE (fac);
+      priv->message_received_id = g_signal_connect (priv->conn,
+          "nua-event::nua_i_message",
+          G_CALLBACK (tpsip_nua_i_message_cb),
+          self);
+
+      break;
+    case TP_CONNECTION_STATUS_DISCONNECTED:
+      tpsip_text_factory_close_all (self);
+
+      g_signal_handler_disconnect (conn, priv->message_received_id);
+      priv->message_received_id = 0;
 
-  g_signal_handlers_disconnect_by_func (priv->conn,
-       G_CALLBACK (tpsip_nua_i_message_cb),
-       fac);
+      break;
+    default:
+      break;
+    }
 }
 
 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_text_factory_##x
-  IMPLEMENT(close_all);
-  IMPLEMENT(foreach);
-  IMPLEMENT(request);
-  IMPLEMENT(connected);
-  IMPLEMENT(disconnected);
-#undef IMPLEMENT
+  TpChannelManagerIface *iface = g_iface;
+
+  iface->foreach_channel = tpsip_text_factory_foreach_channel;
+  iface->foreach_channel_class = tpsip_text_factory_foreach_channel_class;
+  iface->create_channel = tpsip_text_factory_create_channel;
+  iface->request_channel = tpsip_text_factory_request_channel;
+  iface->ensure_channel = tpsip_text_factory_ensure_channel;
 }
diff --git a/src/text-factory.h b/src/text-factory.h
index ea0c013..8a998d7 100644
--- a/src/text-factory.h
+++ b/src/text-factory.h
@@ -21,9 +21,7 @@
 #ifndef __TPSIP_TEXT_FACTORY_H__
 #define __TPSIP_TEXT_FACTORY_H__
 
-#include <telepathy-glib/channel-factory-iface.h>
-
-#include "sip-text-channel.h"
+#include <glib-object.h>
 
 G_BEGIN_DECLS
 
-- 
1.5.6.5




More information about the Telepathy-commits mailing list