[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