summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJonny Lamb <jonny.lamb@collabora.co.uk>2011-09-28 18:58:10 +0100
committerJonny Lamb <jonny.lamb@collabora.co.uk>2011-09-28 18:58:10 +0100
commita64cd72472d48ad8e88bfebe5e6046f02d4b5c93 (patch)
tree3a6c29cc5719c0b20f86fc15732d11b3e39556f1 /src
parent5f1ad2c76f43842856fb01a2dc51648a42f24284 (diff)
parent9c86f446c6a00142c373aae1fa357f5c00f0f2c6 (diff)
Merge branch 'moar-caps'
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/auth-manager.c2
-rw-r--r--src/capabilities.c2
-rw-r--r--src/capabilities.h74
-rw-r--r--src/caps-channel-manager.c8
-rw-r--r--src/caps-channel-manager.h105
-rw-r--r--src/caps-hash.c7
-rw-r--r--src/connection.c329
-rw-r--r--src/connection.h4
-rw-r--r--src/ft-manager.c5
-rw-r--r--src/im-factory.c2
-rw-r--r--src/jingle-session.c2
-rw-r--r--src/legacy-caps.h2
-rw-r--r--src/media-factory.c5
-rw-r--r--src/muc-factory.c2
-rw-r--r--src/presence-cache.c94
-rw-r--r--src/presence-cache.h9
-rw-r--r--src/presence.c67
-rw-r--r--src/presence.h4
-rw-r--r--src/private-tubes-factory.c6
-rw-r--r--src/roomlist-manager.c2
-rw-r--r--src/roster.c2
-rw-r--r--src/search-manager.c2
-rw-r--r--src/server-tls-manager.c2
24 files changed, 500 insertions, 241 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index c94cfaa0..0d5355ff 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -44,12 +44,12 @@ libgabble_convenience_la_SOURCES = \
call-stream.h \
call-stream.c \
$(top_srcdir)/gabble/capabilities-set.h \
- capabilities.h \
+ $(top_srcdir)/gabble/capabilities.h \
capabilities.c \
$(top_srcdir)/gabble/caps-hash.h \
caps-hash.h \
caps-hash.c \
- caps-channel-manager.h \
+ $(top_srcdir)/gabble/caps-channel-manager.h \
caps-channel-manager.c \
conn-aliasing.h \
conn-aliasing.c \
diff --git a/src/auth-manager.c b/src/auth-manager.c
index a9424854..d9638eed 100644
--- a/src/auth-manager.c
+++ b/src/auth-manager.c
@@ -28,7 +28,7 @@
#define DEBUG_FLAG GABBLE_DEBUG_AUTH
-#include "caps-channel-manager.h"
+#include "gabble/caps-channel-manager.h"
#include "server-sasl-channel.h"
#include "connection.h"
#include "debug.h"
diff --git a/src/capabilities.c b/src/capabilities.c
index b3ef11e8..d0b36e78 100644
--- a/src/capabilities.c
+++ b/src/capabilities.c
@@ -19,7 +19,7 @@
*/
#include "config.h"
-#include "capabilities.h"
+#include "gabble/capabilities.h"
#include <stdlib.h>
#include <string.h>
diff --git a/src/capabilities.h b/src/capabilities.h
deleted file mode 100644
index 8e7d1a03..00000000
--- a/src/capabilities.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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 <glib-object.h>
-
-#include "gabble/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 <content/> */
-#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_CAMERA_V1 "camera-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
index 73b3e222..dea13a65 100644
--- a/src/caps-channel-manager.c
+++ b/src/caps-channel-manager.c
@@ -21,7 +21,7 @@
*/
#include "config.h"
-#include "caps-channel-manager.h"
+#include "gabble/caps-channel-manager.h"
#include <telepathy-glib/dbus.h>
#include <telepathy-glib/channel-manager.h>
@@ -82,6 +82,7 @@ gabble_caps_channel_manager_get_contact_capabilities (
* 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
+ * @data_forms: a #GPtrArray of #WockyDataForm objects
*
* Convert the capabilities of a Telepathy client into XMPP capabilities to be
* advertised.
@@ -95,7 +96,8 @@ gabble_caps_channel_manager_represent_client (
const gchar *client_name,
const GPtrArray *filters,
const gchar * const *cap_tokens,
- GabbleCapabilitySet *cap_set)
+ GabbleCapabilitySet *cap_set,
+ GPtrArray *data_forms)
{
GabbleCapsChannelManagerInterface *iface =
GABBLE_CAPS_CHANNEL_MANAGER_GET_INTERFACE (caps_manager);
@@ -103,6 +105,6 @@ gabble_caps_channel_manager_represent_client (
if (method != NULL)
{
- method (caps_manager, client_name, filters, cap_tokens, cap_set);
+ method (caps_manager, client_name, filters, cap_tokens, cap_set, data_forms);
}
}
diff --git a/src/caps-channel-manager.h b/src/caps-channel-manager.h
deleted file mode 100644
index 05947b75..00000000
--- a/src/caps-channel-manager.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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 <glib-object.h>
-#include <telepathy-glib/exportable-channel.h>
-#include <telepathy-glib/handle.h>
-
-#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, GabbleCapsChannelManagerInterface))
-
-typedef struct _GabbleCapsChannelManager GabbleCapsChannelManager;
-typedef struct _GabbleCapsChannelManagerInterface GabbleCapsChannelManagerInterface;
-
-/* 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 _GabbleCapsChannelManagerInterface {
- 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/caps-hash.c b/src/caps-hash.c
index bf8a2a08..1518748e 100644
--- a/src/caps-hash.c
+++ b/src/caps-hash.c
@@ -35,7 +35,7 @@
#define DEBUG_FLAG GABBLE_DEBUG_PRESENCE
#include "base64.h"
-#include "capabilities.h"
+#include "gabble/capabilities.h"
#include "debug.h"
#include "namespaces.h"
#include "presence-cache.h"
@@ -61,6 +61,7 @@ caps_hash_compute_from_self_presence (GabbleConnection *self)
const GabbleCapabilitySet *cap_set;
GPtrArray *features = g_ptr_array_new ();
GPtrArray *identities = wocky_disco_identity_array_new ();
+ GPtrArray *data_forms;
gchar *str;
/* XEP-0030 requires at least 1 identity. We don't need more. */
@@ -71,7 +72,9 @@ caps_hash_compute_from_self_presence (GabbleConnection *self)
cap_set = gabble_presence_peek_caps (presence);
gabble_capability_set_foreach (cap_set, ptr_array_add_str, features);
- str = wocky_caps_hash_compute_from_lists (features, identities, NULL);
+ data_forms = gabble_presence_peek_data_forms (presence);
+
+ str = wocky_caps_hash_compute_from_lists (features, identities, data_forms);
g_ptr_array_free (features, TRUE);
wocky_disco_identity_array_free (identities);
diff --git a/src/connection.c b/src/connection.c
index b06cbc10..1ea7d655 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -36,6 +36,7 @@
#include <wocky/wocky-tls-handler.h>
#include <wocky/wocky-ping.h>
#include <wocky/wocky-xmpp-error.h>
+#include <wocky/wocky-data-form.h>
#include <telepathy-glib/channel-manager.h>
#include <telepathy-glib/dbus.h>
#include <telepathy-glib/enums.h>
@@ -50,8 +51,8 @@
#define DEBUG_FLAG GABBLE_DEBUG_CONNECTION
#include "bytestream-factory.h"
-#include "capabilities.h"
-#include "caps-channel-manager.h"
+#include "gabble/capabilities.h"
+#include "gabble/caps-channel-manager.h"
#include "caps-hash.h"
#include "auth-manager.h"
#include "conn-aliasing.h"
@@ -258,6 +259,10 @@ struct _GabbleConnectionPrivate
/* the union of the above */
GabbleCapabilitySet *all_caps;
+ /* data forms provided via UpdateCapabilities()
+ * gchar * (client name) => GPtrArray<owned WockyDataForm> */
+ GHashTable *client_data_forms;
+
/* auth manager */
GabbleAuthManager *auth_manager;
@@ -444,6 +449,9 @@ gabble_connection_constructor (GType type,
priv->client_caps = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) gabble_capability_set_free);
+ priv->client_data_forms = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify) g_ptr_array_unref);
+
/* Historically, the optional Jingle transports were in our initial
* presence, but could be removed by AdvertiseCapabilities(). Emulate
* that here for now. */
@@ -1222,6 +1230,8 @@ gabble_connection_dispose (GObject *object)
gabble_capability_set_free (priv->sidecar_caps);
gabble_capability_set_free (priv->bonus_caps);
+ g_hash_table_destroy (priv->client_data_forms);
+
if (priv->disconnect_timer != 0)
{
g_source_remove (priv->disconnect_timer);
@@ -1362,6 +1372,14 @@ WockyPorter *gabble_connection_dup_porter (GabbleConnection *conn)
return NULL;
}
+WockySession *
+gabble_connection_get_session (GabbleConnection *connection)
+{
+ g_return_val_if_fail (GABBLE_IS_CONNECTION (connection), NULL);
+
+ return connection->session;
+}
+
/**
* _gabble_connection_send
*
@@ -2303,7 +2321,8 @@ gabble_connection_fill_in_caps (GabbleConnection *self,
/* Ensure this set of capabilities is in the cache. */
gabble_presence_cache_add_own_caps (self->presence_cache, caps_hash,
- gabble_presence_peek_caps (presence), NULL);
+ gabble_presence_peek_caps (presence), NULL,
+ gabble_presence_peek_data_forms (presence));
/* XEP-0115 deprecates 'ext' feature bundles. But we still need
* BUNDLE_VOICE_V1 it for backward-compatibility with Gabble 0.2 */
@@ -2401,10 +2420,13 @@ gabble_connection_refresh_capabilities (GabbleConnection *self,
GHashTableIter iter;
gpointer k, v;
GabbleCapabilitySet *save_set;
+ GPtrArray *data_forms;
save_set = self->priv->all_caps;
self->priv->all_caps = gabble_capability_set_new ();
+ data_forms = g_ptr_array_new ();
+
gabble_capability_set_update (self->priv->all_caps,
gabble_capabilities_get_fixed_caps ());
gabble_capability_set_update (self->priv->all_caps, self->priv->notify_caps);
@@ -2412,6 +2434,7 @@ gabble_connection_refresh_capabilities (GabbleConnection *self,
gabble_capability_set_update (self->priv->all_caps, self->priv->sidecar_caps);
gabble_capability_set_update (self->priv->all_caps, self->priv->bonus_caps);
+ /* first, normal caps */
g_hash_table_iter_init (&iter, self->priv->client_caps);
while (g_hash_table_iter_next (&iter, &k, &v))
@@ -2427,13 +2450,22 @@ gabble_connection_refresh_capabilities (GabbleConnection *self,
gabble_capability_set_update (self->priv->all_caps, v);
}
+ /* now data forms */
+ g_hash_table_iter_init (&iter, self->priv->client_data_forms);
+
+ /* just borrow the ref, data_forms doesn't have a free func */
+ while (g_hash_table_iter_next (&iter, &k, &v))
+ tp_g_ptr_array_extend (data_forms, v);
+
if (self->self_presence != NULL)
gabble_presence_set_capabilities (self->self_presence,
- self->priv->resource, self->priv->all_caps, self->priv->caps_serial++);
+ self->priv->resource, self->priv->all_caps, data_forms,
+ self->priv->caps_serial++);
if (gabble_capability_set_equals (self->priv->all_caps, save_set))
{
gabble_capability_set_free (save_set);
+ g_ptr_array_unref (data_forms);
DEBUG ("nothing to do");
return FALSE;
}
@@ -2442,6 +2474,7 @@ gabble_connection_refresh_capabilities (GabbleConnection *self,
if (base->status != TP_CONNECTION_STATUS_CONNECTED)
{
gabble_capability_set_free (save_set);
+ g_ptr_array_unref (data_forms);
DEBUG ("not emitting self-presence stanza: not connected yet");
return FALSE;
}
@@ -2449,6 +2482,7 @@ gabble_connection_refresh_capabilities (GabbleConnection *self,
if (!conn_presence_signal_own_presence (self, NULL, &error))
{
gabble_capability_set_free (save_set);
+ g_ptr_array_unref (data_forms);
DEBUG ("error sending presence: %s", error->message);
g_error_free (error);
return FALSE;
@@ -2459,6 +2493,8 @@ gabble_connection_refresh_capabilities (GabbleConnection *self,
else
*old_out = save_set;
+ g_ptr_array_unref (data_forms);
+
return TRUE;
}
@@ -2570,6 +2606,7 @@ iq_disco_cb (WockyPorter *porter,
const GabbleCapabilityInfo *info = NULL;
const GabbleCapabilitySet *features = NULL;
const GPtrArray *identities = NULL;
+ const GPtrArray *data_forms = NULL;
/* query's existence is checked by WockyPorter before this function is called */
query = wocky_node_get_child (wocky_stanza_get_top_node (stanza), "query");
@@ -2599,19 +2636,25 @@ iq_disco_cb (WockyPorter *porter,
wocky_node_set_attribute (result_query, "node", node);
if (node == NULL)
- features = gabble_presence_peek_caps (self->self_presence);
- /* If node is not NULL, it can be either a caps bundle as defined in the
- * legacy XEP-0115 version 1.3 or an hash as defined in XEP-0115 version
- * 1.5. Let's see if it's a verification string we've told the cache about.
- */
+ {
+ features = gabble_presence_peek_caps (self->self_presence);
+ data_forms = gabble_presence_peek_data_forms (self->self_presence);
+ }
else
- info = gabble_presence_cache_peek_own_caps (self->presence_cache,
- suffix);
+ {
+ /* If node is not NULL, it can be either a caps bundle as defined in the
+ * legacy XEP-0115 version 1.3 or an hash as defined in XEP-0115 version
+ * 1.5. Let's see if it's a verification string we've told the cache about.
+ */
+ info = gabble_presence_cache_peek_own_caps (self->presence_cache,
+ suffix);
+ }
if (info)
{
features = info->cap_set;
identities = info->identities;
+ data_forms = info->data_forms;
}
if (identities && identities->len != 0)
@@ -2650,6 +2693,18 @@ iq_disco_cb (WockyPorter *porter,
features = gabble_capabilities_get_bundle_video_v1 ();
}
+ if (data_forms != NULL)
+ {
+ guint i;
+
+ for (i = 0; i < data_forms->len; i++)
+ {
+ WockyDataForm *form = g_ptr_array_index (data_forms, i);
+
+ wocky_data_form_add_to_node (form, result_query);
+ }
+ }
+
if (features == NULL && tp_strdiff (suffix, BUNDLE_PMUC_V1))
{
_gabble_connection_send_iq_error (self, stanza,
@@ -3193,6 +3248,111 @@ gabble_connection_advertise_capabilities (TpSvcConnectionInterfaceCapabilities *
g_ptr_array_free (ret, TRUE);
}
+static const gchar *
+get_form_type (WockyDataForm *form)
+{
+ WockyDataFormField *field;
+
+ field = g_hash_table_lookup (form->fields,
+ "FORM_TYPE");
+ g_assert (field != NULL);
+
+ return field->raw_value_contents[0];
+}
+
+static const gchar *
+check_form_is_unique (GabbleConnection *self,
+ const gchar *form_type)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, self->priv->client_data_forms);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ const gchar *manager = key;
+ GPtrArray *data_forms = value;
+ guint i;
+
+ if (data_forms == NULL || data_forms->len == 0)
+ continue;
+
+ for (i = 0; i < data_forms->len; i++)
+ {
+ WockyDataForm *form = g_ptr_array_index (data_forms, i);
+
+ if (!tp_strdiff (get_form_type (form), form_type))
+ return manager;
+ }
+ }
+
+ return NULL;
+}
+
+static gboolean
+check_data_form_in_list (GPtrArray *array,
+ const gchar *form_type)
+{
+ guint i;
+
+ for (i = 0; i < array->len; i++)
+ {
+ WockyDataForm *form = g_ptr_array_index (array, i);
+
+ if (!tp_strdiff (get_form_type (form), form_type))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+check_data_form_is_valid (GabbleConnection *self,
+ WockyDataForm *form,
+ GPtrArray *existing_forms)
+{
+ WockyDataFormField *field;
+ const gchar *form_type, *other_client;
+
+ /* We want rid of forms with no FORM_TYPE quickly. */
+ field = g_hash_table_lookup (form->fields, "FORM_TYPE");
+
+ if (field == NULL || tp_str_empty (field->raw_value_contents[0]))
+ {
+ WARNING ("data form with no FORM_TYPE field; ignoring");
+ return FALSE;
+ }
+
+ form_type = field->raw_value_contents[0];
+
+ /* We'll get warnings (potentially bad) if two clients cause a
+ * channel manager to create two data forms with the same FORM_TYPE,
+ * or if multiple channel managers create two data forms with the
+ * same FORM_TYPE, for the same client. This is probably not a
+ * problem in practice given hardly anyone uses data forms in entity
+ * capabilities anyway. */
+
+ /* We don't want the same data form from another caps channel
+ * manager for this client either */
+ if (check_data_form_in_list (existing_forms, form_type))
+ {
+ WARNING ("duplicate data form '%s' from another channel "
+ "manager; ignoring", form_type);
+ return FALSE;
+ }
+
+ /* And lastly we don't want a form we're already advertising. */
+ other_client = check_form_is_unique (self, form_type);
+ if (other_client != NULL)
+ {
+ WARNING ("Data form '%s' already provided by client "
+ "%s; ignoring", form_type, other_client);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/**
* gabble_connection_update_capabilities
*
@@ -3239,10 +3399,12 @@ gabble_connection_update_capabilities (
const GPtrArray *filters = g_value_get_boxed (va->values + 1);
const gchar * const * cap_tokens = g_value_get_boxed (va->values + 2);
GabbleCapabilitySet *cap_set;
+ GPtrArray *data_forms;
g_hash_table_remove (self->priv->client_caps, client_name);
+ g_hash_table_remove (self->priv->client_data_forms, client_name);
- if ((cap_tokens == NULL || cap_tokens[0] != NULL) &&
+ if ((cap_tokens == NULL || cap_tokens[0] == NULL) &&
filters->len == 0)
{
/* no capabilities */
@@ -3251,6 +3413,8 @@ gabble_connection_update_capabilities (
}
cap_set = gabble_capability_set_new ();
+ data_forms = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) g_object_unref);
tp_base_connection_channel_manager_iter_init (&iter, base);
@@ -3258,18 +3422,30 @@ gabble_connection_update_capabilities (
{
if (GABBLE_IS_CAPS_CHANNEL_MANAGER (manager))
{
+ GPtrArray *forms = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) g_object_unref);
+ guint j;
+
+ /* First, represent the client... */
gabble_caps_channel_manager_represent_client (
GABBLE_CAPS_CHANNEL_MANAGER (manager), client_name, filters,
- cap_tokens, cap_set);
+ cap_tokens, cap_set, forms);
+
+ /* Now check the forms... */
+ for (j = 0; j < forms->len; j++)
+ {
+ WockyDataForm *form = g_ptr_array_index (forms, j);
+
+ if (check_data_form_is_valid (self, form, data_forms))
+ g_ptr_array_add (data_forms, g_object_ref (form));
+ }
+
+ g_ptr_array_unref (forms);
}
}
- if (gabble_capability_set_size (cap_set) == 0)
- {
- DEBUG ("client %s has no interesting capabilities", client_name);
- gabble_capability_set_free (cap_set);
- }
- else
+ /* first deal with normal caps */
+ if (gabble_capability_set_size (cap_set) > 0)
{
if (DEBUGGING)
{
@@ -3282,6 +3458,33 @@ gabble_connection_update_capabilities (
g_hash_table_insert (self->priv->client_caps, g_strdup (client_name),
cap_set);
}
+ else
+ {
+ DEBUG ("client %s has no interesting capabilities", client_name);
+ gabble_capability_set_free (cap_set);
+ }
+
+ /* now data forms */
+ if (data_forms->len > 0)
+ {
+ guint j;
+
+ /* now print out what forms we have here */
+ DEBUG ("client %s contributes %u data form%s:", client_name,
+ data_forms->len,
+ data_forms->len > 1 ? "s" : "");
+
+ for (j = 0; j < data_forms->len; j++)
+ DEBUG (" - %s", get_form_type (g_ptr_array_index (data_forms, i)));
+
+ g_hash_table_insert (self->priv->client_data_forms,
+ g_strdup (client_name), data_forms);
+ }
+ else
+ {
+ DEBUG ("client %s has no interesting data forms", client_name);
+ g_ptr_array_unref (data_forms);
+ }
}
if (gabble_connection_refresh_capabilities (self, &old_caps))
@@ -3711,9 +3914,95 @@ gabble_connection_add_sidecar_own_caps (GabbleConnection *self,
ver = gabble_caps_hash_compute (cap_set, identities_copy);
gabble_presence_cache_add_own_caps (self->presence_cache, ver,
- cap_set, identities_copy);
+ cap_set, identities_copy, NULL);
wocky_disco_identity_array_free (identities_copy);
return ver;
}
+
+const gchar *
+gabble_connection_get_jid_for_caps (GabbleConnection *conn,
+ WockyXep0115Capabilities *caps)
+{
+ TpHandle handle;
+ TpBaseConnection *base;
+ TpHandleRepoIface *contact_handles;
+
+ g_return_val_if_fail (GABBLE_IS_CONNECTION (conn), NULL);
+ g_return_val_if_fail (GABBLE_IS_PRESENCE (caps), NULL);
+
+ base = (TpBaseConnection *) conn;
+
+ if ((GabblePresence *) caps == conn->self_presence)
+ {
+ handle = tp_base_connection_get_self_handle (base);
+ }
+ else
+ {
+ handle = gabble_presence_cache_get_handle (conn->presence_cache,
+ (GabblePresence *) caps);
+ }
+
+ contact_handles = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+
+ return tp_handle_inspect (contact_handles, handle);
+}
+
+const gchar *
+gabble_connection_pick_best_resource_for_caps (GabbleConnection *connection,
+ const gchar *jid,
+ GabbleCapabilitySetPredicate predicate,
+ gconstpointer user_data)
+{
+ TpBaseConnection *base;
+ TpHandleRepoIface *contact_handles;
+ TpHandle handle;
+ GabblePresence *presence;
+
+ g_return_val_if_fail (GABBLE_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (!tp_str_empty (jid), NULL);
+
+ base = (TpBaseConnection *) connection;
+ contact_handles = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+
+ handle = tp_handle_ensure (contact_handles, jid,
+ NULL, NULL);
+
+ if (handle == 0)
+ return NULL;
+
+ presence = gabble_presence_cache_get (connection->presence_cache,
+ handle);
+
+ if (presence == NULL)
+ return NULL;
+
+ return gabble_presence_pick_resource_by_caps (presence, 0,
+ predicate, user_data);
+}
+
+TpBaseContactList *
+gabble_connection_get_contact_list (GabbleConnection *connection)
+{
+ g_return_val_if_fail (GABBLE_IS_CONNECTION (connection), NULL);
+
+ return (TpBaseContactList *) connection->roster;
+}
+
+WockyXep0115Capabilities *
+gabble_connection_get_caps (GabbleConnection *connection,
+ TpHandle handle)
+{
+ GabblePresence *presence;
+
+ g_return_val_if_fail (GABBLE_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (handle > 0, NULL);
+
+ presence = gabble_presence_cache_get (connection->presence_cache,
+ handle);
+
+ return (WockyXep0115Capabilities *) presence;
+}
diff --git a/src/connection.h b/src/connection.h
index 586b648c..d1dc73a5 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -34,7 +34,7 @@
#include <wocky/wocky-pep-service.h>
#include "gabble/connection.h"
-#include "capabilities.h"
+#include "gabble/capabilities.h"
#include "error.h"
#include "ft-manager.h"
#include "jingle-factory.h"
@@ -204,8 +204,6 @@ typedef enum {
GABBLE_CONNECTION_ALIAS_FROM_ROSTER
} GabbleConnectionAliasSource;
-gchar *gabble_connection_get_full_jid (GabbleConnection *conn);
-
WockyPorter *gabble_connection_dup_porter (GabbleConnection *conn);
gboolean _gabble_connection_set_properties_from_account (
diff --git a/src/ft-manager.c b/src/ft-manager.c
index 9c3128df..b79881ac 100644
--- a/src/ft-manager.c
+++ b/src/ft-manager.c
@@ -30,7 +30,7 @@
#include "jingle-session.h"
#include "jingle-share.h"
-#include "caps-channel-manager.h"
+#include "gabble/caps-channel-manager.h"
#include "connection.h"
#include "ft-manager.h"
#include "error.h"
@@ -824,7 +824,8 @@ gabble_ft_manager_represent_client (
const gchar *client_name,
const GPtrArray *filters,
const gchar * const *cap_tokens G_GNUC_UNUSED,
- GabbleCapabilitySet *cap_set)
+ GabbleCapabilitySet *cap_set,
+ GPtrArray *data_forms G_GNUC_UNUSED)
{
guint i;
diff --git a/src/im-factory.c b/src/im-factory.c
index 08f19f6c..be518b27 100644
--- a/src/im-factory.c
+++ b/src/im-factory.c
@@ -36,7 +36,7 @@
#include "extensions/extensions.h"
-#include "caps-channel-manager.h"
+#include "gabble/caps-channel-manager.h"
#include "connection.h"
#include "debug.h"
#include "disco.h"
diff --git a/src/jingle-session.c b/src/jingle-session.c
index f20c2d63..2981e3e8 100644
--- a/src/jingle-session.c
+++ b/src/jingle-session.c
@@ -30,7 +30,7 @@
#define DEBUG_FLAG GABBLE_DEBUG_MEDIA
-#include "capabilities.h"
+#include "gabble/capabilities.h"
#include "connection.h"
#include "conn-presence.h"
#include "debug.h"
diff --git a/src/legacy-caps.h b/src/legacy-caps.h
index 080ac3b0..e2de46c3 100644
--- a/src/legacy-caps.h
+++ b/src/legacy-caps.h
@@ -23,7 +23,7 @@
#include <glib-object.h>
-#include "capabilities.h"
+#include "gabble/capabilities.h"
typedef void (*TypeFlagsToCapsFunc) (guint typeflags, GabbleCapabilitySet *caps);
typedef guint (*CapsToTypeFlagsFunc) (const GabbleCapabilitySet *caps);
diff --git a/src/media-factory.c b/src/media-factory.c
index 4a2c7c70..e8ec9908 100644
--- a/src/media-factory.c
+++ b/src/media-factory.c
@@ -36,7 +36,7 @@
#define DEBUG_FLAG GABBLE_DEBUG_MEDIA
-#include "caps-channel-manager.h"
+#include "gabble/caps-channel-manager.h"
#include "connection.h"
#include "debug.h"
#include "jingle-factory.h"
@@ -1208,7 +1208,8 @@ gabble_media_factory_represent_client (GabbleCapsChannelManager *manager,
const gchar *client_name,
const GPtrArray *filters,
const gchar * const *cap_tokens,
- GabbleCapabilitySet *cap_set)
+ GabbleCapabilitySet *cap_set,
+ GPtrArray *data_forms)
{
static GQuark q_gtalk_p2p = 0, q_ice_udp = 0, q_h264 = 0;
static GQuark qc_gtalk_p2p = 0, qc_ice_udp = 0, qc_h264 = 0;
diff --git a/src/muc-factory.c b/src/muc-factory.c
index 1feb21a1..554b1504 100644
--- a/src/muc-factory.c
+++ b/src/muc-factory.c
@@ -36,7 +36,7 @@
#define DEBUG_FLAG GABBLE_DEBUG_MUC
-#include "caps-channel-manager.h"
+#include "gabble/caps-channel-manager.h"
#include "connection.h"
#include "conn-olpc.h"
#include "debug.h"
diff --git a/src/presence-cache.c b/src/presence-cache.c
index 05556f8b..89a6534e 100644
--- a/src/presence-cache.c
+++ b/src/presence-cache.c
@@ -41,11 +41,13 @@
#include <wocky/wocky-caps-hash.h>
#include <wocky/wocky-disco-identity.h>
#include <wocky/wocky-utils.h>
+#include <wocky/wocky-namespaces.h>
+#include <wocky/wocky-data-form.h>
#define DEBUG_FLAG GABBLE_DEBUG_PRESENCE
-#include "capabilities.h"
-#include "caps-channel-manager.h"
+#include "gabble/capabilities.h"
+#include "gabble/caps-channel-manager.h"
#include "conn-presence.h"
#include "debug.h"
#include "disco.h"
@@ -251,18 +253,36 @@ capability_info_free (GabbleCapabilityInfo *info)
wocky_disco_identity_array_free (info->identities);
info->identities = NULL;
+ if (info->data_forms != NULL)
+ g_ptr_array_unref (info->data_forms);
+ info->data_forms = NULL;
+
tp_intset_destroy (info->guys);
g_slice_free (GabbleCapabilityInfo, info);
}
+static void
+replace_data_forms (GabbleCapabilityInfo *info,
+ GPtrArray *data_forms)
+{
+ if (data_forms == info->data_forms)
+ return;
+
+ tp_clear_pointer (&info->data_forms, g_ptr_array_unref);
+
+ if (data_forms != NULL)
+ info->data_forms = g_ptr_array_ref (data_forms);
+}
+
static guint
capability_info_recvd (GabblePresenceCache *cache,
const gchar *node,
TpHandle handle,
GabbleCapabilitySet *cap_set,
guint trust_inc,
- guint client_types)
+ guint client_types,
+ GPtrArray *data_forms)
{
GabbleCapabilityInfo *info = capability_info_get (cache, node);
@@ -293,6 +313,8 @@ capability_info_recvd (GabblePresenceCache *cache,
info->client_types = client_types;
+ replace_data_forms (info, data_forms);
+
return info->trust;
}
@@ -1012,7 +1034,7 @@ _parse_node (GabblePresence *presence,
gabble_capability_set_add (cap_set, QUIRK_GOOGLE_WEBMAIL_CLIENT);
gabble_capability_set_add (cap_set, QUIRK_OMITS_CONTENT_CREATORS);
- gabble_presence_set_capabilities (presence, resource, cap_set, serial);
+ gabble_presence_set_capabilities (presence, resource, cap_set, NULL, serial);
gabble_capability_set_free (cap_set);
}
}
@@ -1142,6 +1164,7 @@ set_caps_for (DiscoWaiter *waiter,
GabblePresenceCache *cache,
GabbleCapabilitySet *cap_set,
guint client_types,
+ GPtrArray *data_forms,
TpHandle responder_handle,
const gchar *responder_jid)
{
@@ -1158,7 +1181,7 @@ set_caps_for (DiscoWaiter *waiter,
waiter->handle, responder_handle, responder_jid);
gabble_presence_set_capabilities (presence, waiter->resource, cap_set,
- waiter->serial);
+ data_forms, waiter->serial);
new_cap_set = gabble_presence_peek_caps (presence);
emit_capabilities_update (cache, waiter->handle, old_cap_set, new_cap_set);
gabble_capability_set_free (old_cap_set);
@@ -1222,6 +1245,29 @@ client_types_from_message (TpHandle handle,
return client_types;
}
+static GPtrArray *
+data_forms_from_message (WockyNode *node)
+{
+ GPtrArray *out = g_ptr_array_new_with_free_func (g_object_unref);
+
+ WockyNodeIter iter;
+ WockyNode *x_node = NULL;
+
+ wocky_node_iter_init (&iter, node, "x", WOCKY_XMPP_NS_DATA);
+ while (wocky_node_iter_next (&iter, &x_node))
+ {
+ WockyDataForm *form = wocky_data_form_new_from_node (x_node, NULL);
+
+ /* we've already parsed the reply to check the hash matches, so
+ * we can already guarantee these data forms will be parsed
+ * fine */
+ if (G_LIKELY (form != NULL))
+ g_ptr_array_add (out, form);
+ }
+
+ return out;
+}
+
static void
_signal_presences_updated (GabblePresenceCache *cache,
TpHandle handle)
@@ -1257,6 +1303,7 @@ _caps_disco_cb (GabbleDisco *disco,
gboolean jid_is_valid;
gpointer key;
guint client_types = 0;
+ GPtrArray *data_forms = NULL;
cache = GABBLE_PRESENCE_CACHE (user_data);
priv = cache->priv;
@@ -1305,6 +1352,7 @@ _caps_disco_cb (GabbleDisco *disco,
cap_set = gabble_capability_set_new_from_stanza (query_result);
client_types = client_types_from_message (handle, query_result,
waiter_self->resource);
+ data_forms = data_forms_from_message (query_result);
/* Only 'sha-1' is mandatory to implement by XEP-0115. If the remote contact
* uses another hash algorithm, don't check the hash and fallback to the old
@@ -1326,7 +1374,7 @@ _caps_disco_cb (GabbleDisco *disco,
else if (g_str_equal (waiter_self->ver, computed_hash))
{
trust = capability_info_recvd (cache, node, handle, cap_set,
- CAPABILITY_BUNDLE_ENOUGH_TRUST, client_types);
+ CAPABILITY_BUNDLE_ENOUGH_TRUST, client_types, data_forms);
}
else
{
@@ -1341,7 +1389,8 @@ _caps_disco_cb (GabbleDisco *disco,
}
else
{
- trust = capability_info_recvd (cache, node, handle, cap_set, 1, client_types);
+ trust = capability_info_recvd (cache, node, handle, cap_set, 1,
+ client_types, data_forms);
}
/* Remove the node from the hash table without freeing the key or list of
@@ -1381,7 +1430,8 @@ _caps_disco_cb (GabbleDisco *disco,
{
DiscoWaiter *waiter = (DiscoWaiter *) i->data;
- set_caps_for (waiter, cache, cap_set, client_types, handle, jid);
+ set_caps_for (waiter, cache, cap_set, client_types,
+ data_forms, handle, jid);
emit_capabilities_discovered (cache, waiter->handle);
}
@@ -1409,7 +1459,8 @@ _caps_disco_cb (GabbleDisco *disco,
g_free (tmp);
}
- set_caps_for (waiter_self, cache, cap_set, client_types, handle, jid);
+ set_caps_for (waiter_self, cache, cap_set, client_types,
+ data_forms, handle, jid);
}
waiters = g_slist_remove (waiters, waiter_self);
@@ -1435,6 +1486,7 @@ _caps_disco_cb (GabbleDisco *disco,
}
gabble_capability_set_free (cap_set);
+ g_ptr_array_unref (data_forms);
OUT:
if (handle)
@@ -1501,7 +1553,7 @@ _process_caps_uri (GabblePresenceCache *cache,
guint types;
gabble_presence_set_capabilities (
- presence, resource, cap_set, serial);
+ presence, resource, cap_set, info->data_forms, serial);
/* We can only get this information from actual disco replies,
* so we depend on having this information from the caps cache. */
@@ -2100,7 +2152,8 @@ gabble_presence_cache_add_own_caps (
GabblePresenceCache *cache,
const gchar *ver,
const GabbleCapabilitySet *cap_set,
- const GPtrArray *identities)
+ const GPtrArray *identities,
+ GPtrArray *data_forms)
{
gchar *uri = g_strdup_printf ("%s#%s", NS_GABBLE_CAPS, ver);
GabbleCapabilityInfo *info = capability_info_get (cache, uri);
@@ -2135,6 +2188,8 @@ gabble_presence_cache_add_own_caps (
info->trust = CAPABILITY_BUNDLE_ENOUGH_TRUST;
tp_intset_add (info->guys, cache->priv->conn->parent.self_handle);
+ replace_data_forms (info, data_forms);
+
/* FIXME: we should satisfy any waiters for this node now. fd.o bug #24619. */
out:
@@ -2497,3 +2552,20 @@ gabble_presence_cache_disco_in_progress (GabblePresenceCache *cache,
return in_progress;
}
+
+TpHandle
+gabble_presence_cache_get_handle (GabblePresenceCache *cache,
+ GabblePresence *presence)
+{
+ GHashTableIter iter;
+ gpointer key, val;
+
+ g_hash_table_iter_init (&iter, cache->priv->presence);
+ while (g_hash_table_iter_next (&iter, &key, &val))
+ {
+ if (presence == val)
+ return GPOINTER_TO_UINT (key);
+ }
+
+ return 0;
+}
diff --git a/src/presence-cache.h b/src/presence-cache.h
index 44af23fb..0e528396 100644
--- a/src/presence-cache.h
+++ b/src/presence-cache.h
@@ -65,6 +65,9 @@ struct _GabbleCapabilityInfo
/* array of GabbleDiscoIdentity or NULL */
GPtrArray *identities;
+ /* array of WockyDataForm or NULL */
+ GPtrArray *data_forms;
+
TpIntSet *guys;
guint trust;
@@ -107,7 +110,8 @@ void gabble_presence_cache_maybe_remove (GabblePresenceCache *cache,
void gabble_presence_cache_add_own_caps (GabblePresenceCache *cache,
const gchar *ver,
const GabbleCapabilitySet *cap_set,
- const GPtrArray *identities);
+ const GPtrArray *identities,
+ GPtrArray *data_forms);
const GabbleCapabilityInfo *gabble_presence_cache_peek_own_caps (
GabblePresenceCache *cache,
const gchar *ver);
@@ -140,6 +144,9 @@ GHashTable* gabble_presence_cache_get_location (GabblePresenceCache *cache,
gboolean gabble_presence_cache_disco_in_progress (GabblePresenceCache *cache,
TpHandle handle, const gchar *resource);
+TpHandle gabble_presence_cache_get_handle (GabblePresenceCache *cache,
+ GabblePresence *presence);
+
G_END_DECLS
#endif /* __GABBLE_PRESENCE_CACHE_H__ */
diff --git a/src/presence.c b/src/presence.c
index a707822a..1ddaedf6 100644
--- a/src/presence.c
+++ b/src/presence.c
@@ -24,8 +24,9 @@
#include <string.h>
#include <telepathy-glib/channel-manager.h>
#include <wocky/wocky-utils.h>
+#include <wocky/wocky-xep-0115-capabilities.h>
-#include "capabilities.h"
+#include "gabble/capabilities.h"
#include "conn-presence.h"
#include "presence-cache.h"
#include "namespaces.h"
@@ -36,7 +37,12 @@
#include "debug.h"
-G_DEFINE_TYPE (GabblePresence, gabble_presence, G_TYPE_OBJECT);
+static void xep_0115_capabilities_iface_init (gpointer, gpointer);
+
+G_DEFINE_TYPE_WITH_CODE (GabblePresence, gabble_presence, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (WOCKY_TYPE_XEP_0115_CAPABILITIES,
+ xep_0115_capabilities_iface_init);
+)
typedef struct _Resource Resource;
@@ -44,6 +50,7 @@ struct _Resource {
gchar *name;
guint client_type;
GabbleCapabilitySet *cap_set;
+ GPtrArray *data_forms;
guint caps_serial;
GabblePresenceId status;
gchar *status_message;
@@ -58,6 +65,9 @@ struct _GabblePresencePrivate {
/* The aggregated caps of all the contacts' resources. */
GabbleCapabilitySet *cap_set;
+ /* The aggregated data forms of all the contacts' resources */
+ GPtrArray *data_forms;
+
gchar *no_resource_status_message;
GSList *resources;
guint olpc_views;
@@ -72,6 +82,8 @@ _resource_new (gchar *name)
new->name = name;
new->client_type = 0;
new->cap_set = gabble_capability_set_new ();
+ new->data_forms = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) g_object_unref);
new->status = GABBLE_PRESENCE_OFFLINE;
new->status_message = NULL;
new->priority = 0;
@@ -87,6 +99,7 @@ _resource_free (Resource *resource)
g_free (resource->name);
g_free (resource->status_message);
gabble_capability_set_free (resource->cap_set);
+ g_ptr_array_unref (resource->data_forms);
g_slice_free (Resource, resource);
}
@@ -103,6 +116,7 @@ gabble_presence_finalize (GObject *object)
g_slist_free (priv->resources);
gabble_capability_set_free (priv->cap_set);
+ g_ptr_array_unref (priv->data_forms);
g_free (presence->nickname);
g_free (presence->avatar_sha1);
@@ -128,6 +142,8 @@ gabble_presence_init (GabblePresence *self)
priv = self->priv;
priv->cap_set = gabble_capability_set_new ();
+ priv->data_forms = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) g_object_unref);
priv->resources = NULL;
self->status = GABBLE_PRESENCE_UNKNOWN;
@@ -198,6 +214,13 @@ gabble_presence_peek_caps (GabblePresence *presence)
return presence->priv->cap_set;
}
+GPtrArray *
+gabble_presence_peek_data_forms (GabblePresence *presence)
+{
+ g_return_val_if_fail (presence != NULL, NULL);
+ return presence->priv->data_forms;
+}
+
gboolean
gabble_presence_has_resources (GabblePresence *self)
{
@@ -266,10 +289,22 @@ gabble_presence_resource_has_caps (GabblePresence *presence,
return FALSE;
}
+static void
+extend_and_dup (GPtrArray *target,
+ GPtrArray *source)
+{
+ if (source == NULL)
+ return;
+
+ g_ptr_array_foreach (source, (GFunc) g_object_ref, NULL);
+ tp_g_ptr_array_extend (target, source);
+}
+
void
gabble_presence_set_capabilities (GabblePresence *presence,
const gchar *resource,
const GabbleCapabilitySet *cap_set,
+ const GPtrArray *data_forms,
guint serial)
{
GabblePresencePrivate *priv = presence->priv;
@@ -288,11 +323,13 @@ gabble_presence_set_capabilities (GabblePresence *presence,
}
gabble_capability_set_clear (priv->cap_set);
+ g_ptr_array_set_size (priv->data_forms, 0);
if (resource == NULL)
{
DEBUG ("Setting capabilities for bare JID");
gabble_capability_set_update (priv->cap_set, cap_set);
+ extend_and_dup (priv->data_forms, (GPtrArray *) data_forms);
return;
}
@@ -315,6 +352,7 @@ gabble_presence_set_capabilities (GabblePresence *presence,
tmp->caps_serial);
tmp->caps_serial = serial;
gabble_capability_set_clear (tmp->cap_set);
+ g_ptr_array_set_size (tmp->data_forms, 0);
}
if (serial >= tmp->caps_serial)
@@ -322,11 +360,19 @@ gabble_presence_set_capabilities (GabblePresence *presence,
DEBUG ("updating caps for resource %s", resource);
gabble_capability_set_update (tmp->cap_set, cap_set);
+
+ /* TODO: deal with duplicates */
+ extend_and_dup (tmp->data_forms, (GPtrArray *) data_forms);
}
}
gabble_capability_set_update (priv->cap_set, tmp->cap_set);
+
+ /* TODO: deal with duplicates */
+ extend_and_dup (priv->data_forms, tmp->data_forms);
}
+
+ g_signal_emit_by_name (presence, "capabilities-changed");
}
static Resource *
@@ -855,3 +901,20 @@ gabble_presence_get_client_types_array (GabblePresence *presence,
return (gchar **) g_ptr_array_free (array, FALSE);
}
+
+static const GPtrArray *
+gabble_presence_get_data_forms (WockyXep0115Capabilities *caps)
+{
+ GabblePresence *presence = GABBLE_PRESENCE (caps);
+
+ return presence->priv->data_forms;
+}
+
+static void
+xep_0115_capabilities_iface_init (gpointer g_iface,
+ gpointer iface_data)
+{
+ WockyXep0115CapabilitiesInterface *iface = g_iface;
+
+ iface->get_data_forms = gabble_presence_get_data_forms;
+}
diff --git a/src/presence.h b/src/presence.h
index 4f9126d0..50d6945a 100644
--- a/src/presence.h
+++ b/src/presence.h
@@ -24,7 +24,7 @@
#include <glib-object.h>
-#include "capabilities.h"
+#include "gabble/capabilities.h"
#include "connection.h"
#include "types.h"
@@ -96,11 +96,13 @@ gboolean gabble_presence_update (GabblePresence *presence,
void gabble_presence_set_capabilities (GabblePresence *presence,
const gchar *resource,
const GabbleCapabilitySet *cap_set,
+ const GPtrArray *data_forms,
guint serial);
gboolean gabble_presence_has_cap (GabblePresence *presence, const gchar *ns);
GabbleCapabilitySet *gabble_presence_dup_caps (GabblePresence *presence);
const GabbleCapabilitySet *gabble_presence_peek_caps (GabblePresence *presence);
+GPtrArray *gabble_presence_peek_data_forms (GabblePresence *presence);
gboolean gabble_presence_has_resources (GabblePresence *self);
diff --git a/src/private-tubes-factory.c b/src/private-tubes-factory.c
index 4ec36fd1..52c10a84 100644
--- a/src/private-tubes-factory.c
+++ b/src/private-tubes-factory.c
@@ -36,8 +36,7 @@
#define DEBUG_FLAG GABBLE_DEBUG_TUBES
-#include "caps-channel-manager.h"
-#include "capabilities.h"
+#include "gabble/caps-channel-manager.h"
#include "connection.h"
#include "debug.h"
#include "muc-channel.h"
@@ -612,7 +611,8 @@ gabble_private_tubes_factory_represent_client (
const gchar *client_name,
const GPtrArray *filters,
const gchar * const *cap_tokens,
- GabbleCapabilitySet *cap_set)
+ GabbleCapabilitySet *cap_set,
+ GPtrArray *data_forms)
{
guint i;
diff --git a/src/roomlist-manager.c b/src/roomlist-manager.c
index 76abee68..5f38a102 100644
--- a/src/roomlist-manager.c
+++ b/src/roomlist-manager.c
@@ -33,7 +33,7 @@
#define DEBUG_FLAG GABBLE_DEBUG_MUC
-#include "caps-channel-manager.h"
+#include "gabble/caps-channel-manager.h"
#include "connection.h"
#include "debug.h"
#include "namespaces.h"
diff --git a/src/roster.c b/src/roster.c
index 798b83c6..8d8c3b7b 100644
--- a/src/roster.c
+++ b/src/roster.c
@@ -37,7 +37,7 @@
#define DEBUG_FLAG GABBLE_DEBUG_ROSTER
-#include "caps-channel-manager.h"
+#include "gabble/caps-channel-manager.h"
#include "conn-aliasing.h"
#include "conn-presence.h"
#include "conn-util.h"
diff --git a/src/search-manager.c b/src/search-manager.c
index d3c1fa57..fec4b74d 100644
--- a/src/search-manager.c
+++ b/src/search-manager.c
@@ -29,7 +29,7 @@
#define DEBUG_FLAG GABBLE_DEBUG_SEARCH
-#include "caps-channel-manager.h"
+#include "gabble/caps-channel-manager.h"
#include "connection.h"
#include "debug.h"
#include "disco.h"
diff --git a/src/server-tls-manager.c b/src/server-tls-manager.c
index 62ab8865..48364512 100644
--- a/src/server-tls-manager.c
+++ b/src/server-tls-manager.c
@@ -23,7 +23,7 @@
#define DEBUG_FLAG GABBLE_DEBUG_TLS
#include "debug.h"
-#include "caps-channel-manager.h"
+#include "gabble/caps-channel-manager.h"
#include "connection.h"
#include "server-tls-channel.h"
#include "util.h"