[Telepathy-commits] [telepathy-haze/master] HazeContactList: 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/contact-list-channel.c |    2 +-
 src/contact-list.c         |  257 +++++++++++++++++++++++++++++++++++++++++---
 src/contact-list.h         |    3 +-
 3 files changed, 245 insertions(+), 17 deletions(-)

diff --git a/src/contact-list-channel.c b/src/contact-list-channel.c
index 2ca3706..a671d84 100644
--- a/src/contact-list-channel.c
+++ b/src/contact-list-channel.c
@@ -414,7 +414,7 @@ haze_request_authorize (PurpleAccount *account,
 
     HazeContactListChannel *publish =
         haze_contact_list_get_channel (conn->contact_list,
-            TP_HANDLE_TYPE_LIST, HAZE_LIST_HANDLE_PUBLISH, NULL);
+            TP_HANDLE_TYPE_LIST, HAZE_LIST_HANDLE_PUBLISH, NULL, NULL);
     HazeContactListChannelPrivate *priv =
         HAZE_CONTACT_LIST_CHANNEL_GET_PRIVATE (publish);
 
diff --git a/src/contact-list.c b/src/contact-list.c
index 398869a..f6183c5 100644
--- a/src/contact-list.c
+++ b/src/contact-list.c
@@ -21,8 +21,10 @@
 
 #include <string.h>
 
-#include <telepathy-glib/interfaces.h>
 #include <telepathy-glib/channel-factory-iface.h>
+#include <telepathy-glib/channel-manager.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/interfaces.h>
 #include <telepathy-glib/intset.h>
 
 #include "connection.h"
@@ -35,18 +37,22 @@ struct _HazeContactListPrivate {
 
     GHashTable *list_channels;
     GHashTable *group_channels;
+    gulong status_changed_id;
 
     gboolean dispose_has_run;
 };
 
 static void
 haze_contact_list_factory_iface_init (gpointer g_iface, gpointer iface_data);
+static void channel_manager_iface_init (gpointer, gpointer);
 
 G_DEFINE_TYPE_WITH_CODE(HazeContactList,
     haze_contact_list,
     G_TYPE_OBJECT,
     G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_FACTORY_IFACE,
-      haze_contact_list_factory_iface_init));
+      haze_contact_list_factory_iface_init);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
+      channel_manager_iface_init))
 
 /* properties: */
 enum {
@@ -72,15 +78,32 @@ haze_contact_list_init (HazeContactList *self)
     priv->dispose_has_run = FALSE;
 }
 
+static void haze_contact_list_close_all (HazeContactList *self);
+
+static void
+status_changed_cb (HazeConnection *conn,
+                   guint status,
+                   guint reason,
+                   HazeContactList *self)
+{
+    if (status == TP_CONNECTION_STATUS_DISCONNECTED)
+        haze_contact_list_close_all (self);
+}
+
 static GObject *
 haze_contact_list_constructor (GType type, guint n_props,
                                GObjectConstructParam *props)
 {
     GObject *obj;
+    HazeContactList *self;
 
     obj = G_OBJECT_CLASS (haze_contact_list_parent_class)->
         constructor (type, n_props, props);
 
+    self = HAZE_CONTACT_LIST (obj);
+    self->priv->status_changed_id = g_signal_connect (self->priv->conn,
+        "status-changed", (GCallback) status_changed_cb, self);
+
     return obj;
 }
 
@@ -95,7 +118,7 @@ haze_contact_list_dispose (GObject *object)
 
     priv->dispose_has_run = TRUE;
 
-    tp_channel_factory_iface_close_all (TP_CHANNEL_FACTORY_IFACE (object));
+    haze_contact_list_close_all (self);
     g_assert (priv->list_channels == NULL);
     g_assert (priv->group_channels == NULL);
 
@@ -214,7 +237,8 @@ contact_list_channel_closed_cb (HazeContactListChannel *chan,
 static HazeContactListChannel *
 _haze_contact_list_create_channel (HazeContactList *contact_list,
                                    guint handle_type,
-                                   TpHandle handle)
+                                   TpHandle handle,
+                                   gpointer request_token)
 {
     HazeContactListPrivate *priv = contact_list->priv;
     TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn);
@@ -226,6 +250,7 @@ _haze_contact_list_create_channel (HazeContactList *contact_list,
     const char *name;
     char *mangled_name;
     char *object_path;
+    GSList *requests = NULL;
 
     g_assert (handle_type == TP_HANDLE_TYPE_LIST ||
             handle_type == TP_HANDLE_TYPE_GROUP);
@@ -259,15 +284,92 @@ _haze_contact_list_create_channel (HazeContactList *contact_list,
 
     tp_channel_factory_iface_emit_new_channel (contact_list,
                                                (TpChannelIface *)chan, NULL);
+
+    if (request_token != NULL)
+        requests = g_slist_prepend (requests, request_token);
+
+    tp_channel_manager_emit_new_channel (contact_list,
+        TP_EXPORTABLE_CHANNEL (chan), requests);
+    g_slist_free (requests);
+
     g_free (object_path);
 
     return chan;
 }
 
+struct foreach_data {
+    TpExportableChannelFunc func;
+    gpointer data;
+};
+
+static void
+foreach_helper (gpointer k,
+                gpointer v,
+                gpointer data)
+{
+  struct foreach_data *foreach = data;
+
+  foreach->func (TP_EXPORTABLE_CHANNEL (v), foreach->data);
+}
+
+static void
+haze_contact_list_foreach_channel (TpChannelManager *manager,
+                                   TpExportableChannelFunc func,
+                                   gpointer data)
+{
+    HazeContactList *self = HAZE_CONTACT_LIST (manager);
+    struct foreach_data foreach = { func, data };
+
+    g_hash_table_foreach (self->priv->group_channels, foreach_helper,
+        &foreach);
+    g_hash_table_foreach (self->priv->list_channels, foreach_helper,
+        &foreach);
+}
+
+static const gchar * const list_fixed_properties[] = {
+    TP_IFACE_CHANNEL ".ChannelType",
+    TP_IFACE_CHANNEL ".TargetHandleType",
+    NULL
+};
+static const gchar * const list_allowed_properties[] = {
+    TP_IFACE_CHANNEL ".TargetHandle",
+    TP_IFACE_CHANNEL ".TargetID",
+    NULL
+};
+static const gchar * const *group_fixed_properties = list_fixed_properties;
+static const gchar * const *group_allowed_properties = list_allowed_properties;
+
+static void
+haze_contact_list_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_CONTACT_LIST);
+    g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType", value);
+
+    handle_type_value = tp_g_value_slice_new (G_TYPE_UINT);
+    g_hash_table_insert (table, TP_IFACE_CHANNEL ".TargetHandleType",
+        handle_type_value);
+
+    g_value_set_uint (handle_type_value, TP_HANDLE_TYPE_LIST);
+    func (manager, table, list_allowed_properties, user_data);
+
+    g_value_set_uint (handle_type_value, TP_HANDLE_TYPE_GROUP);
+    func (manager, table, group_allowed_properties, user_data);
+
+    g_hash_table_destroy (table);
+}
+
 HazeContactListChannel *
 haze_contact_list_get_channel (HazeContactList *contact_list,
                                guint handle_type,
                                TpHandle handle,
+                               gpointer request_token,
                                gboolean *created)
 {
     HazeContactListPrivate *priv = contact_list->priv;
@@ -294,7 +396,7 @@ haze_contact_list_get_channel (HazeContactList *contact_list,
     else
     {
         chan = _haze_contact_list_create_channel (contact_list, handle_type,
-            handle);
+            handle, request_token);
         if (created)
             *created = TRUE;
     }
@@ -316,7 +418,7 @@ _haze_contact_list_get_group (HazeContactList *contact_list,
     HazeContactListChannel *group;
 
     group = haze_contact_list_get_channel (contact_list, TP_HANDLE_TYPE_GROUP,
-        group_handle, created);
+        group_handle, NULL, created);
 
     tp_handle_unref (group_repo, group_handle);
 
@@ -324,9 +426,8 @@ _haze_contact_list_get_group (HazeContactList *contact_list,
 }
 
 static void
-haze_contact_list_factory_iface_close_all (TpChannelFactoryIface *iface)
+haze_contact_list_close_all (HazeContactList *self)
 {
-    HazeContactList *self = HAZE_CONTACT_LIST (iface);
     HazeContactListPrivate *priv = self->priv;
     GHashTable *tmp;
 
@@ -342,6 +443,12 @@ haze_contact_list_factory_iface_close_all (TpChannelFactoryIface *iface)
         priv->group_channels = NULL;
         g_hash_table_destroy (tmp);
     }
+
+    if (priv->status_changed_id != 0)
+    {
+        g_signal_handler_disconnect (priv->conn, priv->status_changed_id);
+        priv->status_changed_id = 0;
+    }
 }
 
 static void
@@ -389,7 +496,7 @@ buddy_added_cb (PurpleBuddy *buddy, gpointer unused)
     add_handles = _handle_a_buddy (priv->conn, buddy);
 
     subscribe = haze_contact_list_get_channel (contact_list,
-        TP_HANDLE_TYPE_LIST, HAZE_LIST_HANDLE_SUBSCRIBE, NULL);
+        TP_HANDLE_TYPE_LIST, HAZE_LIST_HANDLE_SUBSCRIBE, NULL, NULL);
 
     tp_group_mixin_change_members (G_OBJECT (subscribe), "",
         tp_handle_set_peek (add_handles), NULL, NULL, NULL, 0, 0);
@@ -440,7 +547,7 @@ buddy_removed_cb (PurpleBuddy *buddy, gpointer unused)
     if (last_instance)
     {
         subscribe = haze_contact_list_get_channel (contact_list,
-            TP_HANDLE_TYPE_LIST, HAZE_LIST_HANDLE_SUBSCRIBE, NULL);
+            TP_HANDLE_TYPE_LIST, HAZE_LIST_HANDLE_SUBSCRIBE, NULL, NULL);
 
         tp_group_mixin_change_members (G_OBJECT (subscribe), "",
             NULL, tp_handle_set_peek (rem_handles), NULL, NULL, 0, 0);
@@ -515,7 +622,7 @@ _create_initial_group(gchar *group_name,
     TpHandle group_handle = tp_handle_ensure (handle_repo, group_name, NULL,
         NULL);
     group = haze_contact_list_get_channel (contact_list,
-        TP_HANDLE_TYPE_GROUP, group_handle, NULL /*created*/);
+        TP_HANDLE_TYPE_GROUP, group_handle, NULL, NULL /*created*/);
 
     tp_group_mixin_change_members (G_OBJECT (group), "", handles, NULL,
                                    NULL, NULL, 0, 0);
@@ -569,11 +676,11 @@ haze_contact_list_factory_iface_connected (TpChannelFactoryIface *iface)
 
     /* Ensure contact lists exist before going any further. */
     subscribe = haze_contact_list_get_channel (self, TP_HANDLE_TYPE_LIST,
-        HAZE_LIST_HANDLE_SUBSCRIBE, NULL /*created*/);
+        HAZE_LIST_HANDLE_SUBSCRIBE, NULL, NULL /*created*/);
     g_assert (subscribe != NULL);
 
     publish = haze_contact_list_get_channel (self, TP_HANDLE_TYPE_LIST,
-            HAZE_LIST_HANDLE_PUBLISH, NULL /*created*/);
+            HAZE_LIST_HANDLE_PUBLISH, NULL, NULL /*created*/);
     g_assert (publish != NULL);
 
     _add_initial_buddies (self, subscribe);
@@ -649,7 +756,7 @@ haze_contact_list_factory_iface_request (TpChannelFactoryIface *iface,
     channel_name = tp_handle_inspect (handle_repo, handle);
     DEBUG ("grabbing channel '%s'...", channel_name);
     chan = haze_contact_list_get_channel (self, handle_type, handle,
-        &created);
+        NULL, &created);
 
     if (chan)
     {
@@ -676,10 +783,130 @@ haze_contact_list_factory_iface_init (gpointer g_iface,
 {
     TpChannelFactoryIfaceClass *klass = (TpChannelFactoryIfaceClass *) g_iface;
 
-    klass->close_all = haze_contact_list_factory_iface_close_all;
+    klass->close_all = (TpChannelFactoryIfaceProc) haze_contact_list_close_all;
     klass->connecting = haze_contact_list_factory_iface_connecting;
     klass->connected = haze_contact_list_factory_iface_connected;
     klass->disconnected = haze_contact_list_factory_iface_disconnected;
     klass->foreach = haze_contact_list_factory_iface_foreach;
     klass->request = haze_contact_list_factory_iface_request;
 }
+
+static gboolean
+haze_contact_list_request (HazeContactList *self,
+                           gpointer request_token,
+                           GHashTable *request_properties,
+                           gboolean require_new)
+{
+    TpHandleRepoIface *handle_repo;
+    TpHandleType handle_type;
+    TpHandle handle;
+    const gchar *channel_name;
+    gboolean created;
+    HazeContactListChannel *chan;
+    GError *error = NULL;
+    const gchar * const *fixed_properties;
+    const gchar * const *allowed_properties;
+
+    if (tp_strdiff (tp_asv_get_string (request_properties,
+            TP_IFACE_CHANNEL ".ChannelType"),
+        TP_IFACE_CHANNEL_TYPE_CONTACT_LIST))
+    {
+        return FALSE;
+    }
+
+    handle_type = tp_asv_get_uint32 (request_properties,
+        TP_IFACE_CHANNEL ".TargetHandleType", NULL);
+
+    switch (handle_type)
+    {
+    case TP_HANDLE_TYPE_LIST:
+        fixed_properties = list_fixed_properties;
+        allowed_properties = list_allowed_properties;
+        break;
+    case TP_HANDLE_TYPE_GROUP:
+        fixed_properties = group_fixed_properties;
+        allowed_properties = group_allowed_properties;
+        break;
+    default:
+        return FALSE;
+    }
+
+    handle_repo = tp_base_connection_get_handles (
+        TP_BASE_CONNECTION (self->priv->conn), handle_type);
+
+    handle = tp_asv_get_uint32 (request_properties,
+        TP_IFACE_CHANNEL ".TargetHandle", NULL);
+    g_assert (tp_handle_is_valid (handle_repo, handle, NULL));
+
+    if (tp_channel_manager_asv_has_unknown_properties (request_properties,
+          fixed_properties, allowed_properties, &error))
+    {
+        goto error;
+    }
+
+    channel_name = tp_handle_inspect (handle_repo, handle);
+    DEBUG ("grabbing channel '%s'...", channel_name);
+
+    chan = haze_contact_list_get_channel (self, handle_type, 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_contact_list_create_channel (TpChannelManager *manager,
+                                  gpointer request_token,
+                                  GHashTable *request_properties)
+{
+    HazeContactList *self = HAZE_CONTACT_LIST (manager);
+
+    return haze_contact_list_request (self, request_token,
+        request_properties, TRUE);
+}
+
+static gboolean
+haze_contact_list_ensure_channel (TpChannelManager *manager,
+                                  gpointer request_token,
+                                  GHashTable *request_properties)
+{
+    HazeContactList *self = HAZE_CONTACT_LIST (manager);
+
+    return haze_contact_list_request (self, 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_contact_list_foreach_channel;
+    iface->foreach_channel_class = haze_contact_list_foreach_channel_class;
+    iface->create_channel = haze_contact_list_create_channel;
+    iface->ensure_channel = haze_contact_list_ensure_channel;
+    /* Request is equivalent to Ensure for this channel class */
+    iface->request_channel = haze_contact_list_ensure_channel;
+}
diff --git a/src/contact-list.h b/src/contact-list.h
index f2b9a48..27fe7c1 100644
--- a/src/contact-list.h
+++ b/src/contact-list.h
@@ -61,6 +61,7 @@ GType haze_contact_list_get_type (void);
 G_END_DECLS
 
 HazeContactListChannel *haze_contact_list_get_channel (HazeContactList *self,
-    guint handle_type, TpHandle handle, gboolean *created);
+    guint handle_type, TpHandle handle, gpointer request_token,
+    gboolean *created);
 
 #endif /* #ifndef __HAZE_CONTACT_LIST_H__*/
-- 
1.5.6.5




More information about the telepathy-commits mailing list