From c26759d1cda55c8212c9f3c4700f62c646fdd837 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 1 Nov 2010 13:16:32 +0000 Subject: Import GabbleCapsChannelManager and related classes From Gabble, with minimal modifications: - put gabble/namespaces.h in gabble_namespaces.h - include capabilities-set.h instead of gabble/capabilities-set.h - use DEBUG_PRESENCE instead of GABBLE_DEBUG_PRESENCE --- src/Makefile.am | 7 + src/capabilities-set.h | 86 ++++++ src/capabilities.c | 752 +++++++++++++++++++++++++++++++++++++++++++++ src/capabilities.h | 73 +++++ src/caps-channel-manager.c | 126 ++++++++ src/caps-channel-manager.h | 106 +++++++ src/gabble_namespaces.h | 27 ++ src/namespaces.h | 118 +++++++ 8 files changed, 1295 insertions(+) create mode 100644 src/capabilities-set.h create mode 100644 src/capabilities.c create mode 100644 src/capabilities.h create mode 100644 src/caps-channel-manager.c create mode 100644 src/caps-channel-manager.h create mode 100644 src/gabble_namespaces.h create mode 100644 src/namespaces.h diff --git a/src/Makefile.am b/src/Makefile.am index 8e3d0264..294fb23d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,6 +15,13 @@ libexec_PROGRAMS=telepathy-salut noinst_PROGRAMS = write-mgr-file CORE_SOURCES = \ + capabilities.c \ + capabilities.h \ + capabilities-set.h \ + caps-channel-manager.c \ + caps-channel-manager.h \ + gabble_namespaces.h \ + namespaces.h \ salut-capabilities.c \ salut-capabilities.h \ salut-caps-channel-manager.c \ diff --git a/src/capabilities-set.h b/src/capabilities-set.h new file mode 100644 index 00000000..3f215259 --- /dev/null +++ b/src/capabilities-set.h @@ -0,0 +1,86 @@ +/* + * capabilities-set.h - capabilities set API available to telepathy-gabble plugins + * Copyright (C) 2005-2010 Collabora Ltd. + * Copyright (C) 2005-2010 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 as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#ifndef GABBLE_PLUGINS_CAPABILITIES_SET_H +#define GABBLE_PLUGINS_CAPABILITIES_SET_H + +#include + +#include + +G_BEGIN_DECLS + +/** + * GabbleCapabilitySet: + * + * A set of capabilities. + */ +typedef struct _GabbleCapabilitySet GabbleCapabilitySet; + +GabbleCapabilitySet *gabble_capability_set_new (void); +GabbleCapabilitySet *gabble_capability_set_new_from_stanza ( + WockyNode *query_result); +GabbleCapabilitySet *gabble_capability_set_copy ( + const GabbleCapabilitySet *caps); +void gabble_capability_set_update (GabbleCapabilitySet *target, + const GabbleCapabilitySet *source); +void gabble_capability_set_add (GabbleCapabilitySet *caps, + const gchar *cap); +gboolean gabble_capability_set_remove (GabbleCapabilitySet *caps, + const gchar *cap); +void gabble_capability_set_exclude (GabbleCapabilitySet *caps, + const GabbleCapabilitySet *removed); +void gabble_capability_set_intersect (GabbleCapabilitySet *target, + const GabbleCapabilitySet *source); +gint gabble_capability_set_size (const GabbleCapabilitySet *caps); +gboolean gabble_capability_set_has (const GabbleCapabilitySet *caps, + const gchar *cap); +gboolean gabble_capability_set_has_one (const GabbleCapabilitySet *caps, + const GabbleCapabilitySet *alternatives); +gboolean gabble_capability_set_at_least (const GabbleCapabilitySet *caps, + const GabbleCapabilitySet *query); +gboolean gabble_capability_set_equals (const GabbleCapabilitySet *a, + const GabbleCapabilitySet *b); +void gabble_capability_set_clear (GabbleCapabilitySet *caps); +void gabble_capability_set_free (GabbleCapabilitySet *caps); +void gabble_capability_set_foreach (const GabbleCapabilitySet *caps, + GFunc func, gpointer user_data); +gchar *gabble_capability_set_dump (const GabbleCapabilitySet *caps, + const gchar *indent); +gchar *gabble_capability_set_dump_diff (const GabbleCapabilitySet *old_caps, + const GabbleCapabilitySet *new_caps, + const gchar *indent); + +typedef gboolean (*GabbleCapabilitySetPredicate) ( + const GabbleCapabilitySet *set, gconstpointer user_data); +/* These functions are compatible with GabbleCapabilitySetPredicate; + * pass in the desired capabilities as the user_data */ +#define gabble_capability_set_predicate_equals \ + ((GabbleCapabilitySetPredicate) gabble_capability_set_equals) +#define gabble_capability_set_predicate_has \ + ((GabbleCapabilitySetPredicate) gabble_capability_set_has) +#define gabble_capability_set_predicate_has_one \ + ((GabbleCapabilitySetPredicate) gabble_capability_set_has_one) +#define gabble_capability_set_predicate_at_least \ + ((GabbleCapabilitySetPredicate) gabble_capability_set_at_least) + +G_END_DECLS + +#endif diff --git a/src/capabilities.c b/src/capabilities.c new file mode 100644 index 00000000..07e76d82 --- /dev/null +++ b/src/capabilities.c @@ -0,0 +1,752 @@ +/* + * capabilities.c - Connection.Interface.Capabilities constants and utilities + * Copyright (C) 2005 Collabora Ltd. + * Copyright (C) 2005 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 as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 "config.h" +#include "capabilities.h" + +#include +#include + +#include +#include +#include +#include +#include + +#define DEBUG_FLAG DEBUG_PRESENCE +#include "debug.h" +#include "namespaces.h" + +typedef struct _Feature Feature; + +struct _Feature +{ + enum { + FEATURE_FIXED, + FEATURE_OPTIONAL, + FEATURE_OLPC + } feature_type; + gchar *ns; +}; + +static const Feature self_advertised_features[] = +{ + { FEATURE_FIXED, NS_GOOGLE_FEAT_SESSION }, + { FEATURE_FIXED, NS_JINGLE_TRANSPORT_RAWUDP }, + { FEATURE_FIXED, NS_JINGLE015 }, + { FEATURE_FIXED, NS_JINGLE032 }, + { FEATURE_FIXED, NS_CHAT_STATES }, + { FEATURE_FIXED, NS_NICK }, + { FEATURE_FIXED, NS_NICK "+notify" }, + { FEATURE_FIXED, NS_SI }, + { FEATURE_FIXED, NS_IBB }, + { FEATURE_FIXED, NS_TUBES }, + { FEATURE_FIXED, NS_BYTESTREAMS }, + { FEATURE_OPTIONAL, NS_FILE_TRANSFER }, + + { FEATURE_OPTIONAL, NS_GOOGLE_TRANSPORT_P2P }, + { FEATURE_OPTIONAL, NS_JINGLE_TRANSPORT_ICEUDP }, + + { FEATURE_OPTIONAL, NS_GOOGLE_FEAT_SHARE }, + { FEATURE_OPTIONAL, NS_GOOGLE_FEAT_VOICE }, + { FEATURE_OPTIONAL, NS_GOOGLE_FEAT_VIDEO }, + { FEATURE_OPTIONAL, NS_JINGLE_DESCRIPTION_AUDIO }, + { FEATURE_OPTIONAL, NS_JINGLE_DESCRIPTION_VIDEO }, + { FEATURE_OPTIONAL, NS_JINGLE_RTP }, + { FEATURE_OPTIONAL, NS_JINGLE_RTP_AUDIO }, + { FEATURE_OPTIONAL, NS_JINGLE_RTP_VIDEO }, + + { FEATURE_OLPC, NS_OLPC_BUDDY_PROPS "+notify" }, + { FEATURE_OLPC, NS_OLPC_ACTIVITIES "+notify" }, + { FEATURE_OLPC, NS_OLPC_CURRENT_ACTIVITY "+notify" }, + { FEATURE_OLPC, NS_OLPC_ACTIVITY_PROPS "+notify" }, + + { FEATURE_OPTIONAL, NS_GEOLOC "+notify" }, + + { 0, NULL } +}; + +static const Feature quirks[] = { + { 0, QUIRK_OMITS_CONTENT_CREATORS }, + { 0, NULL } +}; + +static GabbleCapabilitySet *legacy_caps = NULL; +static GabbleCapabilitySet *share_v1_caps = NULL; +static GabbleCapabilitySet *voice_v1_caps = NULL; +static GabbleCapabilitySet *video_v1_caps = NULL; +static GabbleCapabilitySet *any_audio_caps = NULL; +static GabbleCapabilitySet *any_video_caps = NULL; +static GabbleCapabilitySet *any_audio_video_caps = NULL; +static GabbleCapabilitySet *any_google_av_caps = NULL; +static GabbleCapabilitySet *any_jingle_av_caps = NULL; +static GabbleCapabilitySet *any_transport_caps = NULL; +static GabbleCapabilitySet *fixed_caps = NULL; +static GabbleCapabilitySet *geoloc_caps = NULL; +static GabbleCapabilitySet *olpc_caps = NULL; + +const GabbleCapabilitySet * +gabble_capabilities_get_legacy (void) +{ + return legacy_caps; +} + +const GabbleCapabilitySet * +gabble_capabilities_get_bundle_share_v1 (void) +{ + return share_v1_caps; +} + +const GabbleCapabilitySet * +gabble_capabilities_get_bundle_voice_v1 (void) +{ + return voice_v1_caps; +} + +const GabbleCapabilitySet * +gabble_capabilities_get_bundle_video_v1 (void) +{ + return video_v1_caps; +} + +const GabbleCapabilitySet * +gabble_capabilities_get_any_audio (void) +{ + return any_audio_caps; +} + +const GabbleCapabilitySet * +gabble_capabilities_get_any_video (void) +{ + return any_video_caps; +} + +const GabbleCapabilitySet * +gabble_capabilities_get_any_audio_video (void) +{ + return any_audio_video_caps; +} + +const GabbleCapabilitySet * +gabble_capabilities_get_any_google_av (void) +{ + return any_google_av_caps; +} + +const GabbleCapabilitySet * +gabble_capabilities_get_any_jingle_av (void) +{ + return any_jingle_av_caps; +} + +const GabbleCapabilitySet * +gabble_capabilities_get_any_transport (void) +{ + return any_transport_caps; +} + +const GabbleCapabilitySet * +gabble_capabilities_get_fixed_caps (void) +{ + return fixed_caps; +} + +const GabbleCapabilitySet * +gabble_capabilities_get_geoloc_notify (void) +{ + return geoloc_caps; +} + +const GabbleCapabilitySet * +gabble_capabilities_get_olpc_notify (void) +{ + return olpc_caps; +} + +static gboolean +omits_content_creators (WockyNode *identity) +{ + const gchar *name, *suffix; + gchar *end; + int ver; + + name = wocky_node_get_attribute (identity, "name"); + + if (name == NULL) + return FALSE; + +#define PREFIX "Telepathy Gabble 0.7." + + if (!g_str_has_prefix (name, PREFIX)) + return FALSE; + + suffix = name + strlen (PREFIX); + ver = strtol (suffix, &end, 10); + + if (*end != '\0') + return FALSE; + + /* Gabble versions since 0.7.16 did not send the creator='' attribute for + * contents. The bug is fixed in 0.7.29. + */ + if (ver >= 16 && ver < 29) + { + DEBUG ("contact is using '%s' which omits 'creator'", name); + return TRUE; + } + else + { + return FALSE; + } +} + +static gsize feature_handles_refcount = 0; +/* The handles in this repository are not really handles in the tp-spec sense + * of the word; we're just using it as a convenient implementation of a + * refcounted string pool. Their string values are either XMPP namespaces, + * or "quirk" pseudo-namespaces starting with QUIRK_PREFIX_CHAR (like + * QUIRK_OMITS_CONTENT_CREATORS). */ +static TpHandleRepoIface *feature_handles = NULL; + +void +gabble_capabilities_init (gpointer conn) +{ + DEBUG ("%p", conn); + + if (feature_handles_refcount++ == 0) + { + const Feature *feat; + + g_assert (feature_handles == NULL); + /* TpDynamicHandleRepo wants a handle type, which isn't relevant here + * (we're just using it as a string pool). Use an arbitrary handle type + * to shut it up. */ + feature_handles = tp_dynamic_handle_repo_new (TP_HANDLE_TYPE_CONTACT, + NULL, NULL); + + /* make the pre-cooked bundles */ + + legacy_caps = gabble_capability_set_new (); + + for (feat = self_advertised_features; feat->ns != NULL; feat++) + { + gabble_capability_set_add (legacy_caps, feat->ns); + } + + share_v1_caps = gabble_capability_set_new (); + gabble_capability_set_add (share_v1_caps, NS_GOOGLE_FEAT_SHARE); + + voice_v1_caps = gabble_capability_set_new (); + gabble_capability_set_add (voice_v1_caps, NS_GOOGLE_FEAT_VOICE); + + video_v1_caps = gabble_capability_set_new (); + gabble_capability_set_add (video_v1_caps, NS_GOOGLE_FEAT_VIDEO); + + any_audio_caps = gabble_capability_set_new (); + gabble_capability_set_add (any_audio_caps, NS_JINGLE_RTP_AUDIO); + gabble_capability_set_add (any_audio_caps, NS_JINGLE_DESCRIPTION_AUDIO); + gabble_capability_set_add (any_audio_caps, NS_GOOGLE_FEAT_VOICE); + + any_video_caps = gabble_capability_set_new (); + gabble_capability_set_add (any_video_caps, NS_JINGLE_RTP_VIDEO); + gabble_capability_set_add (any_video_caps, NS_JINGLE_DESCRIPTION_VIDEO); + gabble_capability_set_add (any_video_caps, NS_GOOGLE_FEAT_VIDEO); + + any_audio_video_caps = gabble_capability_set_copy (any_audio_caps); + gabble_capability_set_update (any_audio_video_caps, any_video_caps); + + any_google_av_caps = gabble_capability_set_new (); + gabble_capability_set_add (any_google_av_caps, NS_GOOGLE_FEAT_VOICE); + gabble_capability_set_add (any_google_av_caps, NS_GOOGLE_FEAT_VIDEO); + + any_jingle_av_caps = gabble_capability_set_copy (any_audio_caps); + gabble_capability_set_update (any_jingle_av_caps, any_video_caps); + gabble_capability_set_exclude (any_jingle_av_caps, any_google_av_caps); + + any_transport_caps = gabble_capability_set_new (); + gabble_capability_set_add (any_transport_caps, NS_GOOGLE_TRANSPORT_P2P); + gabble_capability_set_add (any_transport_caps, NS_JINGLE_TRANSPORT_ICEUDP); + gabble_capability_set_add (any_transport_caps, NS_JINGLE_TRANSPORT_RAWUDP); + + fixed_caps = gabble_capability_set_new (); + + for (feat = self_advertised_features; feat->ns != NULL; feat++) + { + if (feat->feature_type == FEATURE_FIXED) + gabble_capability_set_add (fixed_caps, feat->ns); + } + + geoloc_caps = gabble_capability_set_new (); + gabble_capability_set_add (geoloc_caps, NS_GEOLOC "+notify"); + + olpc_caps = gabble_capability_set_new (); + + for (feat = self_advertised_features; feat->ns != NULL; feat++) + { + if (feat->feature_type == FEATURE_OLPC) + gabble_capability_set_add (olpc_caps, feat->ns); + } + } + + g_assert (feature_handles != NULL); +} + +void +gabble_capabilities_finalize (gpointer conn) +{ + DEBUG ("%p", conn); + + g_assert (feature_handles_refcount > 0); + + if (--feature_handles_refcount == 0) + { + gabble_capability_set_free (legacy_caps); + gabble_capability_set_free (share_v1_caps); + gabble_capability_set_free (voice_v1_caps); + gabble_capability_set_free (video_v1_caps); + gabble_capability_set_free (any_audio_caps); + gabble_capability_set_free (any_video_caps); + gabble_capability_set_free (any_audio_video_caps); + gabble_capability_set_free (any_google_av_caps); + gabble_capability_set_free (any_jingle_av_caps); + gabble_capability_set_free (any_transport_caps); + gabble_capability_set_free (fixed_caps); + gabble_capability_set_free (geoloc_caps); + gabble_capability_set_free (olpc_caps); + + legacy_caps = NULL; + share_v1_caps = NULL; + voice_v1_caps = NULL; + video_v1_caps = NULL; + any_audio_caps = NULL; + any_video_caps = NULL; + any_audio_video_caps = NULL; + any_google_av_caps = NULL; + any_jingle_av_caps = NULL; + any_transport_caps = NULL; + fixed_caps = NULL; + geoloc_caps = NULL; + olpc_caps = NULL; + + tp_clear_object (&feature_handles); + } +} + +struct _GabbleCapabilitySet { + TpHandleSet *handles; +}; + +GabbleCapabilitySet * +gabble_capability_set_new (void) +{ + GabbleCapabilitySet *ret = g_slice_new0 (GabbleCapabilitySet); + + g_assert (feature_handles != NULL); + ret->handles = tp_handle_set_new (feature_handles); + return ret; +} + +GabbleCapabilitySet * +gabble_capability_set_new_from_stanza (WockyNode *query_result) +{ + GabbleCapabilitySet *ret; + const gchar *var; + GSList *ni; + + g_return_val_if_fail (query_result != NULL, NULL); + + ret = gabble_capability_set_new (); + + for (ni = query_result->children; ni != NULL; ni = g_slist_next (ni)) + { + WockyNode *child = ni->data; + + if (!tp_strdiff (child->name, "identity")) + { + if (omits_content_creators (child)) + gabble_capability_set_add (ret, QUIRK_OMITS_CONTENT_CREATORS); + + continue; + } + + if (tp_strdiff (child->name, "feature")) + continue; + + var = wocky_node_get_attribute (child, "var"); + + if (NULL == var) + continue; + + if (G_UNLIKELY (var[0] == QUIRK_PREFIX_CHAR)) + { + /* I think not! (It's not allowed in XML...) */ + continue; + } + + /* TODO: only store namespaces we understand. */ + gabble_capability_set_add (ret, var); + } + + return ret; +} + +GabbleCapabilitySet * +gabble_capability_set_copy (const GabbleCapabilitySet *caps) +{ + GabbleCapabilitySet *ret; + + g_return_val_if_fail (caps != NULL, NULL); + + ret = gabble_capability_set_new (); + + gabble_capability_set_update (ret, caps); + + return ret; +} + +void +gabble_capability_set_update (GabbleCapabilitySet *target, + const GabbleCapabilitySet *source) +{ + TpIntSet *ret; + g_return_if_fail (target != NULL); + g_return_if_fail (source != NULL); + + ret = tp_handle_set_update (target->handles, + tp_handle_set_peek (source->handles)); + + tp_intset_destroy (ret); +} + +typedef struct { + GSList *deleted; + TpHandleSet *intersect_with; +} IntersectHelper; + +static void +intersect_helper (TpHandleSet *unused G_GNUC_UNUSED, + TpHandle handle, + gpointer p) +{ + IntersectHelper *data = p; + + if (!tp_handle_set_is_member (data->intersect_with, handle)) + data->deleted = g_slist_prepend (data->deleted, GUINT_TO_POINTER (handle)); +} + +void +gabble_capability_set_intersect (GabbleCapabilitySet *target, + const GabbleCapabilitySet *source) +{ + IntersectHelper data = { NULL, NULL }; + + g_return_if_fail (target != NULL); + g_return_if_fail (source != NULL); + + if (target == source) + return; + + data.intersect_with = source->handles; + + tp_handle_set_foreach (target->handles, intersect_helper, &data); + + while (data.deleted != NULL) + { + DEBUG ("dropping %s", tp_handle_inspect (feature_handles, + GPOINTER_TO_UINT (data.deleted->data))); + tp_handle_set_remove (target->handles, + GPOINTER_TO_UINT (data.deleted->data)); + data.deleted = g_slist_delete_link (data.deleted, data.deleted); + } +} + +static void +remove_from_set (TpHandleSet *unused G_GNUC_UNUSED, + TpHandle handle, + gpointer handles) +{ + tp_handle_set_remove (handles, handle); +} + +void +gabble_capability_set_exclude (GabbleCapabilitySet *caps, + const GabbleCapabilitySet *removed) +{ + g_return_if_fail (caps != NULL); + g_return_if_fail (removed != NULL); + + if (caps == removed) + { + gabble_capability_set_clear (caps); + return; + } + + tp_handle_set_foreach (removed->handles, remove_from_set, caps->handles); +} + +void +gabble_capability_set_add (GabbleCapabilitySet *caps, + const gchar *cap) +{ + TpHandle handle; + + g_return_if_fail (caps != NULL); + g_return_if_fail (cap != NULL); + + handle = tp_handle_ensure (feature_handles, cap, NULL, NULL); + + tp_handle_set_add (caps->handles, handle); + tp_handle_unref (feature_handles, handle); +} + +gboolean +gabble_capability_set_remove (GabbleCapabilitySet *caps, + const gchar *cap) +{ + TpHandle handle; + + g_return_val_if_fail (caps != NULL, FALSE); + g_return_val_if_fail (cap != NULL, FALSE); + + handle = tp_handle_lookup (feature_handles, cap, NULL, NULL); + + if (handle == 0) + return FALSE; + + return tp_handle_set_remove (caps->handles, handle); +} + +void +gabble_capability_set_clear (GabbleCapabilitySet *caps) +{ + g_return_if_fail (caps != NULL); + + /* There is no tp_handle_set_clear, so do the next best thing */ + tp_handle_set_destroy (caps->handles); + caps->handles = tp_handle_set_new (feature_handles); +} + +void +gabble_capability_set_free (GabbleCapabilitySet *caps) +{ + g_return_if_fail (caps != NULL); + + tp_handle_set_destroy (caps->handles); + g_slice_free (GabbleCapabilitySet, caps); +} + +gint +gabble_capability_set_size (const GabbleCapabilitySet *caps) +{ + g_return_val_if_fail (caps != NULL, 0); + return tp_handle_set_size (caps->handles); +} + +/* By design, this function can be used as a GabbleCapabilitySetPredicate */ +gboolean +gabble_capability_set_has (const GabbleCapabilitySet *caps, + const gchar *cap) +{ + TpHandle handle; + + g_return_val_if_fail (caps != NULL, FALSE); + g_return_val_if_fail (cap != NULL, FALSE); + + handle = tp_handle_lookup (feature_handles, cap, NULL, NULL); + + if (handle == 0) + { + /* nobody in the whole CM has this capability */ + return FALSE; + } + + return tp_handle_set_is_member (caps->handles, handle); +} + +/* By design, this function can be used as a GabbleCapabilitySetPredicate */ +gboolean +gabble_capability_set_has_one (const GabbleCapabilitySet *caps, + const GabbleCapabilitySet *alternatives) +{ + TpIntSetIter iter; + + g_return_val_if_fail (caps != NULL, FALSE); + g_return_val_if_fail (alternatives != NULL, FALSE); + + tp_intset_iter_init (&iter, tp_handle_set_peek (alternatives->handles)); + + while (tp_intset_iter_next (&iter)) + { + if (tp_handle_set_is_member (caps->handles, iter.element)) + { + return TRUE; + } + } + + return FALSE; +} + +/* By design, this function can be used as a GabbleCapabilitySetPredicate */ +gboolean +gabble_capability_set_at_least (const GabbleCapabilitySet *caps, + const GabbleCapabilitySet *query) +{ + TpIntSetIter iter; + + g_return_val_if_fail (caps != NULL, FALSE); + g_return_val_if_fail (query != NULL, FALSE); + + tp_intset_iter_init (&iter, tp_handle_set_peek (query->handles)); + + while (tp_intset_iter_next (&iter)) + { + if (!tp_handle_set_is_member (caps->handles, iter.element)) + { + return FALSE; + } + } + + return TRUE; +} + +gboolean +gabble_capability_set_equals (const GabbleCapabilitySet *a, + const GabbleCapabilitySet *b) +{ + g_return_val_if_fail (a != NULL, FALSE); + g_return_val_if_fail (b != NULL, FALSE); + + return tp_intset_is_equal (tp_handle_set_peek (a->handles), + tp_handle_set_peek (b->handles)); +} + +/* Does not iterate over quirks, only real features. */ +void +gabble_capability_set_foreach (const GabbleCapabilitySet *caps, + GFunc func, gpointer user_data) +{ + TpIntSetIter iter; + + g_return_if_fail (caps != NULL); + g_return_if_fail (func != NULL); + + tp_intset_iter_init (&iter, tp_handle_set_peek (caps->handles)); + + while (tp_intset_iter_next (&iter)) + { + const gchar *var = tp_handle_inspect (feature_handles, iter.element); + + g_return_if_fail (var != NULL); + + if (var[0] != QUIRK_PREFIX_CHAR) + func ((gchar *) var, user_data); + } +} + +static void +append_intset (GString *ret, + const TpIntSet *cap_ints, + const gchar *indent) +{ + TpIntSetFastIter iter; + guint element; + + tp_intset_fast_iter_init (&iter, cap_ints); + + while (tp_intset_fast_iter_next (&iter, &element)) + { + const gchar *var = tp_handle_inspect (feature_handles, element); + + g_return_if_fail (var != NULL); + + if (var[0] == QUIRK_PREFIX_CHAR) + { + g_string_append_printf (ret, "%sQuirk: %s\n", indent, var + 1); + } + else + { + g_string_append_printf (ret, "%sFeature: %s\n", indent, var); + } + } +} + +gchar * +gabble_capability_set_dump (const GabbleCapabilitySet *caps, + const gchar *indent) +{ + GString *ret; + + g_return_val_if_fail (caps != NULL, NULL); + + if (indent == NULL) + indent = ""; + + ret = g_string_new (indent); + g_string_append (ret, "--begin--\n"); + append_intset (ret, tp_handle_set_peek (caps->handles), indent); + g_string_append (ret, indent); + g_string_append (ret, "--end--\n"); + return g_string_free (ret, FALSE); +} + +gchar * +gabble_capability_set_dump_diff (const GabbleCapabilitySet *old_caps, + const GabbleCapabilitySet *new_caps, + const gchar *indent) +{ + TpIntSet *old_ints, *new_ints, *rem, *add; + GString *ret; + + g_return_val_if_fail (old_caps != NULL, NULL); + g_return_val_if_fail (new_caps != NULL, NULL); + + old_ints = tp_handle_set_peek (old_caps->handles); + new_ints = tp_handle_set_peek (new_caps->handles); + + if (tp_intset_is_equal (old_ints, new_ints)) + return g_strdup_printf ("%s--no change--", indent); + + rem = tp_intset_difference (old_ints, new_ints); + add = tp_intset_difference (new_ints, old_ints); + + ret = g_string_new (""); + + if (!tp_intset_is_empty (rem)) + { + g_string_append (ret, indent); + g_string_append (ret, "--removed--\n"); + append_intset (ret, rem, indent); + } + + if (!tp_intset_is_empty (add)) + { + g_string_append (ret, indent); + g_string_append (ret, "--added--\n"); + append_intset (ret, add, indent); + } + + g_string_append (ret, indent); + g_string_append (ret, "--end--"); + + tp_intset_destroy (add); + tp_intset_destroy (rem); + + return g_string_free (ret, FALSE); +} diff --git a/src/capabilities.h b/src/capabilities.h new file mode 100644 index 00000000..52b4b0f6 --- /dev/null +++ b/src/capabilities.h @@ -0,0 +1,73 @@ +/* + * capabilities.h - Connection.Interface.Capabilities constants and utilities + * Copyright (C) 2005 Collabora Ltd. + * Copyright (C) 2005 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 as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#ifndef __GABBLE_CAPABILITIES__H__ +#define __GABBLE_CAPABILITIES__H__ + +#include + +#include "capabilities-set.h" + +/* Pseudo-capabilities for buggy or strange implementations, represented as + * strings starting with a character not allowed in XML (the ASCII beep :-) */ +#define QUIRK_PREFIX_CHAR '\x07' +#define QUIRK_PREFIX "\x07" +/* Gabble 0.7.x with 16 <= x < 29 omits @creator on */ +#define QUIRK_OMITS_CONTENT_CREATORS "\x07omits-content-creators" +/* The Google Webmail client doesn't support some features */ +#define QUIRK_GOOGLE_WEBMAIL_CLIENT "\x07google-webmail-client" + +/* Some useful capability sets for Jingle etc. */ +const GabbleCapabilitySet *gabble_capabilities_get_legacy (void); +const GabbleCapabilitySet *gabble_capabilities_get_any_audio (void); +const GabbleCapabilitySet *gabble_capabilities_get_any_video (void); +const GabbleCapabilitySet *gabble_capabilities_get_any_audio_video (void); +const GabbleCapabilitySet *gabble_capabilities_get_any_google_av (void); +const GabbleCapabilitySet *gabble_capabilities_get_any_jingle_av (void); +const GabbleCapabilitySet *gabble_capabilities_get_any_transport (void); +const GabbleCapabilitySet *gabble_capabilities_get_geoloc_notify (void); +const GabbleCapabilitySet *gabble_capabilities_get_olpc_notify (void); + +/* XEP-0115 version 1.3: + * + * "The names of the feature bundles MUST NOT be used for semantic purposes: + * they are merely opaque identifiers" + * + * However, some old Jabber clients (e.g. Gabble 0.2) and various Google + * clients require the bundle names "voice-v1" and "video-v1". We keep these + * names for compatibility. + */ +#define BUNDLE_SHARE_V1 "share-v1" +#define BUNDLE_VOICE_V1 "voice-v1" +#define BUNDLE_VIDEO_V1 "video-v1" +#define BUNDLE_PMUC_V1 "pmuc-v1" + +const GabbleCapabilitySet *gabble_capabilities_get_bundle_share_v1 (void); +const GabbleCapabilitySet *gabble_capabilities_get_bundle_voice_v1 (void); +const GabbleCapabilitySet *gabble_capabilities_get_bundle_video_v1 (void); + +/* Return the capabilities we always have */ +const GabbleCapabilitySet *gabble_capabilities_get_fixed_caps (void); + +void gabble_capabilities_init (gpointer conn); +void gabble_capabilities_finalize (gpointer conn); + +#endif /* __GABBLE_CAPABILITIES__H__ */ + diff --git a/src/caps-channel-manager.c b/src/caps-channel-manager.c new file mode 100644 index 00000000..746a828f --- /dev/null +++ b/src/caps-channel-manager.c @@ -0,0 +1,126 @@ +/* + * caps-channel-manager.c - interface holding capabilities functions for + * channel managers + * + * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2008 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 as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 "config.h" +#include "caps-channel-manager.h" + +#include +#include + + +#define DEBUG_FLAG DEBUG_PRESENCE +#include "debug.h" + +GType +gabble_caps_channel_manager_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) + { + static const GTypeInfo info = { + sizeof (GabbleCapsChannelManagerIface), + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL /* instance_init */ + }; + + type = g_type_register_static (G_TYPE_INTERFACE, + "GabbleCapsChannelManager", &info, 0); + + g_type_interface_add_prerequisite (type, TP_TYPE_CHANNEL_MANAGER); + } + + return type; +} + +/* Virtual-method wrappers */ +void +gabble_caps_channel_manager_reset_capabilities ( + GabbleCapsChannelManager *caps_manager) +{ + GabbleCapsChannelManagerIface *iface = + GABBLE_CAPS_CHANNEL_MANAGER_GET_INTERFACE (caps_manager); + GabbleCapsChannelManagerResetCapsFunc method = iface->reset_caps; + + if (method != NULL) + { + method (caps_manager); + } + /* ... else assume there is no need to reset the caps */ +} + +void +gabble_caps_channel_manager_get_contact_capabilities ( + GabbleCapsChannelManager *caps_manager, + TpHandle handle, + const GabbleCapabilitySet *caps, + GPtrArray *arr) +{ + GabbleCapsChannelManagerIface *iface = + GABBLE_CAPS_CHANNEL_MANAGER_GET_INTERFACE (caps_manager); + GabbleCapsChannelManagerGetContactCapsFunc method = iface->get_contact_caps; + + if (method != NULL) + { + method (caps_manager, handle, caps, arr); + } + /* ... else assume there is not caps for this kind of channels */ +} + +/** + * gabble_caps_channel_manager_represent_client: + * @self: a channel manager + * @client_name: the name of the client, for any debug messages + * @filters: the channel classes accepted by the client, as an array of + * GHashTable with string keys and GValue values + * @cap_tokens: the handler capability tokens supported by the client + * @cap_set: a set into which to merge additional XMPP capabilities + * + * Convert the capabilities of a Telepathy client into XMPP capabilities to be + * advertised. + * + * (The actual XMPP capabilities advertised will be the union of the XMPP + * capabilities of every installed client.) + */ +void +gabble_caps_channel_manager_represent_client ( + GabbleCapsChannelManager *caps_manager, + const gchar *client_name, + const GPtrArray *filters, + const gchar * const *cap_tokens, + GabbleCapabilitySet *cap_set) +{ + GabbleCapsChannelManagerIface *iface = + GABBLE_CAPS_CHANNEL_MANAGER_GET_INTERFACE (caps_manager); + GabbleCapsChannelManagerRepresentClientFunc method = iface->represent_client; + + if (method != NULL) + { + method (caps_manager, client_name, filters, cap_tokens, cap_set); + } +} diff --git a/src/caps-channel-manager.h b/src/caps-channel-manager.h new file mode 100644 index 00000000..e5623bbf --- /dev/null +++ b/src/caps-channel-manager.h @@ -0,0 +1,106 @@ +/* + * caps-channel-manager.h - interface holding capabilities functions for + * channel managers + * + * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2008 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 as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#ifndef GABBLE_CAPS_CHANNEL_MANAGER_H +#define GABBLE_CAPS_CHANNEL_MANAGER_H + +#include +#include +#include + +#include "capabilities.h" + +G_BEGIN_DECLS + +#define GABBLE_TYPE_CAPS_CHANNEL_MANAGER \ + (gabble_caps_channel_manager_get_type ()) + +#define GABBLE_CAPS_CHANNEL_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GABBLE_TYPE_CAPS_CHANNEL_MANAGER, GabbleCapsChannelManager)) + +#define GABBLE_IS_CAPS_CHANNEL_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + GABBLE_TYPE_CAPS_CHANNEL_MANAGER)) + +#define GABBLE_CAPS_CHANNEL_MANAGER_GET_INTERFACE(obj) \ + (G_TYPE_INSTANCE_GET_INTERFACE ((obj), \ + GABBLE_TYPE_CAPS_CHANNEL_MANAGER, GabbleCapsChannelManagerIface)) + +typedef struct _GabbleCapsChannelManager GabbleCapsChannelManager; +typedef struct _GabbleCapsChannelManagerIface GabbleCapsChannelManagerIface; + + +/* virtual methods */ + +typedef void (*GabbleCapsChannelManagerGetContactCapsFunc) ( + GabbleCapsChannelManager *manager, + TpHandle handle, + const GabbleCapabilitySet *caps, + GPtrArray *arr); + +typedef void (*GabbleCapsChannelManagerResetCapsFunc) ( + GabbleCapsChannelManager *manager); + +typedef void (*GabbleCapsChannelManagerAddCapFunc) ( + GabbleCapsChannelManager *manager, + GHashTable *cap, + GabbleCapabilitySet *cap_set); + +typedef void (*GabbleCapsChannelManagerRepresentClientFunc) ( + GabbleCapsChannelManager *manager, + const gchar *client_name, + const GPtrArray *filters, + const gchar * const *cap_tokens, + GabbleCapabilitySet *cap_set); + +void gabble_caps_channel_manager_reset_capabilities ( + GabbleCapsChannelManager *caps_manager); + +void gabble_caps_channel_manager_get_contact_capabilities ( + GabbleCapsChannelManager *caps_manager, + TpHandle handle, + const GabbleCapabilitySet *caps, + GPtrArray *arr); + +void gabble_caps_channel_manager_represent_client ( + GabbleCapsChannelManager *caps_manager, + const gchar *client_name, + const GPtrArray *filters, + const gchar * const *cap_tokens, + GabbleCapabilitySet *cap_set); + +struct _GabbleCapsChannelManagerIface { + GTypeInterface parent; + + GabbleCapsChannelManagerResetCapsFunc reset_caps; + GabbleCapsChannelManagerGetContactCapsFunc get_contact_caps; + GabbleCapsChannelManagerRepresentClientFunc represent_client; + + gpointer priv; +}; + +GType gabble_caps_channel_manager_get_type (void); + +G_END_DECLS + +#endif diff --git a/src/gabble_namespaces.h b/src/gabble_namespaces.h new file mode 100644 index 00000000..d8e145f2 --- /dev/null +++ b/src/gabble_namespaces.h @@ -0,0 +1,27 @@ +/* + * namespaces.h — namespace constants definitions that can be used by telepathy-gabble plugins + * Copyright © 2009 Collabora Ltd. + * Copyright © 2009 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 as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#ifndef GABBLE_PLUGINS_NAMESPACES_H +#define GABBLE_PLUGINS_NAMESPACES_H + +#define NS_CAPS "http://jabber.org/protocol/caps" +#define NS_GABBLE_CAPS "http://telepathy.freedesktop.org/caps" + +#endif diff --git a/src/namespaces.h b/src/namespaces.h new file mode 100644 index 00000000..e0d2834b --- /dev/null +++ b/src/namespaces.h @@ -0,0 +1,118 @@ +/* + * namespaces.h - XMPP namespace constants + * Copyright (C) 2005 Collabora Ltd. + * Copyright (C) 2005 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 as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#ifndef __GABBLE_NAMESPACES__H__ +#define __GABBLE_NAMESPACES__H__ + +#include "gabble_namespaces.h" +#include + +#define NS_AMP WOCKY_XMPP_NS_AMP +#define NS_BYTESTREAMS "http://jabber.org/protocol/bytestreams" +#define NS_CHAT_STATES WOCKY_NS_CHATSTATE +#define NS_FEATURENEG WOCKY_XMPP_NS_FEATURENEG +#define NS_FILE_TRANSFER "http://jabber.org/protocol/si/profile/file-transfer" +#define NS_GOOGLE_CAPS "http://www.google.com/xmpp/client/caps" +#define NS_GOOGLE_FEAT_SESSION "http://www.google.com/xmpp/protocol/session" +#define NS_GOOGLE_FEAT_SHARE "http://google.com/xmpp/protocol/share/v1" +#define NS_GOOGLE_FEAT_VOICE "http://www.google.com/xmpp/protocol/voice/v1" +#define NS_GOOGLE_FEAT_VIDEO "http://www.google.com/xmpp/protocol/video/v1" +#define NS_GOOGLE_JINGLE_INFO "google:jingleinfo" +#define NS_GOOGLE_ROSTER "google:roster" +#define NS_GOOGLE_QUEUE "google:queue" +#define NS_IBB WOCKY_XMPP_NS_IBB + +/* Namespaces for XEP-0166 draft v0.15, the most capable Jingle dialect + * supported by telepathy-gabble < 0.7.16, including the versions shipped with + * Maemo Chinook and Diablo. + */ +#define NS_JINGLE015 "http://jabber.org/protocol/jingle" + +/* RTP audio capability in Jingle v0.15 (obsoleted by NS_JINGLE_RTP) */ +#define NS_JINGLE_DESCRIPTION_AUDIO \ + "http://jabber.org/protocol/jingle/description/audio" +/* RTP video capability in Jingle v0.15 (obsoleted by NS_JINGLE_RTP) */ +#define NS_JINGLE_DESCRIPTION_VIDEO \ + "http://jabber.org/protocol/jingle/description/video" + +/* XEP-0166 draft */ +#define NS_JINGLE032 "urn:xmpp:jingle:1" +#define NS_JINGLE_ERRORS "urn:xmpp:jingle:errors:1" + +/* XEP-0167 (Jingle RTP) */ +#define NS_JINGLE_RTP "urn:xmpp:jingle:apps:rtp:1" +#define NS_JINGLE_RTP_ERRORS "urn:xmpp:jingle:apps:rtp:errors:1" +#define NS_JINGLE_RTP_INFO "urn:xmpp:jingle:apps:rtp:info:1" +#define NS_JINGLE_RTP_AUDIO "urn:xmpp:jingle:apps:rtp:audio" +#define NS_JINGLE_RTP_VIDEO "urn:xmpp:jingle:apps:rtp:video" + +/* Google's Jingle dialect */ +#define NS_GOOGLE_SESSION "http://www.google.com/session" +/* Audio capability in Google Jingle dialect */ +#define NS_GOOGLE_SESSION_PHONE "http://www.google.com/session/phone" +/* Video capability in Google's Jingle dialect */ +#define NS_GOOGLE_SESSION_VIDEO "http://www.google.com/session/video" +/* File transfer capability in Google's Jingle dialect */ +#define NS_GOOGLE_SESSION_SHARE "http://www.google.com/session/share" + +/* google-p2p transport */ +#define NS_GOOGLE_TRANSPORT_P2P "http://www.google.com/transport/p2p" +/* Jingle RAW-UDP transport */ +#define NS_JINGLE_TRANSPORT_RAWUDP "urn:xmpp:jingle:transports:raw-udp:1" +/* Jingle ICE-UDP transport */ +#define NS_JINGLE_TRANSPORT_ICEUDP "urn:xmpp:jingle:transports:ice-udp:1" + +#define NS_MUC "http://jabber.org/protocol/muc" +#define NS_MUC_BYTESTREAM "http://telepathy.freedesktop.org/xmpp/protocol/muc-bytestream" +#define NS_MUC_USER "http://jabber.org/protocol/muc#user" +#define NS_MUC_ADMIN "http://jabber.org/protocol/muc#admin" +#define NS_MUC_OWNER "http://jabber.org/protocol/muc#owner" +#define NS_NICK "http://jabber.org/protocol/nick" +#define NS_OOB "jabber:iq:oob" +#define NS_OLPC_BUDDY_PROPS "http://laptop.org/xmpp/buddy-properties" +#define NS_OLPC_ACTIVITIES "http://laptop.org/xmpp/activities" +#define NS_OLPC_CURRENT_ACTIVITY "http://laptop.org/xmpp/current-activity" +#define NS_OLPC_ACTIVITY_PROPS "http://laptop.org/xmpp/activity-properties" +#define NS_OLPC_BUDDY "http://laptop.org/xmpp/buddy" +#define NS_OLPC_ACTIVITY "http://laptop.org/xmpp/activity" +#define NS_PUBSUB "http://jabber.org/protocol/pubsub" +#define NS_PRESENCE_INVISIBLE "presence-invisible" +#define NS_PRIVACY "jabber:iq:privacy" +#define NS_INVISIBLE "urn:xmpp:invisible:0" +#define NS_REGISTER "jabber:iq:register" +#define NS_ROSTER "jabber:iq:roster" +#define NS_SEARCH "jabber:iq:search" +#define NS_SI "http://jabber.org/protocol/si" +#define NS_SI_MULTIPLE "http://telepathy.freedesktop.org/xmpp/si-multiple" +#define NS_TUBES "http://telepathy.freedesktop.org/xmpp/tubes" +#define NS_MUJI "http://telepathy.freedesktop.org/xmpp/muji" +#define NS_VCARD_TEMP "vcard-temp" +#define NS_VCARD_TEMP_UPDATE "vcard-temp:x:update" +#define NS_X_DATA "jabber:x:data" +#define NS_X_DELAY "jabber:x:delay" +#define NS_X_CONFERENCE "jabber:x:conference" +#define NS_XMPP_STANZAS "urn:ietf:params:xml:ns:xmpp-stanzas" +#define NS_GEOLOC "http://jabber.org/protocol/geoloc" +#define NS_GOOGLE_MAIL_NOTIFY "google:mail:notify" + +#define NS_TEMPPRES "urn:xmpp:temppres:0" +#define NS_GOOGLE_SHARED_STATUS "google:shared-status" + +#endif /* __GABBLE_NAMESPACES__H__ */ -- cgit v1.2.1