diff options
Diffstat (limited to 'qt4/tests/lib/glib/echo/im-manager.c')
-rw-r--r-- | qt4/tests/lib/glib/echo/im-manager.c | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/qt4/tests/lib/glib/echo/im-manager.c b/qt4/tests/lib/glib/echo/im-manager.c new file mode 100644 index 000000000..7403af282 --- /dev/null +++ b/qt4/tests/lib/glib/echo/im-manager.c @@ -0,0 +1,378 @@ +/* + * im-manager.c - an example channel manager for channels talking to a + * particular contact. Similar code is used for 1-1 IM channels in many + * protocols (IRC private messages ("/query"), XMPP IM etc.) + * + * Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/> + * Copyright (C) 2007 Nokia Corporation + * + * Copying and distribution of this file, with or without modification, + * are permitted in any medium without royalty provided the copyright + * notice and this notice are preserved. + */ + +#include "im-manager.h" + +#include <dbus/dbus-glib.h> + +#include <telepathy-glib/telepathy-glib.h> + +#include "chan.h" + +static void channel_manager_iface_init (gpointer, gpointer); + +G_DEFINE_TYPE_WITH_CODE (ExampleEchoImManager, + example_echo_im_manager, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER, + channel_manager_iface_init)) + +/* type definition stuff */ + +enum +{ + PROP_CONNECTION = 1, + N_PROPS +}; + +struct _ExampleEchoImManagerPrivate +{ + TpBaseConnection *conn; + + /* GUINT_TO_POINTER (handle) => ExampleEchoChannel */ + GHashTable *channels; + gulong status_changed_id; +}; + +static void +example_echo_im_manager_init (ExampleEchoImManager *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_ECHO_IM_MANAGER, + ExampleEchoImManagerPrivate); + + self->priv->channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, g_object_unref); +} + +static void example_echo_im_manager_close_all (ExampleEchoImManager *self); + +static void +dispose (GObject *object) +{ + ExampleEchoImManager *self = EXAMPLE_ECHO_IM_MANAGER (object); + + example_echo_im_manager_close_all (self); + g_assert (self->priv->channels == NULL); + + ((GObjectClass *) example_echo_im_manager_parent_class)->dispose (object); +} + +static void +get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + ExampleEchoImManager *self = EXAMPLE_ECHO_IM_MANAGER (object); + + switch (property_id) + { + case PROP_CONNECTION: + g_value_set_object (value, self->priv->conn); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + ExampleEchoImManager *self = EXAMPLE_ECHO_IM_MANAGER (object); + + switch (property_id) + { + case PROP_CONNECTION: + /* We don't ref the connection, because it owns a reference to the + * channel manager, and it guarantees that the manager's lifetime is + * less than its lifetime */ + self->priv->conn = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +status_changed_cb (TpBaseConnection *conn, + guint status, + guint reason, + ExampleEchoImManager *self) +{ + if (status == TP_CONNECTION_STATUS_DISCONNECTED) + example_echo_im_manager_close_all (self); +} + +static void +constructed (GObject *object) +{ + ExampleEchoImManager *self = EXAMPLE_ECHO_IM_MANAGER (object); + void (*chain_up) (GObject *) = + ((GObjectClass *) example_echo_im_manager_parent_class)->constructed; + + if (chain_up != NULL) + { + chain_up (object); + } + + self->priv->status_changed_id = g_signal_connect (self->priv->conn, + "status-changed", (GCallback) status_changed_cb, self); +} + +static void +example_echo_im_manager_class_init (ExampleEchoImManagerClass *klass) +{ + GParamSpec *param_spec; + GObjectClass *object_class = (GObjectClass *) klass; + + object_class->constructed = constructed; + object_class->dispose = dispose; + object_class->get_property = get_property; + object_class->set_property = set_property; + + param_spec = g_param_spec_object ("connection", "Connection object", + "The connection that owns this channel manager", + TP_TYPE_BASE_CONNECTION, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | + G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); + + g_type_class_add_private (klass, sizeof (ExampleEchoImManagerPrivate)); +} + +static void +example_echo_im_manager_close_all (ExampleEchoImManager *self) +{ + if (self->priv->channels != NULL) + { + GHashTable *tmp = self->priv->channels; + + 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 +example_echo_im_manager_foreach_channel (TpChannelManager *iface, + TpExportableChannelFunc callback, + gpointer user_data) +{ + ExampleEchoImManager *self = EXAMPLE_ECHO_IM_MANAGER (iface); + GHashTableIter iter; + gpointer handle, channel; + + g_hash_table_iter_init (&iter, self->priv->channels); + + while (g_hash_table_iter_next (&iter, &handle, &channel)) + { + callback (TP_EXPORTABLE_CHANNEL (channel), user_data); + } +} + +static void +channel_closed_cb (ExampleEchoChannel *chan, + ExampleEchoImManager *self) +{ + tp_channel_manager_emit_channel_closed_for_object (self, + TP_EXPORTABLE_CHANNEL (chan)); + + if (self->priv->channels != NULL) + { + TpHandle handle; + gboolean really_destroyed; + + g_object_get (chan, + "handle", &handle, + "channel-destroyed", &really_destroyed, + NULL); + + /* Re-announce the channel if it's not yet ready to go away (pending + * messages) */ + if (really_destroyed) + { + g_hash_table_remove (self->priv->channels, + GUINT_TO_POINTER (handle)); + } + else + { + tp_channel_manager_emit_new_channel (self, + TP_EXPORTABLE_CHANNEL (chan), NULL); + } + } +} + +static void +new_channel (ExampleEchoImManager *self, + TpHandle handle, + TpHandle initiator, + gpointer request_token) +{ + ExampleEchoChannel *chan; + gchar *object_path; + GSList *requests = NULL; + + object_path = g_strdup_printf ("%s/EchoChannel%u", + self->priv->conn->object_path, handle); + + chan = g_object_new (EXAMPLE_TYPE_ECHO_CHANNEL, + "connection", self->priv->conn, + "object-path", object_path, + "handle", handle, + "initiator-handle", initiator, + NULL); + + g_free (object_path); + + g_signal_connect (chan, "closed", (GCallback) channel_closed_cb, self); + + /* self->priv->channels takes ownership of 'chan' */ + g_hash_table_insert (self->priv->channels, GUINT_TO_POINTER (handle), chan); + + 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); +} + +static const gchar * const fixed_properties[] = { + TP_PROP_CHANNEL_CHANNEL_TYPE, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, + NULL +}; + +static const gchar * const allowed_properties[] = { + TP_PROP_CHANNEL_TARGET_HANDLE, + TP_PROP_CHANNEL_TARGET_ID, + NULL +}; + +static void +example_echo_im_manager_foreach_channel_class (TpChannelManager *manager, + TpChannelManagerChannelClassFunc func, + gpointer user_data) +{ + GHashTable *table = tp_asv_new ( + TP_PROP_CHANNEL_CHANNEL_TYPE, + G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, + NULL); + + + func (manager, table, allowed_properties, user_data); + + g_hash_table_destroy (table); +} + +static gboolean +example_echo_im_manager_request (ExampleEchoImManager *self, + gpointer request_token, + GHashTable *request_properties, + gboolean require_new) +{ + TpHandle handle; + ExampleEchoChannel *chan; + GError *error = NULL; + + if (tp_strdiff (tp_asv_get_string (request_properties, + TP_PROP_CHANNEL_CHANNEL_TYPE), + TP_IFACE_CHANNEL_TYPE_TEXT)) + { + return FALSE; + } + + if (tp_asv_get_uint32 (request_properties, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL) != TP_HANDLE_TYPE_CONTACT) + { + return FALSE; + } + + handle = tp_asv_get_uint32 (request_properties, + TP_PROP_CHANNEL_TARGET_HANDLE, NULL); + g_assert (handle != 0); + + if (tp_channel_manager_asv_has_unknown_properties (request_properties, + fixed_properties, allowed_properties, &error)) + { + goto error; + } + + chan = g_hash_table_lookup (self->priv->channels, GUINT_TO_POINTER (handle)); + + if (chan == NULL) + { + new_channel (self, handle, self->priv->conn->self_handle, request_token); + } + else if (require_new) + { + g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + "An echo channel to contact #%u already exists", handle); + goto error; + } + 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 +example_echo_im_manager_create_channel (TpChannelManager *manager, + gpointer request_token, + GHashTable *request_properties) +{ + return example_echo_im_manager_request (EXAMPLE_ECHO_IM_MANAGER (manager), + request_token, request_properties, TRUE); +} + +static gboolean +example_echo_im_manager_ensure_channel (TpChannelManager *manager, + gpointer request_token, + GHashTable *request_properties) +{ + return example_echo_im_manager_request (EXAMPLE_ECHO_IM_MANAGER (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 = example_echo_im_manager_foreach_channel; + iface->foreach_channel_class = example_echo_im_manager_foreach_channel_class; + iface->create_channel = example_echo_im_manager_create_channel; + iface->ensure_channel = example_echo_im_manager_ensure_channel; + /* In this channel manager, Request has the same semantics as Ensure */ + iface->request_channel = example_echo_im_manager_ensure_channel; +} |