[Telepathy-commits] [telepathy-haze/master] HazeImChannelFactory: be a TpChannelManager as well as a TpChannelFactoryIface

Simon McVittie simon.mcvittie at collabora.co.uk
Mon Mar 23 02:44:10 PDT 2009


---
 src/im-channel-factory.c |  219 ++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 200 insertions(+), 19 deletions(-)

diff --git a/src/im-channel-factory.c b/src/im-channel-factory.c
index e242c5f..0c7418d 100644
--- a/src/im-channel-factory.c
+++ b/src/im-channel-factory.c
@@ -24,10 +24,12 @@
 
 #include <string.h>
 
+#include <telepathy-glib/base-connection.h>
 #include <telepathy-glib/channel-factory-iface.h>
-#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/channel-manager.h>
+#include <telepathy-glib/dbus.h>
 #include <telepathy-glib/handle-repo.h>
-#include <telepathy-glib/base-connection.h>
+#include <telepathy-glib/interfaces.h>
 
 #include "debug.h"
 #include "im-channel.h"
@@ -36,17 +38,21 @@
 struct _HazeImChannelFactoryPrivate {
     HazeConnection *conn;
     GHashTable *channels;
+    gulong status_changed_id;
     gboolean dispose_has_run;
 };
 
 static void haze_im_channel_factory_iface_init (gpointer g_iface,
                                                 gpointer iface_data);
+static void channel_manager_iface_init (gpointer, gpointer);
 
 G_DEFINE_TYPE_WITH_CODE(HazeImChannelFactory,
     haze_im_channel_factory,
     G_TYPE_OBJECT,
     G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_FACTORY_IFACE,
-      haze_im_channel_factory_iface_init));
+      haze_im_channel_factory_iface_init);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
+      channel_manager_iface_init))
 
 /* properties: */
 enum {
@@ -56,7 +62,9 @@ enum {
 };
 
 static HazeIMChannel *get_im_channel (HazeImChannelFactory *self,
-    TpHandle handle, TpHandle initiator, gboolean *created);
+    TpHandle handle, TpHandle initiator, gpointer request_token,
+    gboolean *created);
+static void close_all (HazeImChannelFactory *self);
 
 static void
 conversation_updated_cb (PurpleConversation *conv,
@@ -100,7 +108,7 @@ conversation_updated_cb (PurpleConversation *conv,
     }
 
     chan = get_im_channel (im_factory, ui_data->contact_handle,
-        ui_data->contact_handle, NULL);
+        ui_data->contact_handle, NULL, NULL);
 
     tp_svc_channel_interface_chat_state_emit_chat_state_changed (
         (TpSvcChannelInterfaceChatState*)chan, ui_data->contact_handle, state);
@@ -128,7 +136,7 @@ haze_im_channel_factory_dispose (GObject *object)
 
     self->priv->dispose_has_run = TRUE;
 
-    tp_channel_factory_iface_close_all (TP_CHANNEL_FACTORY_IFACE (object));
+    close_all (self);
     g_assert (self->priv->channels == NULL);
 
     if (G_OBJECT_CLASS (haze_im_channel_factory_parent_class)->dispose)
@@ -172,12 +180,39 @@ haze_im_channel_factory_set_property (GObject *object,
 }
 
 static void
+status_changed_cb (HazeConnection *conn,
+                   guint status,
+                   guint reason,
+                   HazeImChannelFactory *self)
+{
+    if (status == TP_CONNECTION_STATUS_DISCONNECTED)
+        close_all (self);
+}
+
+static void
+haze_im_channel_factory_constructed (GObject *object)
+{
+    HazeImChannelFactory *self = HAZE_IM_CHANNEL_FACTORY (object);
+    void (*constructed) (GObject *) =
+        ((GObjectClass *) haze_im_channel_factory_parent_class)->constructed;
+
+    if (constructed != NULL)
+    {
+        constructed (object);
+    }
+
+    self->priv->status_changed_id = g_signal_connect (self->priv->conn,
+        "status-changed", (GCallback) status_changed_cb, self);
+}
+
+static void
 haze_im_channel_factory_class_init (HazeImChannelFactoryClass *klass)
 {
     GObjectClass *object_class = G_OBJECT_CLASS (klass);
     GParamSpec *param_spec;
     void *conv_handle = purple_conversations_get_handle();
 
+    object_class->constructed = haze_im_channel_factory_constructed;
     object_class->dispose = haze_im_channel_factory_dispose;
     object_class->get_property = haze_im_channel_factory_get_property;
     object_class->set_property = haze_im_channel_factory_set_property;
@@ -219,11 +254,13 @@ im_channel_closed_cb (HazeIMChannel *chan, gpointer user_data)
 static HazeIMChannel *
 new_im_channel (HazeImChannelFactory *self,
                 TpHandle handle,
-                TpHandle initiator)
+                TpHandle initiator,
+                gpointer request_token)
 {
     TpBaseConnection *conn;
     HazeIMChannel *chan;
     char *object_path;
+    GSList *requests = NULL;
 
     g_assert (HAZE_IS_IM_CHANNEL_FACTORY (self));
 
@@ -250,6 +287,13 @@ new_im_channel (HazeImChannelFactory *self,
     tp_channel_factory_iface_emit_new_channel (self, (TpChannelIface *)chan,
             NULL);
 
+    if (request_token != NULL)
+        requests = g_slist_prepend (requests, request_token);
+
+    tp_channel_manager_emit_new_channel (self,
+        TP_EXPORTABLE_CHANNEL (chan), requests);
+    g_slist_free (requests);
+
     g_free (object_path);
 
     return chan;
@@ -259,6 +303,7 @@ static HazeIMChannel *
 get_im_channel (HazeImChannelFactory *self,
                 TpHandle handle,
                 TpHandle initiator,
+                gpointer request_token,
                 gboolean *created)
 {
     HazeIMChannel *chan =
@@ -271,7 +316,7 @@ get_im_channel (HazeImChannelFactory *self,
     }
     else
     {
-        chan = new_im_channel (self, handle, initiator);
+        chan = new_im_channel (self, handle, initiator, request_token);
         if (created)
             *created = TRUE;
     }
@@ -280,9 +325,8 @@ get_im_channel (HazeImChannelFactory *self,
 }
 
 static void
-haze_im_channel_factory_iface_close_all (TpChannelFactoryIface *iface)
+close_all (HazeImChannelFactory *self)
 {
-    HazeImChannelFactory *self = HAZE_IM_CHANNEL_FACTORY (iface);
     GHashTable *tmp;
 
     DEBUG ("closing im channels");
@@ -293,6 +337,13 @@ haze_im_channel_factory_iface_close_all (TpChannelFactoryIface *iface)
         self->priv->channels = NULL;
         g_hash_table_destroy (tmp);
     }
+
+    if (self->priv->status_changed_id != 0)
+    {
+        g_signal_handler_disconnect (self->priv->conn,
+            self->priv->status_changed_id);
+        self->priv->status_changed_id = 0;
+    }
 }
 
 static void
@@ -309,7 +360,7 @@ haze_im_channel_factory_iface_disconnected (TpChannelFactoryIface *iface)
 
 struct _ForeachData
 {
-    TpChannelFunc foreach;
+    TpExportableChannelFunc foreach;
     gpointer user_data;
 };
 
@@ -317,15 +368,15 @@ 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);
 }
 
 static void
-haze_im_channel_factory_iface_foreach (TpChannelFactoryIface *iface,
-                                       TpChannelFunc foreach,
-                                       gpointer user_data)
+haze_im_channel_factory_foreach (TpChannelManager *iface,
+                                 TpExportableChannelFunc foreach,
+                                 gpointer user_data)
 {
     HazeImChannelFactory *self = HAZE_IM_CHANNEL_FACTORY (iface);
     struct _ForeachData data;
@@ -362,7 +413,8 @@ haze_im_channel_factory_iface_request (TpChannelFactoryIface *iface,
     if (!tp_handle_is_valid (contact_repo, handle, error))
         return TP_CHANNEL_FACTORY_REQUEST_STATUS_ERROR;
 
-    chan = get_im_channel (self, handle, base_conn->self_handle, &created);
+    chan = get_im_channel (self, handle, base_conn->self_handle,
+        NULL, &created);
     if (created)
     {
         status = TP_CHANNEL_FACTORY_REQUEST_STATUS_CREATED;
@@ -382,11 +434,12 @@ haze_im_channel_factory_iface_init (gpointer g_iface,
 {
     TpChannelFactoryIfaceClass *klass = (TpChannelFactoryIfaceClass *) g_iface;
 
-    klass->close_all = haze_im_channel_factory_iface_close_all;
+    klass->close_all = (TpChannelFactoryIfaceProc) close_all;
     klass->connecting = haze_im_channel_factory_iface_connecting;
     klass->connected = NULL; //haze_im_channel_factory_iface_connected;
     klass->disconnected = haze_im_channel_factory_iface_disconnected;
-    klass->foreach = haze_im_channel_factory_iface_foreach;
+    klass->foreach = (TpChannelFactoryIfaceForeachImpl)
+        haze_im_channel_factory_foreach;
     klass->request = haze_im_channel_factory_iface_request;
 }
 
@@ -420,7 +473,7 @@ haze_write_im (PurpleConversation *conv,
         type = TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION;
 
     chan = get_im_channel (im_factory, ui_data->contact_handle,
-        ui_data->contact_handle, NULL);
+        ui_data->contact_handle, NULL, NULL);
 
     if (flags & PURPLE_MESSAGE_RECV)
         tp_text_mixin_receive (G_OBJECT (chan), type, ui_data->contact_handle,
@@ -558,3 +611,131 @@ haze_get_conv_ui_ops(void)
 {
     return &conversation_ui_ops;
 }
+
+static const gchar * const fixed_properties[] = {
+    TP_IFACE_CHANNEL ".ChannelType",
+    TP_IFACE_CHANNEL ".TargetHandleType",
+    NULL
+};
+static const gchar * const allowed_properties[] = {
+    TP_IFACE_CHANNEL ".TargetHandle",
+    TP_IFACE_CHANNEL ".TargetID",
+    NULL
+};
+
+static void
+haze_im_channel_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;
+
+    value = tp_g_value_slice_new (G_TYPE_STRING);
+    g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST);
+    g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType", value);
+
+    value = tp_g_value_slice_new (G_TYPE_UINT);
+    g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT);
+    g_hash_table_insert (table, TP_IFACE_CHANNEL ".TargetHandleType", value);
+
+    func (manager, table, allowed_properties, user_data);
+
+    g_hash_table_destroy (table);
+}
+
+static gboolean
+haze_im_channel_factory_request (HazeImChannelFactory *self,
+                                 gpointer request_token,
+                                 GHashTable *request_properties,
+                                 gboolean require_new)
+{
+    TpBaseConnection *base_conn = TP_BASE_CONNECTION (self->priv->conn);
+    TpHandle handle;
+    gboolean created;
+    HazeIMChannel *chan;
+    GError *error = NULL;
+
+    if (tp_strdiff (tp_asv_get_string (request_properties,
+            TP_IFACE_CHANNEL ".ChannelType"),
+        TP_IFACE_CHANNEL_TYPE_TEXT))
+    {
+        return FALSE;
+    }
+
+    if (tp_asv_get_uint32 (request_properties,
+        TP_IFACE_CHANNEL ".TargetHandleType", NULL) != TP_HANDLE_TYPE_CONTACT)
+    {
+        return FALSE;
+    }
+
+    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,
+          fixed_properties, allowed_properties, &error))
+    {
+        goto error;
+    }
+
+    chan = get_im_channel (self, handle, base_conn->self_handle,
+        request_token, &created);
+    g_assert (chan != NULL);
+
+    if (!created)
+    {
+        if (require_new)
+        {
+            tp_channel_manager_emit_request_failed (self, request_token,
+                TP_ERRORS, TP_ERROR_NOT_AVAILABLE, "Channel already exists");
+        }
+        else
+        {
+            tp_channel_manager_emit_request_already_satisfied (self,
+                request_token, TP_EXPORTABLE_CHANNEL (chan));
+        }
+    }
+
+    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
+haze_im_channel_factory_create_channel (TpChannelManager *manager,
+                                        gpointer request_token,
+                                        GHashTable *request_properties)
+{
+    return haze_im_channel_factory_request (HAZE_IM_CHANNEL_FACTORY (manager),
+        request_token, request_properties, TRUE);
+}
+
+static gboolean
+haze_im_channel_factory_ensure_channel (TpChannelManager *manager,
+                                        gpointer request_token,
+                                        GHashTable *request_properties)
+{
+    return haze_im_channel_factory_request (HAZE_IM_CHANNEL_FACTORY (manager),
+        request_token, request_properties, FALSE);
+}
+
+static void
+channel_manager_iface_init (gpointer g_iface,
+                            gpointer iface_data G_GNUC_UNUSED)
+{
+    TpChannelManagerIface *iface = g_iface;
+
+    iface->foreach_channel = haze_im_channel_factory_foreach;
+    iface->foreach_channel_class =
+        haze_im_channel_factory_foreach_channel_class;
+    iface->create_channel = haze_im_channel_factory_create_channel;
+    iface->ensure_channel = haze_im_channel_factory_ensure_channel;
+    /* Request is equivalent to Ensure for this channel class */
+    iface->request_channel = haze_im_channel_factory_ensure_channel;
+}
-- 
1.5.6.5




More information about the telepathy-commits mailing list