[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