[telepathy-idle/master] Initial transition from IdleIMFactory to IdleIMManager

Jonathon Jongsma jjongsma at gnome.org
Thu Sep 10 16:07:38 PDT 2009


using new TpChannelManager interface instead of old TpChannelFactory interface
---
 src/Makefile.am                              |    8 +-
 src/idle-connection.c                        |   27 +-
 src/idle-im-factory.c                        |  260 --------------
 src/idle-im-manager.c                        |  489 ++++++++++++++++++++++++++
 src/{idle-im-factory.h => idle-im-manager.h} |   28 +-
 5 files changed, 521 insertions(+), 291 deletions(-)
 delete mode 100644 src/idle-im-factory.c
 create mode 100644 src/idle-im-manager.c
 rename src/{idle-im-factory.h => idle-im-manager.h} (51%)

diff --git a/src/Makefile.am b/src/Makefile.am
index 6b979f8..0795300 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,12 +22,12 @@ libidle_convenience_la_SOURCES = \
 	idle-handles.h \
 	idle-im-channel.c \
 	idle-im-channel.h \
-	idle-im-factory.c \
-	idle-im-factory.h \
+	idle-im-manager.c \
+	idle-im-manager.h \
 	idle-muc-channel.c \
 	idle-muc-channel.h \
-	idle-muc-factory.c \
-	idle-muc-factory.h \
+	idle-muc-manager.c \
+	idle-muc-manager.h \
 	idle-parser.c \
 	idle-parser.h \
 	idle-server-connection.c \
diff --git a/src/idle-connection.c b/src/idle-connection.c
index 6c2d645..1664c91 100644
--- a/src/idle-connection.c
+++ b/src/idle-connection.c
@@ -34,14 +34,14 @@
 #include <telepathy-glib/errors.h>
 #include <telepathy-glib/interfaces.h>
 #include <telepathy-glib/svc-connection.h>
-#include <telepathy-glib/channel-factory-iface.h>
+#include <telepathy-glib/channel-manager.h>
 
 #define IDLE_DEBUG_FLAG IDLE_DEBUG_CONNECTION
 #include "idle-ctcp.h"
 #include "idle-debug.h"
 #include "idle-handles.h"
-#include "idle-im-factory.h"
-#include "idle-muc-factory.h"
+#include "idle-im-manager.h"
+#include "idle-muc-manager.h"
 #include "idle-parser.h"
 #include "idle-server-connection.h"
 #include "idle-server-connection-iface.h"
@@ -164,7 +164,7 @@ struct _IdleConnectionPrivate {
 #define IDLE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), IDLE_TYPE_CONNECTION, IdleConnectionPrivate))
 
 static void _iface_create_handle_repos(TpBaseConnection *self, TpHandleRepoIface **repos);
-static GPtrArray *_iface_create_channel_factories(TpBaseConnection *self);
+static GPtrArray *_iface_create_channel_managers(TpBaseConnection *self);
 static gchar *_iface_get_unique_connection_name(TpBaseConnection *self);
 static void _iface_disconnected(TpBaseConnection *self);
 static void _iface_shut_down(TpBaseConnection *self);
@@ -359,7 +359,8 @@ static void idle_connection_class_init(IdleConnectionClass *klass) {
 
 	parent_class->create_handle_repos = _iface_create_handle_repos;
 	parent_class->get_unique_connection_name = _iface_get_unique_connection_name;
-	parent_class->create_channel_factories = _iface_create_channel_factories;
+	parent_class->create_channel_factories = NULL;
+	parent_class->create_channel_managers = _iface_create_channel_managers;
 	parent_class->connecting = NULL;
 	parent_class->connected = NULL;
 	parent_class->disconnected = _iface_disconnected;
@@ -392,17 +393,17 @@ static void idle_connection_class_init(IdleConnectionClass *klass) {
 	g_object_class_install_property(object_class, PROP_USE_SSL, param_spec);
 }
 
-static GPtrArray *_iface_create_channel_factories(TpBaseConnection *self) {
-	GPtrArray *factories = g_ptr_array_sized_new(1);
-	GObject *factory;
+static GPtrArray *_iface_create_channel_managers(TpBaseConnection *self) {
+	GPtrArray *managers = g_ptr_array_sized_new(1);
+	GObject *manager;
 
-	factory = g_object_new(IDLE_TYPE_IM_FACTORY, "connection", self, NULL);
-	g_ptr_array_add(factories, factory);
+	manager = g_object_new(IDLE_TYPE_IM_MANAGER, "connection", self, NULL);
+	g_ptr_array_add(managers, manager);
 
-	factory = g_object_new(IDLE_TYPE_MUC_FACTORY, "connection", self, NULL);
-	g_ptr_array_add(factories, factory);
+	manager = g_object_new(IDLE_TYPE_MUC_MANAGER, "connection", self, NULL);
+	g_ptr_array_add(managers, manager);
 
-	return factories;
+	return managers;
 }
 
 static void _iface_create_handle_repos(TpBaseConnection *self, TpHandleRepoIface **repos) {
diff --git a/src/idle-im-factory.c b/src/idle-im-factory.c
deleted file mode 100644
index 972c8e3..0000000
--- a/src/idle-im-factory.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * This file is part of telepathy-idle
- *
- * Copyright (C) 2006-2007 Collabora Limited
- * Copyright (C) 2006-2007 Nokia Corporation
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include "idle-im-factory.h"
-
-#include <telepathy-glib/channel-factory-iface.h>
-#include <telepathy-glib/interfaces.h>
-
-#define IDLE_DEBUG_FLAG IDLE_DEBUG_IM
-#include "idle-connection.h"
-#include "idle-ctcp.h"
-#include "idle-debug.h"
-#include "idle-im-channel.h"
-#include "idle-parser.h"
-#include "idle-text.h"
-
-static void _factory_iface_init(gpointer g_iface, gpointer iface_data);
-
-G_DEFINE_TYPE_WITH_CODE(IdleIMFactory, idle_im_factory, G_TYPE_OBJECT,
-		G_IMPLEMENT_INTERFACE(TP_TYPE_CHANNEL_FACTORY_IFACE, _factory_iface_init));
-
-/* properties */
-enum {
-	PROP_CONNECTION = 1,
-	LAST_PROPERTY_ENUM
-};
-
-typedef struct _IdleIMFactoryPrivate IdleIMFactoryPrivate;
-struct _IdleIMFactoryPrivate {
-	IdleConnection *conn;
-	GHashTable *channels;
-
-	gboolean dispose_has_run;
-};
-
-#define IDLE_IM_FACTORY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), IDLE_TYPE_IM_FACTORY, IdleIMFactoryPrivate))
-
-static IdleParserHandlerResult _notice_privmsg_handler(IdleParser *parser, IdleParserMessageCode code, GValueArray *args, gpointer user_data);
-
-static void _iface_close_all(TpChannelFactoryIface *iface);
-static void _iface_connecting(TpChannelFactoryIface *iface);
-static void _iface_disconnected(TpChannelFactoryIface *iface);
-static void _iface_foreach(TpChannelFactoryIface *iface, TpChannelFunc func, gpointer user_data);
-static TpChannelFactoryRequestStatus _iface_request(TpChannelFactoryIface *iface, const gchar *chan_type, TpHandleType handle_type, guint handle, gpointer request, TpChannelIface **new_chan, GError **error);
-
-static IdleIMChannel *_create_channel(IdleIMFactory *factory, TpHandle handle, gpointer context);
-static void _channel_closed_cb(IdleIMChannel *chan, gpointer user_data);
-
-static void idle_im_factory_init(IdleIMFactory *obj) {
-	IdleIMFactoryPrivate *priv = IDLE_IM_FACTORY_GET_PRIVATE(obj);
-
-	priv->channels = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
-}
-
-static void idle_im_factory_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {
-	IdleIMFactory *fac = IDLE_IM_FACTORY(object);
-	IdleIMFactoryPrivate *priv = IDLE_IM_FACTORY_GET_PRIVATE(fac);
-
-	switch (property_id) {
-		case PROP_CONNECTION:
-			g_value_set_object(value, priv->conn);
-			break;
-
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
-			break;
-	}
-}
-
-static void idle_im_factory_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {
-	IdleIMFactory *fac = IDLE_IM_FACTORY(object);
-	IdleIMFactoryPrivate *priv = IDLE_IM_FACTORY_GET_PRIVATE(fac);
-
-	switch (property_id) {
-		case PROP_CONNECTION:
-			priv->conn = g_value_get_object(value);
-			break;
-
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
-			break;
-	}
-}
-
-static void idle_im_factory_class_init(IdleIMFactoryClass *klass) {
-	GObjectClass *object_class = G_OBJECT_CLASS(klass);
-	GParamSpec *param_spec;
-
-	g_type_class_add_private(klass, sizeof(IdleIMFactoryPrivate));
-
-	object_class->get_property = idle_im_factory_get_property;
-	object_class->set_property = idle_im_factory_set_property;
-
-	param_spec = g_param_spec_object("connection", "IdleConnection object", "The IdleConnection object that owns this IM channel factory object.", IDLE_TYPE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
-	g_object_class_install_property(object_class, PROP_CONNECTION, param_spec);
-}
-
-static IdleParserHandlerResult _notice_privmsg_handler(IdleParser *parser, IdleParserMessageCode code, GValueArray *args, gpointer user_data) {
-	IdleIMFactory *factory = IDLE_IM_FACTORY(user_data);
-	IdleIMFactoryPrivate *priv = IDLE_IM_FACTORY_GET_PRIVATE(factory);
-	TpHandle handle = (TpHandle) g_value_get_uint(g_value_array_get_nth(args, 0));
-	IdleIMChannel *chan;
-	TpChannelTextMessageType type;
-	gchar *body;
-
-	if (code == IDLE_PARSER_PREFIXCMD_NOTICE_USER) {
-		type = TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE;
-		body = idle_ctcp_kill_blingbling(g_value_get_string(g_value_array_get_nth(args, 2)));
-	} else {
-		gboolean decoded = idle_text_decode(g_value_get_string(g_value_array_get_nth(args, 2)), &type, &body);
-		if (!decoded)
-			return IDLE_PARSER_HANDLER_RESULT_NOT_HANDLED;
-	}
-
-	idle_connection_emit_queued_aliases_changed(priv->conn);
-
-	if (!priv->channels) {
-		IDLE_DEBUG("Channels hash table missing, ignoring...");
-		return IDLE_PARSER_HANDLER_RESULT_NOT_HANDLED;
-	}
-
-	if (!(chan = g_hash_table_lookup(priv->channels, GUINT_TO_POINTER(handle))))
-		chan = _create_channel(factory, handle, NULL);
-
-	idle_im_channel_receive(chan, type, handle, body);
-
-	g_free(body);
-
-	return IDLE_PARSER_HANDLER_RESULT_HANDLED;
-}
-
-static void _iface_close_all(TpChannelFactoryIface *iface) {
-	IdleIMFactoryPrivate *priv = IDLE_IM_FACTORY_GET_PRIVATE(iface);
-
-	if (!priv->channels) {
-		IDLE_DEBUG("Channels already closed, ignoring...");
-		return;
-	}
-
-	GHashTable *tmp = priv->channels;
-	priv->channels = NULL;
-	g_hash_table_destroy(tmp);
-}
-
-static void _iface_connecting(TpChannelFactoryIface *iface) {
-	IdleIMFactoryPrivate *priv = IDLE_IM_FACTORY_GET_PRIVATE(iface);
-
-	idle_parser_add_handler(priv->conn->parser, IDLE_PARSER_PREFIXCMD_NOTICE_USER, _notice_privmsg_handler, iface);
-	idle_parser_add_handler(priv->conn->parser, IDLE_PARSER_PREFIXCMD_PRIVMSG_USER, _notice_privmsg_handler, iface);
-}
-
-static void _iface_disconnected(TpChannelFactoryIface *iface) {
-	IdleIMFactoryPrivate *priv = IDLE_IM_FACTORY_GET_PRIVATE(iface);
-
-	idle_parser_remove_handlers_by_data(priv->conn->parser, iface);
-}
-
-struct _ForeachHelperData {
-	TpChannelFunc func;
-	gpointer user_data;
-};
-
-static void _foreach_helper(gpointer key, gpointer value, gpointer user_data) {
-	struct _ForeachHelperData *data = user_data;
-	data->func(value, data->user_data);
-}
-
-static void _iface_foreach(TpChannelFactoryIface *iface, TpChannelFunc func, gpointer user_data) {
-	IdleIMFactoryPrivate *priv = IDLE_IM_FACTORY_GET_PRIVATE(iface);
-	struct _ForeachHelperData data = {func, user_data};
-
-	if (!priv->channels) {
-		IDLE_DEBUG("Channels hash table missing, ignoring...");
-		return;
-	}
-
-	g_hash_table_foreach(priv->channels, _foreach_helper, &data);
-}
-
-static TpChannelFactoryRequestStatus _iface_request(TpChannelFactoryIface *iface, const gchar *chan_type, TpHandleType handle_type, guint handle, gpointer request, TpChannelIface **new_chan, GError **error) {
-	IdleIMFactory *factory = IDLE_IM_FACTORY(iface);
-	IdleIMFactoryPrivate *priv = IDLE_IM_FACTORY_GET_PRIVATE(factory);
-
-	if (!g_str_equal(chan_type, TP_IFACE_CHANNEL_TYPE_TEXT))
-		return TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_IMPLEMENTED;
-
-	if (handle_type != TP_HANDLE_TYPE_CONTACT)
-		return TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_AVAILABLE;
-
-	if (!tp_handle_is_valid(tp_base_connection_get_handles(TP_BASE_CONNECTION(priv->conn), TP_HANDLE_TYPE_CONTACT), handle, error))
-		return TP_CHANNEL_FACTORY_REQUEST_STATUS_INVALID_HANDLE;
-
-	if (!priv->channels) {
-		IDLE_DEBUG("Channels hash table missing, failing request...");
-		return TP_CHANNEL_FACTORY_REQUEST_STATUS_ERROR;
-	}
-
-	if ((*new_chan = g_hash_table_lookup(priv->channels, GUINT_TO_POINTER(handle)))) {
-		return TP_CHANNEL_FACTORY_REQUEST_STATUS_EXISTING;
-	} else {
-		*new_chan = (TpChannelIface *) _create_channel(factory, handle, request);
-		return TP_CHANNEL_FACTORY_REQUEST_STATUS_CREATED;
-	}
-}
-
-static IdleIMChannel *_create_channel(IdleIMFactory *factory, TpHandle handle, gpointer context) {
-	IdleIMFactoryPrivate *priv = IDLE_IM_FACTORY_GET_PRIVATE(factory);
-	IdleIMChannel *chan;
-	gchar *object_path;
-
-	object_path = g_strdup_printf("%s/ImChannel%u", priv->conn->parent.object_path, handle);
-	chan = g_object_new(IDLE_TYPE_IM_CHANNEL, "connection", priv->conn, "object-path", object_path, "handle", handle, NULL);
-
-	g_signal_connect(chan, "closed", (GCallback) _channel_closed_cb, factory);
-	g_hash_table_insert(priv->channels, GUINT_TO_POINTER(handle), chan);
-	tp_channel_factory_iface_emit_new_channel(factory, (TpChannelIface *) chan, context);
-
-	g_free(object_path);
-
-	return chan;
-}
-
-static void _channel_closed_cb(IdleIMChannel *chan, gpointer user_data) {
-	IdleIMFactoryPrivate *priv = IDLE_IM_FACTORY_GET_PRIVATE(user_data);
-	TpHandle handle;
-
-	if (priv->channels) {
-		g_object_get(chan, "handle", &handle, NULL);
-		g_hash_table_remove(priv->channels, GUINT_TO_POINTER(handle));
-	}
-}
-
-static void _factory_iface_init(gpointer g_iface, gpointer iface_data) {
-	TpChannelFactoryIfaceClass *klass = (TpChannelFactoryIfaceClass *) g_iface;
-
-	klass->close_all = _iface_close_all;
-	klass->connected = NULL;
-	klass->connecting = _iface_connecting;
-	klass->disconnected = _iface_disconnected;
-	klass->foreach = _iface_foreach;
-	klass->request = _iface_request;
-}
-
diff --git a/src/idle-im-manager.c b/src/idle-im-manager.c
new file mode 100644
index 0000000..972445f
--- /dev/null
+++ b/src/idle-im-manager.c
@@ -0,0 +1,489 @@
+/*
+ * This file is part of telepathy-idle
+ *
+ * Copyright (C) 2006-2007 Collabora Limited
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "idle-im-manager.h"
+
+#include <telepathy-glib/channel-manager.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/dbus.h>
+
+#define IDLE_DEBUG_FLAG IDLE_DEBUG_IM
+#include "idle-connection.h"
+#include "idle-ctcp.h"
+#include "idle-debug.h"
+#include "idle-im-channel.h"
+#include "idle-parser.h"
+#include "idle-text.h"
+
+static void _im_manager_iface_init(gpointer g_iface, gpointer iface_data);
+static GObject * _im_manager_constructor (GType type, guint n_props, GObjectConstructParam *props);
+static void _im_manager_dispose (GObject *object);
+
+G_DEFINE_TYPE_WITH_CODE(IdleIMManager, idle_im_manager, G_TYPE_OBJECT,
+		G_IMPLEMENT_INTERFACE(TP_TYPE_CHANNEL_MANAGER, _im_manager_iface_init));
+
+/* properties */
+enum {
+	PROP_CONNECTION = 1,
+	LAST_PROPERTY_ENUM
+};
+
+static const gchar * const im_channel_fixed_properties[] = {
+    TP_IFACE_CHANNEL ".ChannelType",
+    TP_IFACE_CHANNEL ".TargetHandleType",
+    NULL
+};
+
+static const gchar * const im_channel_allowed_properties[] = {
+    TP_IFACE_CHANNEL ".TargetHandle",
+    TP_IFACE_CHANNEL ".TargetID",
+    NULL
+};
+
+typedef struct _IdleIMManagerPrivate IdleIMManagerPrivate;
+struct _IdleIMManagerPrivate {
+	IdleConnection *conn;
+	GHashTable *channels;
+	int status_changed_id;
+	gboolean dispose_has_run;
+};
+
+#define IDLE_IM_MANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), IDLE_TYPE_IM_MANAGER, IdleIMManagerPrivate))
+
+static IdleParserHandlerResult _notice_privmsg_handler(IdleParser *parser, IdleParserMessageCode code, GValueArray *args, gpointer user_data);
+
+static void _im_manager_close_all(IdleIMManager *manager);
+static void connection_status_changed_cb (IdleConnection* conn, guint status, guint reason, IdleIMManager *self);
+
+static void _im_manager_foreach(TpChannelManager *manager, TpExportableChannelFunc func, gpointer user_data);
+static void _im_manager_foreach_class (TpChannelManager* manager, TpChannelManagerChannelClassFunc func, gpointer user_data);
+
+//static TpChannelManagerRequestStatus _iface_request(TpChannelFactoryIface *iface, const gchar *chan_type, TpHandleType handle_type, guint handle, gpointer request, TpChannelIface **new_chan, GError **error);
+
+static gboolean _im_manager_create_channel(TpChannelManager *manager, gpointer request_token, GHashTable *request_properties);
+static gboolean _im_manager_request_channel(TpChannelManager *manager, gpointer request_token, GHashTable *request_properties);
+static gboolean _im_manager_ensure_channel(TpChannelManager *manager, gpointer request_token, GHashTable *request_properties);
+static gboolean _im_manager_requestotron (IdleIMManager *self, gpointer request_token, GHashTable *request_properties, gboolean require_new);
+static IdleIMChannel *_im_manager_new_channel (IdleIMManager *mgr, TpHandle handle, gpointer request);
+
+static void _im_channel_closed_cb (IdleIMChannel *chan, gpointer user_data);
+
+static void idle_im_manager_init(IdleIMManager *obj) {
+	IdleIMManagerPrivate *priv = IDLE_IM_MANAGER_GET_PRIVATE(obj);
+	priv->channels = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
+	priv->status_changed_id = 0;
+	priv->dispose_has_run = FALSE;
+}
+
+static void idle_im_manager_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {
+	IdleIMManager *mgr = IDLE_IM_MANAGER(object);
+	IdleIMManagerPrivate *priv = IDLE_IM_MANAGER_GET_PRIVATE(mgr);
+
+	switch (property_id) {
+		case PROP_CONNECTION:
+			g_value_set_object(value, priv->conn);
+			break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+			break;
+	}
+}
+
+static void idle_im_manager_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {
+	IdleIMManager *manager = IDLE_IM_MANAGER(object);
+	IdleIMManagerPrivate *priv = IDLE_IM_MANAGER_GET_PRIVATE(manager);
+
+	switch (property_id) {
+		case PROP_CONNECTION:
+			priv->conn = g_value_get_object(value);
+			break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+			break;
+	}
+}
+
+static void idle_im_manager_class_init(IdleIMManagerClass *klass) {
+	GObjectClass *object_class = G_OBJECT_CLASS(klass);
+	GParamSpec *param_spec;
+
+	g_type_class_add_private(klass, sizeof(IdleIMManagerPrivate));
+
+	object_class->constructor = _im_manager_constructor;
+	object_class->dispose = _im_manager_dispose;
+	object_class->get_property = idle_im_manager_get_property;
+	object_class->set_property = idle_im_manager_set_property;
+
+	param_spec = g_param_spec_object("connection", "IdleConnection object", "The IdleConnection object that owns this IM channel manager object.", IDLE_TYPE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
+	g_object_class_install_property(object_class, PROP_CONNECTION, param_spec);
+}
+
+static GObject *
+_im_manager_constructor (GType type,
+						 guint n_props,
+						 GObjectConstructParam *props)
+{
+	GObject *obj;
+	IdleIMManager *self;
+	IdleIMManagerPrivate *priv;
+
+	obj = G_OBJECT_CLASS (idle_im_manager_parent_class)->constructor (type,
+																	  n_props,
+																	  props);
+
+	self = IDLE_IM_MANAGER (obj);
+	priv = IDLE_IM_MANAGER_GET_PRIVATE (self);
+
+	g_return_val_if_fail (priv->conn, obj);
+
+	priv->status_changed_id = g_signal_connect (priv->conn,
+												"status-changed", (GCallback)
+												connection_status_changed_cb,
+												self);
+
+	return obj;
+}
+
+
+static IdleParserHandlerResult _notice_privmsg_handler(IdleParser *parser, IdleParserMessageCode code, GValueArray *args, gpointer user_data) {
+	IdleIMManager *manager = IDLE_IM_MANAGER(user_data);
+	IdleIMManagerPrivate *priv = IDLE_IM_MANAGER_GET_PRIVATE(manager);
+	TpHandle handle = (TpHandle) g_value_get_uint(g_value_array_get_nth(args, 0));
+	IdleIMChannel *chan;
+	TpChannelTextMessageType type;
+	gchar *body;
+
+	if (code == IDLE_PARSER_PREFIXCMD_NOTICE_USER) {
+		type = TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE;
+		body = idle_ctcp_kill_blingbling(g_value_get_string(g_value_array_get_nth(args, 2)));
+	} else {
+		gboolean decoded = idle_text_decode(g_value_get_string(g_value_array_get_nth(args, 2)), &type, &body);
+		if (!decoded)
+			return IDLE_PARSER_HANDLER_RESULT_NOT_HANDLED;
+	}
+
+	idle_connection_emit_queued_aliases_changed(priv->conn);
+
+	if (!priv->channels) {
+		IDLE_DEBUG("Channels hash table missing, ignoring...");
+		return IDLE_PARSER_HANDLER_RESULT_NOT_HANDLED;
+	}
+
+	if (!(chan = g_hash_table_lookup(priv->channels, GUINT_TO_POINTER(handle))))
+		chan = _im_manager_new_channel(manager, handle, NULL);
+
+	idle_im_channel_receive(chan, type, handle, body);
+
+	g_free(body);
+
+	return IDLE_PARSER_HANDLER_RESULT_HANDLED;
+}
+
+static void _im_manager_close_all(IdleIMManager *manager) {
+	IdleIMManagerPrivate *priv = IDLE_IM_MANAGER_GET_PRIVATE(manager);
+
+	if (priv->channels) {
+		GHashTable *tmp = priv->channels;
+		priv->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 connection_status_changed_cb (IdleConnection* conn,
+										  guint status,
+										  guint reason,
+										  IdleIMManager *self)
+{
+	IdleIMManagerPrivate *priv = IDLE_IM_MANAGER_GET_PRIVATE(self);
+
+	if (status == TP_CONNECTION_STATUS_DISCONNECTED) {
+		idle_parser_remove_handlers_by_data(priv->conn->parser, self);
+		_im_manager_close_all (self);
+	} else if (status == TP_CONNECTION_STATUS_CONNECTED) {
+		idle_parser_add_handler(priv->conn->parser, IDLE_PARSER_PREFIXCMD_NOTICE_USER, _notice_privmsg_handler, self);
+		idle_parser_add_handler(priv->conn->parser, IDLE_PARSER_PREFIXCMD_PRIVMSG_USER, _notice_privmsg_handler, self);
+	}
+}
+
+/*
+static void _iface_connecting(TpChannelFactoryIface *iface) {
+	IdleIMFactoryPrivate *priv = IDLE_IM_FACTORY_GET_PRIVATE(iface);
+
+	idle_parser_add_handler(priv->conn->parser, IDLE_PARSER_PREFIXCMD_NOTICE_USER, _notice_privmsg_handler, iface);
+	idle_parser_add_handler(priv->conn->parser, IDLE_PARSER_PREFIXCMD_PRIVMSG_USER, _notice_privmsg_handler, iface);
+}
+
+static void _iface_disconnected(TpChannelFactoryIface *iface) {
+	IdleIMFactoryPrivate *priv = IDLE_IM_FACTORY_GET_PRIVATE(iface);
+
+	idle_parser_remove_handlers_by_data(priv->conn->parser, iface);
+}
+*/
+
+struct _ForeachHelperData {
+	TpExportableChannelFunc func;
+	gpointer user_data;
+};
+
+static void _foreach_helper(gpointer key, gpointer value, gpointer user_data) {
+	struct _ForeachHelperData *data = user_data;
+	data->func(value, data->user_data);
+}
+
+static void _im_manager_foreach(TpChannelManager *manager, TpExportableChannelFunc func, gpointer user_data) {
+	IdleIMManagerPrivate *priv = IDLE_IM_MANAGER_GET_PRIVATE(manager);
+	struct _ForeachHelperData data = {func, user_data};
+
+	if (!priv->channels) {
+		IDLE_DEBUG("Channels hash table missing, ignoring...");
+		return;
+	}
+
+	g_hash_table_foreach(priv->channels, _foreach_helper, &data);
+}
+
+
+static void _im_manager_foreach_class (TpChannelManager* manager,
+									   TpChannelManagerChannelClassFunc func,
+									   gpointer user_data)
+{
+	GHashTable *table;
+	GValue *value;
+
+	table = g_hash_table_new_full (g_str_hash, g_str_equal,
+								   NULL, (GDestroyNotify) tp_g_value_slice_free);
+
+	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, (gpointer) im_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, (gpointer) im_channel_fixed_properties[1], value);
+
+	func (manager, table, im_channel_allowed_properties, user_data);
+
+	g_hash_table_destroy (table);
+}
+
+
+static gboolean
+_im_manager_create_channel(TpChannelManager *manager,
+						   gpointer request_token,
+						   GHashTable *request_properties)
+{
+	IdleIMManager *self = IDLE_IM_MANAGER (manager);
+
+	return _im_manager_requestotron (self, request_token, request_properties,
+									 TRUE);
+}
+
+
+static gboolean
+_im_manager_request_channel(TpChannelManager *manager,
+							gpointer request_token,
+							GHashTable *request_properties)
+{
+	IdleIMManager *self = IDLE_IM_MANAGER (manager);
+
+	return _im_manager_requestotron (self, request_token, request_properties,
+									 FALSE);
+}
+
+
+static gboolean
+_im_manager_ensure_channel(TpChannelManager *manager,
+						   gpointer request_token,
+						   GHashTable *request_properties)
+{
+	IdleIMManager *self = IDLE_IM_MANAGER (manager);
+
+	return _im_manager_requestotron (self, request_token, request_properties,
+									 FALSE);
+}
+
+
+static gboolean
+_im_manager_requestotron (IdleIMManager *self,
+						  gpointer request_token,
+						  GHashTable *request_properties,
+						  gboolean require_new)
+{
+	IdleIMManagerPrivate *priv = IDLE_IM_MANAGER_GET_PRIVATE (self);
+	TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn;
+	TpHandleRepoIface *contact_repo =
+		tp_base_connection_get_handles (base_conn, TP_HANDLE_TYPE_CONTACT);
+	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 (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);
+
+	if (!tp_handle_is_valid (contact_repo, handle, &error))
+		goto error;
+
+	/* Check if there are any other properties that we don't understand */
+	if (tp_channel_manager_asv_has_unknown_properties (request_properties,
+													   im_channel_fixed_properties,
+													   im_channel_allowed_properties,
+													   &error))
+	{
+		goto error;
+	}
+
+	/* Don't support opening a channel to our self handle */
+	if (handle == base_conn->self_handle)
+	{
+		g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
+					 "Can't open a text channel to yourself");
+		goto error;
+	}
+
+	channel = g_hash_table_lookup (priv->channels, GUINT_TO_POINTER (handle));
+
+	if (channel == NULL)
+	{
+		_im_manager_new_channel (self, handle, request_token);
+		return TRUE;
+	}
+
+	if (require_new)
+	{
+		g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+					 "Already chatting with contact #%u in another channel", handle);
+		goto error;
+	}
+
+	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;
+}
+
+
+static void
+_im_channel_closed_cb (IdleIMChannel *chan,
+					  gpointer user_data)
+{
+	IdleIMManager *self = IDLE_IM_MANAGER (user_data);
+	IdleIMManagerPrivate *priv = IDLE_IM_MANAGER_GET_PRIVATE (self);
+	TpHandle handle;
+
+	tp_channel_manager_emit_channel_closed_for_object (self,
+													   TP_EXPORTABLE_CHANNEL (chan));
+
+	if (priv->channels)
+	{
+		g_object_get (chan, "handle", &handle, NULL);
+		IDLE_DEBUG ("Removing channel with handle %u", handle);
+		g_hash_table_remove (priv->channels, GUINT_TO_POINTER (handle));
+	}
+}
+
+
+static IdleIMChannel *
+_im_manager_new_channel (IdleIMManager *mgr,
+						 TpHandle handle,
+						 gpointer request)
+{
+	IdleIMManagerPrivate *priv = IDLE_IM_MANAGER_GET_PRIVATE (mgr);
+	TpBaseConnection *base_connection = TP_BASE_CONNECTION (priv->conn);
+	TpHandleRepoIface *handle_repo =
+		tp_base_connection_get_handles (base_connection, TP_HANDLE_TYPE_CONTACT);
+	IdleIMChannel *chan;
+	const gchar *name;
+	gchar *object_path = NULL;
+	GSList *requests = NULL;
+
+	g_assert (g_hash_table_lookup (priv->channels, GUINT_TO_POINTER (handle))
+			  == NULL);
+
+	name = tp_handle_inspect (handle_repo, handle);
+	IDLE_DEBUG ("Requested channel for handle: %u (%s)", handle, name);
+
+	object_path = g_strdup_printf("%s/ImChannel%u", priv->conn->parent.object_path, handle);
+	chan = g_object_new (IDLE_TYPE_IM_CHANNEL,
+						 "connection", priv->conn,
+						 "object-path", object_path,
+						 "handle", handle,
+						 NULL);
+	g_free (object_path);
+	g_hash_table_insert (priv->channels, GUINT_TO_POINTER (handle), chan);
+
+	if (request != NULL)
+		requests = g_slist_prepend (requests, request);
+
+	tp_channel_manager_emit_new_channel (mgr, TP_EXPORTABLE_CHANNEL (chan),
+										 requests);
+
+	g_slist_free (requests);
+
+	g_signal_connect (chan, "closed", G_CALLBACK (_im_channel_closed_cb), mgr);
+
+	return chan;
+}
+
+static void _im_manager_iface_init(gpointer g_iface, gpointer iface_data) {
+	TpChannelManagerIface *iface = g_iface;
+
+	iface->foreach_channel = _im_manager_foreach;
+	iface->foreach_channel_class = _im_manager_foreach_class;
+	iface->request_channel = _im_manager_request_channel;
+	iface->create_channel = _im_manager_create_channel;
+	iface->ensure_channel = _im_manager_ensure_channel;
+}
+
+static void
+_im_manager_dispose (GObject *object)
+{
+	IdleIMManager *self = IDLE_IM_MANAGER (object);
+	IdleIMManagerPrivate *priv = IDLE_IM_MANAGER_GET_PRIVATE (self);
+
+	if (priv->dispose_has_run)
+		return;
+
+	priv->dispose_has_run = TRUE;
+
+	_im_manager_close_all (self);
+
+	if (G_OBJECT_CLASS (idle_im_manager_parent_class)->dispose)
+		G_OBJECT_CLASS (idle_im_manager_parent_class)->dispose (object);
+}
+
diff --git a/src/idle-im-factory.h b/src/idle-im-manager.h
similarity index 51%
rename from src/idle-im-factory.h
rename to src/idle-im-manager.h
index 2816e41..1967a29 100644
--- a/src/idle-im-factory.h
+++ b/src/idle-im-manager.h
@@ -18,34 +18,34 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#ifndef __IDLE_IM_FACTORY_H__
-#define __IDLE_IM_FACTORY_H__
+#ifndef __IDLE_IM_MANAGER_H__
+#define __IDLE_IM_MANAGER_H__
 
 #include <glib-object.h>
 
 G_BEGIN_DECLS
 
-typedef struct _IdleIMFactory IdleIMFactory;
-typedef struct _IdleIMFactoryClass IdleIMFactoryClass;
+typedef struct _IdleIMManager IdleIMManager;
+typedef struct _IdleIMManagerClass IdleIMManagerClass;
 
-struct _IdleIMFactoryClass {
+struct _IdleIMManagerClass {
 	GObjectClass parent_class;
 };
 
-struct _IdleIMFactory {
+struct _IdleIMManager {
 	GObject parent;
 };
 
-GType idle_im_factory_get_type();
+GType idle_im_manager_get_type();
 
-#define IDLE_TYPE_IM_FACTORY (idle_im_factory_get_type())
-#define IDLE_IM_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), IDLE_TYPE_IM_FACTORY, IdleIMFactory))
-#define IDLE_IM_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), IDLE_TYPE_IM_FACTORY, IdleIMFactoryClass))
-#define IDLE_IS_IM_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), IDLE_TYPE_IM_FACTORY))
-#define IDLE_IS_IM_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), IDLE_TYPE_IM_FACTORY))
-#define IDLE_IM_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), IDLE_TYPE_IM_FACTORY, IdleIMFactoryClass))
+#define IDLE_TYPE_IM_MANAGER (idle_im_manager_get_type())
+#define IDLE_IM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), IDLE_TYPE_IM_MANAGER, IdleIMManager))
+#define IDLE_IM_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), IDLE_TYPE_IM_MANAGER, IdleIMManagerClass))
+#define IDLE_IS_IM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), IDLE_TYPE_IM_MANAGER))
+#define IDLE_IS_IM_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), IDLE_TYPE_IM_MANAGER))
+#define IDLE_IM_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), IDLE_TYPE_IM_MANAGER, IdleIMManagerClass))
 
 G_END_DECLS
 
-#endif /* #ifndef __IDLE_IM_FACTORY_H__ */
+#endif /* #ifndef __IDLE_IM_MANAGER_H__ */
 
-- 
1.5.6.5




More information about the telepathy-commits mailing list