[Telepathy-commits] [telepathy-salut/master] SalutTubesManager implements the enhenced capabilities interface
Alban Crequy
alban.crequy at collabora.co.uk
Thu Feb 26 11:20:09 PST 2009
---
src/salut-tubes-manager.c | 471 ++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 470 insertions(+), 1 deletions(-)
diff --git a/src/salut-tubes-manager.c b/src/salut-tubes-manager.c
index 12a9546..3de463f 100644
--- a/src/salut-tubes-manager.c
+++ b/src/salut-tubes-manager.c
@@ -40,10 +40,12 @@
#include "debug.h"
#include "extensions/extensions.h"
#include "salut-connection.h"
+#include "salut-capabilities.h"
#include "salut-caps-channel-manager.h"
#include "salut-tubes-channel.h"
#include "salut-muc-manager.h"
#include "salut-muc-channel.h"
+#include "salut-self.h"
#include "salut-util.h"
#include "tube-iface.h"
@@ -57,6 +59,7 @@ static void tubes_channel_closed_cb (SalutTubesChannel *chan,
static void salut_tubes_manager_iface_init (gpointer g_iface,
gpointer iface_data);
+static void caps_channel_manager_iface_init (gpointer, gpointer);
G_DEFINE_TYPE_WITH_CODE (SalutTubesManager,
salut_tubes_manager,
@@ -64,7 +67,7 @@ G_DEFINE_TYPE_WITH_CODE (SalutTubesManager,
G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
salut_tubes_manager_iface_init);
G_IMPLEMENT_INTERFACE (SALUT_TYPE_CAPS_CHANNEL_MANAGER,
- NULL));
+ caps_channel_manager_iface_init));
/* properties */
enum
@@ -92,6 +95,35 @@ struct _SalutTubesManagerPrivate
#define SALUT_TUBES_MANAGER_GET_PRIVATE(obj) \
((SalutTubesManagerPrivate *) obj->priv)
+typedef struct _TubesCapabilities TubesCapabilities;
+struct _TubesCapabilities
+{
+ /* Stores the list of tubes supported by a contact. We use a hash table. The
+ * key is the service name and the value is NULL.
+ *
+ * It can also be used to store the list of tubes that Salut advertises to
+ * support when Salut replies to XEP-0115 Entity Capabilities requests. In
+ * this case, a Feature structure is associated with each tube type in order
+ * to be returned by salut_private_tubes_factory_get_feature_list().
+ *
+ * So the value of the hash table is either NULL (if the variable is related
+ * to a contact handle), either a Feature structure (if the variable is
+ * related to the self_handle).
+ */
+
+ /* gchar *Service -> NULL
+ * or
+ * gchar *Service -> Feature *feature
+ */
+ GHashTable *stream_tube_caps;
+
+ /* gchar *ServiceName -> NULL
+ * or
+ * gchar *ServiceName -> Feature *feature
+ */
+ GHashTable *dbus_tube_caps;
+};
+
static void
salut_tubes_manager_init (SalutTubesManager *self)
{
@@ -1029,3 +1061,440 @@ salut_tubes_manager_iface_init (gpointer g_iface,
iface->create_channel = salut_tubes_manager_create_channel;
iface->request_channel = salut_tubes_manager_request_channel;
}
+
+static void
+add_service_to_array (gchar *service,
+ GPtrArray *arr,
+ TpTubeType type,
+ TpHandle handle)
+{
+ GValue monster = {0, };
+ GHashTable *fixed_properties;
+ GValue *channel_type_value;
+ GValue *target_handle_type_value;
+ gchar *tube_allowed_properties[] =
+ {
+ TP_IFACE_CHANNEL ".TargetHandle",
+ NULL
+ };
+
+ g_assert (type == TP_TUBE_TYPE_STREAM || type == TP_TUBE_TYPE_DBUS);
+
+ g_value_init (&monster, SALUT_STRUCT_TYPE_ENHANCED_CONTACT_CAPABILITY);
+ g_value_take_boxed (&monster,
+ dbus_g_type_specialized_construct (
+ SALUT_STRUCT_TYPE_ENHANCED_CONTACT_CAPABILITY));
+
+ fixed_properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
+ (GDestroyNotify) tp_g_value_slice_free);
+
+ channel_type_value = tp_g_value_slice_new (G_TYPE_STRING);
+ if (type == TP_TUBE_TYPE_STREAM)
+ g_value_set_static_string (channel_type_value,
+ SALUT_IFACE_CHANNEL_TYPE_STREAM_TUBE);
+ else
+ g_value_set_static_string (channel_type_value,
+ SALUT_IFACE_CHANNEL_TYPE_DBUS_TUBE);
+ g_hash_table_insert (fixed_properties, TP_IFACE_CHANNEL ".ChannelType",
+ channel_type_value);
+
+ target_handle_type_value = tp_g_value_slice_new (G_TYPE_UINT);
+ g_value_set_uint (target_handle_type_value, TP_HANDLE_TYPE_CONTACT);
+ g_hash_table_insert (fixed_properties,
+ TP_IFACE_CHANNEL ".TargetHandleType", target_handle_type_value);
+
+ target_handle_type_value = tp_g_value_slice_new (G_TYPE_STRING);
+ g_value_set_string (target_handle_type_value, service);
+ if (type == TP_TUBE_TYPE_STREAM)
+ g_hash_table_insert (fixed_properties,
+ SALUT_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service",
+ target_handle_type_value);
+ else
+ g_hash_table_insert (fixed_properties,
+ SALUT_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName",
+ target_handle_type_value);
+
+ dbus_g_type_struct_set (&monster,
+ 0, handle,
+ 1, fixed_properties,
+ 2, tube_allowed_properties,
+ G_MAXUINT);
+
+ g_hash_table_destroy (fixed_properties);
+
+ g_ptr_array_add (arr, g_value_get_boxed (&monster));
+}
+
+static void
+salut_private_tubes_factory_get_contact_caps (
+ SalutCapsChannelManager *manager,
+ SalutConnection *conn,
+ TpHandle handle,
+ GPtrArray *arr)
+{
+ SalutTubesManager *self = SALUT_TUBES_MANAGER (manager);
+ SalutTubesManagerPrivate *priv = SALUT_TUBES_MANAGER_GET_PRIVATE (self);
+ TpBaseConnection *base = (TpBaseConnection *) conn;
+ TubesCapabilities *caps;
+ GHashTable *stream_tube_caps;
+ GHashTable *dbus_tube_caps;
+ GHashTableIter tube_caps_iter;
+ gchar *service;
+ GHashTable *per_channel_manager_caps;
+
+ g_assert (handle != 0);
+
+ if (handle == base->self_handle)
+ {
+ SalutSelf *salut_self;
+ g_object_get (conn, "self", &salut_self, NULL);
+ per_channel_manager_caps = salut_self->per_channel_manager_caps;
+ }
+ else
+ {
+ SalutContact *contact = salut_contact_manager_get_contact (
+ priv->contact_manager, handle);
+
+ if (contact == NULL)
+ return;
+
+ per_channel_manager_caps = contact->per_channel_manager_caps;
+ }
+
+ if (per_channel_manager_caps == NULL)
+ return;
+
+ caps = g_hash_table_lookup (per_channel_manager_caps, manager);
+ if (caps == NULL)
+ return;
+
+ stream_tube_caps = caps->stream_tube_caps;
+ dbus_tube_caps = caps->dbus_tube_caps;
+
+ if (stream_tube_caps != NULL)
+ {
+ g_hash_table_iter_init (&tube_caps_iter, stream_tube_caps);
+ while (g_hash_table_iter_next (&tube_caps_iter, (gpointer *) &service,
+ NULL))
+ {
+ add_service_to_array (service, arr, TP_TUBE_TYPE_STREAM, handle);
+ }
+ }
+
+ if (dbus_tube_caps != NULL)
+ {
+ g_hash_table_iter_init (&tube_caps_iter, dbus_tube_caps);
+ while (g_hash_table_iter_next (&tube_caps_iter, (gpointer *) &service,
+ NULL))
+ {
+ add_service_to_array (service, arr, TP_TUBE_TYPE_DBUS, handle);
+ }
+ }
+}
+
+static void
+salut_private_tubes_factory_get_feature_list (
+ SalutCapsChannelManager *manager,
+ gpointer specific_caps,
+ GSList **features)
+{
+ TubesCapabilities *caps = specific_caps;
+ GHashTableIter iter;
+ gchar *service;
+ Feature *feat;
+
+ g_hash_table_iter_init (&iter, caps->stream_tube_caps);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &service,
+ (gpointer *) &feat))
+ {
+ *features = g_slist_append (*features, (gpointer) feat);
+ }
+
+ g_hash_table_iter_init (&iter, caps->dbus_tube_caps);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &service,
+ (gpointer *) &feat))
+ {
+ *features = g_slist_append (*features, (gpointer) feat);
+ }
+}
+
+static gboolean
+_parse_caps_item (GibberXmppNode *node, gpointer user_data)
+{
+ TubesCapabilities *caps = (TubesCapabilities *) user_data;
+ const gchar *var;
+
+ if (0 != strcmp (node->name, "feature"))
+ return TRUE;
+
+ var = gibber_xmpp_node_get_attribute (node, "var");
+
+ if (NULL == var)
+ return TRUE;
+
+ if (g_str_has_prefix (var, GIBBER_TELEPATHY_NS_TUBES "/"))
+ {
+ /* http://telepathy.freedesktop.org/xmpp/tubes/$type/$service */
+ var += strlen (GIBBER_TELEPATHY_NS_TUBES "/");
+ if (g_str_has_prefix (var, "stream/"))
+ {
+ gchar *service;
+ var += strlen ("stream/");
+ service = g_strdup (var);
+ g_hash_table_insert (caps->stream_tube_caps, service, NULL);
+ }
+ else if (g_str_has_prefix (var, "dbus/"))
+ {
+ gchar *service;
+ var += strlen ("dbus/");
+ service = g_strdup (var);
+ g_hash_table_insert (caps->dbus_tube_caps, service, NULL);
+ }
+ }
+
+ return TRUE;
+}
+
+static gpointer
+salut_private_tubes_factory_parse_caps (
+ SalutCapsChannelManager *manager,
+ GibberXmppNode *node)
+{
+ TubesCapabilities *caps;
+
+ caps = g_new0 (TubesCapabilities, 1);
+ caps->stream_tube_caps = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_free);
+ caps->dbus_tube_caps = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_free);
+
+ gibber_xmpp_node_each_child (node, _parse_caps_item, caps);
+
+ return caps;
+}
+
+static void
+salut_private_tubes_factory_free_caps (
+ SalutCapsChannelManager *manager,
+ gpointer data)
+{
+ TubesCapabilities *caps = data;
+ g_hash_table_destroy (caps->stream_tube_caps);
+ g_hash_table_destroy (caps->dbus_tube_caps);
+ g_free (caps);
+}
+
+static void
+copy_caps_helper (gpointer key, gpointer value, gpointer user_data)
+{
+ GHashTable *out = user_data;
+ gchar *str = key;
+
+ g_hash_table_insert (out, g_strdup (str), NULL);
+}
+
+static void
+salut_private_tubes_factory_copy_caps (
+ SalutCapsChannelManager *manager,
+ gpointer *specific_caps_out,
+ gpointer specific_caps_in)
+{
+ TubesCapabilities *caps_in = specific_caps_in;
+ TubesCapabilities *caps_out = g_new0 (TubesCapabilities, 1);
+
+ caps_out->stream_tube_caps = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_free);
+ g_hash_table_foreach (caps_in->stream_tube_caps, copy_caps_helper,
+ caps_out->stream_tube_caps);
+
+ caps_out->dbus_tube_caps = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_free);
+ g_hash_table_foreach (caps_in->dbus_tube_caps, copy_caps_helper,
+ caps_out->dbus_tube_caps);
+
+ *specific_caps_out = caps_out;
+}
+
+static void
+salut_private_tubes_factory_update_caps (
+ SalutCapsChannelManager *manager,
+ gpointer *specific_caps_out,
+ gpointer specific_caps_in)
+{
+ TubesCapabilities *caps_out = (TubesCapabilities *) specific_caps_out;
+ TubesCapabilities *caps_in = (TubesCapabilities *) specific_caps_in;
+
+ if (caps_in == NULL)
+ return;
+
+ tp_g_hash_table_update (caps_out->stream_tube_caps,
+ caps_in->stream_tube_caps, (GBoxedCopyFunc) g_strdup, NULL);
+ tp_g_hash_table_update (caps_out->dbus_tube_caps,
+ caps_in->dbus_tube_caps, (GBoxedCopyFunc) g_strdup, NULL);
+}
+
+static gboolean
+salut_private_tubes_factory_caps_diff (
+ SalutCapsChannelManager *manager,
+ TpHandle handle,
+ gpointer specific_old_caps,
+ gpointer specific_new_caps)
+{
+ TubesCapabilities *old_caps = specific_old_caps;
+ TubesCapabilities *new_caps = specific_new_caps;
+ GHashTableIter tube_caps_iter;
+ gchar *service;
+
+ if (old_caps != NULL)
+ {
+ g_hash_table_iter_init (&tube_caps_iter, old_caps->stream_tube_caps);
+ while (g_hash_table_iter_next (&tube_caps_iter, (gpointer *) &service,
+ NULL))
+ {
+ gpointer key, value;
+ if (new_caps == NULL ||
+ !g_hash_table_lookup_extended (new_caps->stream_tube_caps,
+ service, &key, &value))
+ {
+ return TRUE;
+ }
+ }
+ g_hash_table_iter_init (&tube_caps_iter, old_caps->dbus_tube_caps);
+ while (g_hash_table_iter_next (&tube_caps_iter, (gpointer *) &service,
+ NULL))
+ {
+ gpointer key, value;
+ if (new_caps == NULL ||
+ !g_hash_table_lookup_extended (new_caps->dbus_tube_caps,
+ service, &key, &value))
+ {
+ return TRUE;
+ }
+ }
+ }
+
+ if (new_caps != NULL)
+ {
+ g_hash_table_iter_init (&tube_caps_iter, new_caps->stream_tube_caps);
+ while (g_hash_table_iter_next (&tube_caps_iter, (gpointer *) &service,
+ NULL))
+ {
+ gpointer key, value;
+ if (old_caps == NULL ||
+ !g_hash_table_lookup_extended (old_caps->stream_tube_caps,
+ service, &key, &value))
+ {
+ return TRUE;
+ }
+ }
+ g_hash_table_iter_init (&tube_caps_iter, new_caps->dbus_tube_caps);
+ while (g_hash_table_iter_next (&tube_caps_iter, (gpointer *) &service,
+ NULL))
+ {
+ gpointer key, value;
+ if (old_caps == NULL ||
+ !g_hash_table_lookup_extended (old_caps->dbus_tube_caps,
+ service, &key, &value))
+ {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+static void
+salut_private_tubes_factory_add_cap (SalutCapsChannelManager *manager,
+ SalutConnection *conn,
+ TpHandle handle,
+ GHashTable *cap)
+{
+ SalutTubesManager *self = SALUT_TUBES_MANAGER (manager);
+ SalutTubesManagerPrivate *priv = SALUT_TUBES_MANAGER_GET_PRIVATE (self);
+ TpBaseConnection *base = (TpBaseConnection *) conn;
+ GHashTable *per_channel_manager_caps;
+ TubesCapabilities *caps;
+ const gchar *channel_type;
+
+ channel_type = tp_asv_get_string (cap,
+ TP_IFACE_CHANNEL ".ChannelType");
+
+ /* this channel is not for this factory */
+ if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES) &&
+ tp_strdiff (channel_type, SALUT_IFACE_CHANNEL_TYPE_STREAM_TUBE) &&
+ tp_strdiff (channel_type, SALUT_IFACE_CHANNEL_TYPE_DBUS_TUBE))
+ return;
+
+ if (tp_asv_get_uint32 (cap,
+ TP_IFACE_CHANNEL ".TargetHandleType", NULL) != TP_HANDLE_TYPE_CONTACT)
+ return;
+
+ if (handle == base->self_handle)
+ {
+ SalutSelf *salut_self;
+ g_object_get (conn, "self", &salut_self, NULL);
+ per_channel_manager_caps = salut_self->per_channel_manager_caps;
+ }
+ else
+ {
+ SalutContact *contact = salut_contact_manager_get_contact (
+ priv->contact_manager, handle);
+
+ if (contact == NULL)
+ return;
+
+ per_channel_manager_caps = contact->per_channel_manager_caps;
+ }
+
+ if (per_channel_manager_caps == NULL)
+ per_channel_manager_caps = g_hash_table_new (NULL, NULL);
+
+ caps = g_hash_table_lookup (per_channel_manager_caps, manager);
+ if (caps == NULL)
+ {
+ caps = g_new0 (TubesCapabilities, 1);
+ caps->stream_tube_caps = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_free);
+ caps->dbus_tube_caps = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_free);
+ g_hash_table_insert (per_channel_manager_caps, manager, caps);
+ }
+
+ if (!tp_strdiff (channel_type, SALUT_IFACE_CHANNEL_TYPE_STREAM_TUBE))
+ {
+ Feature *feat = g_new0 (Feature, 1);
+ gchar *service = g_strdup (tp_asv_get_string (cap,
+ SALUT_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service"));
+ feat->feature_type = FEATURE_OPTIONAL;
+ feat->ns = g_strdup_printf ("%s/stream/%s", GIBBER_TELEPATHY_NS_TUBES,
+ service);
+ g_hash_table_insert (caps->stream_tube_caps, service, feat);
+ }
+ else if (!tp_strdiff (channel_type, SALUT_IFACE_CHANNEL_TYPE_DBUS_TUBE))
+ {
+ Feature *feat = g_new0 (Feature, 1);
+ gchar *service = g_strdup (tp_asv_get_string (cap,
+ SALUT_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName"));
+ feat->feature_type = FEATURE_OPTIONAL;
+ feat->ns = g_strdup_printf ("%s/dbus/%s", GIBBER_TELEPATHY_NS_TUBES,
+ service);
+ g_hash_table_insert (caps->dbus_tube_caps, service, feat);
+ }
+}
+
+
+static void
+caps_channel_manager_iface_init (gpointer g_iface,
+ gpointer iface_data)
+{
+ SalutCapsChannelManagerIface *iface = g_iface;
+
+ iface->get_contact_caps = salut_private_tubes_factory_get_contact_caps;
+ iface->get_feature_list = salut_private_tubes_factory_get_feature_list;
+ iface->parse_caps = salut_private_tubes_factory_parse_caps;
+ iface->free_caps = salut_private_tubes_factory_free_caps;
+ iface->copy_caps = salut_private_tubes_factory_copy_caps;
+ iface->update_caps = salut_private_tubes_factory_update_caps;
+ iface->caps_diff = salut_private_tubes_factory_caps_diff;
+ iface->add_cap = salut_private_tubes_factory_add_cap;
+}
--
1.5.6.5
More information about the telepathy-commits
mailing list