[Telepathy-commits] [telepathy-salut/master] Move salut-bytestream-manager to salut-si-bytestream-manager
Alban Crequy
alban.crequy at collabora.co.uk
Mon Nov 10 08:22:08 PST 2008
20080724112847-a41c0-8f5044e92c92aeb123e546c1c38d6710b4661460.gz
Conflicts:
src/salut-connection.c
---
src/Makefile.am | 4 +-
src/salut-bytestream-manager.c | 1063 -------------------------------------
src/salut-bytestream-manager.h | 83 ---
src/salut-connection.c | 2 +-
src/salut-si-bytestream-manager.c | 1063 +++++++++++++++++++++++++++++++++++++
src/salut-si-bytestream-manager.h | 83 +++
src/tube-stream.c | 2 +-
7 files changed, 1150 insertions(+), 1150 deletions(-)
delete mode 100644 src/salut-bytestream-manager.c
delete mode 100644 src/salut-bytestream-manager.h
create mode 100644 src/salut-si-bytestream-manager.c
create mode 100644 src/salut-si-bytestream-manager.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 8c4dde1..cb877e3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -38,8 +38,8 @@ CORE_SOURCES = \
salut-presence.h \
salut-contact-channel.h \
salut-contact-channel.c \
- salut-bytestream-manager.h \
- salut-bytestream-manager.c \
+ salut-si-bytestream-manager.h \
+ salut-si-bytestream-manager.c \
text-helper.c \
text-helper.h \
salut-roomlist-channel.h \
diff --git a/src/salut-bytestream-manager.c b/src/salut-bytestream-manager.c
deleted file mode 100644
index de32994..0000000
--- a/src/salut-bytestream-manager.c
+++ /dev/null
@@ -1,1063 +0,0 @@
-/*
- * salut-bytestream-manager.c - Source for SalutBytestreamManager
- * Copyright (C) 2007 Collabora Ltd.
- *
- * 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 "salut-bytestream-manager.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <gibber/gibber-bytestream-ibb.h>
-#include <gibber/gibber-bytestream-oob.h>
-#include <gibber/gibber-xmpp-stanza.h>
-#include <gibber/gibber-namespaces.h>
-#include <gibber/gibber-xmpp-error.h>
-#include <gibber/gibber-iq-helper.h>
-
-#include "salut-im-manager.h"
-#include "salut-muc-manager.h"
-
-#define DEBUG_FLAG DEBUG_BYTESTREAM_MGR
-#include "debug.h"
-
-G_DEFINE_TYPE (SalutBytestreamManager, salut_bytestream_manager, G_TYPE_OBJECT)
-
-/* properties */
-enum
-{
- PROP_CONNECTION = 1,
- PROP_HOST_NAME_FQDN,
- LAST_PROPERTY
-};
-
-/* private structure */
-typedef struct _SalutBytestreamManagerPrivate SalutBytestreamManagerPrivate;
-
-struct _SalutBytestreamManagerPrivate
-{
- SalutConnection *connection;
- SalutImManager *im_manager;
- SalutMucManager *muc_manager;
- SalutXmppConnectionManager *xmpp_connection_manager;
- gchar *host_name_fqdn;
-
- gboolean dispose_has_run;
-};
-
-#define SALUT_BYTESTREAM_MANAGER_GET_PRIVATE(obj) \
- ((SalutBytestreamManagerPrivate *) ((SalutBytestreamManager *)obj)->priv)
-
-static void
-salut_bytestream_manager_init (SalutBytestreamManager *self)
-{
- SalutBytestreamManagerPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
- SALUT_TYPE_BYTESTREAM_MANAGER, SalutBytestreamManagerPrivate);
-
- self->priv = priv;
-
- priv->dispose_has_run = FALSE;
-}
-
-/* Filter for SI request (XEP-0095) */
-static gboolean
-si_request_filter (SalutXmppConnectionManager *xcm,
- GibberXmppConnection *conn,
- GibberXmppStanza *stanza,
- SalutContact *contact,
- gpointer user_data)
-{
- GibberStanzaType type;
- GibberStanzaSubType sub_type;
-
- gibber_xmpp_stanza_get_type_info (stanza, &type, &sub_type);
- if (type != GIBBER_STANZA_TYPE_IQ)
- return FALSE;
-
- if (sub_type != GIBBER_STANZA_SUB_TYPE_SET)
- return FALSE;
-
- return (gibber_xmpp_node_get_child_ns (stanza->node, "si",
- GIBBER_XMPP_NS_SI) != NULL);
-}
-
-static gboolean
-streaminit_parse_request (GibberXmppStanza *stanza,
- const gchar **profile,
- const gchar **from,
- const gchar **stream_id,
- const gchar **stream_init_id,
- const gchar **mime_type,
- GSList **stream_methods)
-{
- GibberXmppNode *iq, *si, *feature, *x;
- GSList *x_children, *field_children;
-
- iq = stanza->node;
-
- *stream_init_id = gibber_xmpp_node_get_attribute (iq, "id");
-
- *from = gibber_xmpp_node_get_attribute (stanza->node, "from");
- if (*from == NULL)
- {
- DEBUG ("got a message without a from field");
- return FALSE;
- }
-
- /* Parse <si> */
- si = gibber_xmpp_node_get_child_ns (iq, "si", GIBBER_XMPP_NS_SI);
- if (si == NULL)
- return FALSE;
-
- *stream_id = gibber_xmpp_node_get_attribute (si, "id");
- if (*stream_id == NULL)
- {
- DEBUG ("got a SI request without a stream id field");
- return FALSE;
- }
-
- *mime_type = gibber_xmpp_node_get_attribute (si, "mime-type");
- /* if no mime_type is defined, XEP-0095 says to assume "binary/octect-stream"
- * which is presumably a typo for "application/octet-stream" */
-
- *profile = gibber_xmpp_node_get_attribute (si, "profile");
- if (*profile == NULL)
- {
- DEBUG ("got a SI request without a profile field");
- return FALSE;
- }
-
- /* Parse <feature> */
- feature = gibber_xmpp_node_get_child_ns (si, "feature",
- GIBBER_XMPP_NS_FEATURENEG);
- if (feature == NULL)
- {
- DEBUG ("got a SI request without a feature field");
- return FALSE;
- }
-
- x = gibber_xmpp_node_get_child_ns (feature, "x", GIBBER_XMPP_NS_DATA);
- if (x == NULL)
- {
- DEBUG ("got a SI request without a X data field");
- return FALSE;
- }
-
- for (x_children = x->children; x_children;
- x_children = g_slist_next (x_children))
- {
- GibberXmppNode *field = x_children->data;
-
- if (tp_strdiff (gibber_xmpp_node_get_attribute (field, "var"),
- "stream-method"))
- /* some future field, ignore it */
- continue;
-
- if (tp_strdiff (gibber_xmpp_node_get_attribute (field, "type"),
- "list-single"))
- {
- DEBUG ( "SI request's stream-method field was "
- "not of type list-single");
- return FALSE;
- }
-
- /* Get the stream methods offered */
- *stream_methods = NULL;
- for (field_children = field->children; field_children;
- field_children = g_slist_next (field_children))
- {
- GibberXmppNode *stream_method, *value;
- const gchar *stream_method_str;
-
- stream_method = (GibberXmppNode *) field_children->data;
-
- value = gibber_xmpp_node_get_child (stream_method, "value");
- if (value == NULL)
- continue;
-
- stream_method_str = value->content;
- if (!tp_strdiff (stream_method_str, ""))
- continue;
-
- DEBUG ("Got stream-method %s", stream_method_str);
-
- /* Append to the stream_methods list */
- *stream_methods = g_slist_append (*stream_methods,
- (gchar *) stream_method_str);
- }
-
- /* no need to parse the rest of the fields, we've found the one we
- * wanted */
- break;
- }
-
- if (*stream_methods == NULL)
- {
- DEBUG ("got a SI request without stream method proposed");
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-bytestream_state_changed (GibberBytestreamIface *bytestream,
- GibberBytestreamState state,
- SalutXmppConnectionManager *mgr)
-{
- if (state == GIBBER_BYTESTREAM_STATE_CLOSED)
- {
- GibberXmppConnection *connection;
-
- DEBUG ("bytestream closed, release the connection");
- g_object_get (bytestream, "xmpp-connection", &connection, NULL);
-
- salut_xmpp_connection_manager_release_connection (mgr, connection);
-
- g_object_unref (connection);
- g_object_unref (bytestream);
- }
-}
-
-GibberBytestreamIface *
-choose_bytestream_method (SalutBytestreamManager *self,
- GSList *stream_methods,
- GibberXmppConnection *connection,
- SalutContact *contact,
- const gchar *stream_id,
- const gchar *stream_init_id)
-{
- SalutBytestreamManagerPrivate *priv =
- SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (self);
- GSList *l;
-
- /* We create the stream according the stream method chosen.
- * User has to accept it */
-
- /* check OOB */
- for (l = stream_methods; l != NULL; l = l->next)
- {
- if (!tp_strdiff (l->data, GIBBER_XMPP_NS_OOB))
- {
- DEBUG ("choose OOB in methods list");
- return g_object_new (GIBBER_TYPE_BYTESTREAM_OOB,
- "xmpp-connection", connection,
- "stream-id", stream_id,
- "state", GIBBER_BYTESTREAM_STATE_LOCAL_PENDING,
- "self-id", priv->connection->name,
- "peer-id", contact->name,
- "stream-init-id", stream_init_id,
- NULL);
- }
- }
-
- /* check IBB */
- for (l = stream_methods; l != NULL; l = l->next)
- {
- if (!tp_strdiff (l->data, GIBBER_XMPP_NS_IBB))
- {
- DEBUG ("choose IBB in methods list");
- return g_object_new (GIBBER_TYPE_BYTESTREAM_IBB,
- "xmpp-connection", connection,
- "stream-id", stream_id,
- "state", GIBBER_BYTESTREAM_STATE_LOCAL_PENDING,
- "self-id", priv->connection->name,
- "peer-id", contact->name,
- "stream-init-id", stream_init_id,
- NULL);
- }
- }
-
- return NULL;
-}
-
-static void
-si_request_cb (SalutXmppConnectionManager *xcm,
- GibberXmppConnection *connection,
- GibberXmppStanza *stanza,
- SalutContact *contact,
- gpointer user_data)
-{
- SalutBytestreamManager *self = SALUT_BYTESTREAM_MANAGER (user_data);
- SalutBytestreamManagerPrivate *priv =
- SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (self);
- TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
- (TpBaseConnection *) priv->connection, TP_HANDLE_TYPE_CONTACT);
- TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
- (TpBaseConnection *) priv->connection, TP_HANDLE_TYPE_ROOM);
- TpHandle peer_handle;
- GibberBytestreamIface *bytestream = NULL;
- GibberXmppNode *si, *node;
- const gchar *profile, *from, *stream_id, *stream_init_id, *mime_type;
- GSList *stream_methods = NULL;
-
- /* after this point, the message is for us, so in all cases we either handle
- * it or send an error reply */
-
- if (!streaminit_parse_request (stanza, &profile, &from, &stream_id,
- &stream_init_id, &mime_type, &stream_methods))
- {
- GibberXmppStanza *reply;
-
- reply = gibber_iq_helper_new_error_reply (stanza, XMPP_ERROR_BAD_REQUEST,
- "failed to parse SI request");
- gibber_xmpp_connection_send (connection, reply, NULL);
-
- g_object_unref (reply);
- return;
- }
-
- si = gibber_xmpp_node_get_child_ns (stanza->node, "si", GIBBER_XMPP_NS_SI);
- g_assert (si != NULL);
-
- DEBUG ("received a SI request");
-
- peer_handle = tp_handle_lookup (contact_repo, from, NULL, NULL);
- if (peer_handle == 0)
- {
- goto out;
- }
-
- /* check stream method */
- bytestream = choose_bytestream_method (self, stream_methods, connection,
- contact, stream_id, stream_init_id);
-
- if (bytestream == NULL)
- {
- GibberXmppStanza *reply;
-
- DEBUG ("SI request doesn't contain any supported stream method.");
- reply = gibber_iq_helper_new_error_reply (stanza,
- XMPP_ERROR_SI_NO_VALID_STREAMS, NULL);
-
- gibber_xmpp_connection_send (connection, reply, NULL);
-
- g_object_unref (reply);
- goto out;
- }
-
- /* Now that we have a bytestream, it's responsible for declining the IQ
- * if needed. */
-
- /* As bytestreams are not XCM aware, they can't take/release
- * the connection so we do it for them.
- * We'll release it when the bytestream will be closed */
- salut_xmpp_connection_manager_take_connection (priv->xmpp_connection_manager,
- connection);
-
- g_signal_connect (bytestream, "state-changed",
- G_CALLBACK (bytestream_state_changed), priv->xmpp_connection_manager);
-
- /* We inform the right manager we received a SI request */
- if (tp_strdiff (profile, GIBBER_TELEPATHY_NS_TUBES))
- {
- GError e = { GIBBER_XMPP_ERROR, XMPP_ERROR_SI_BAD_PROFILE, "" };
- DEBUG ("SI profile unsupported: %s", profile);
-
- gibber_bytestream_iface_close (bytestream, &e);
- goto out;
- }
-
- /* A Tubes SI request can be:
- * - a 1-1 new tube offer
- * - a 1-1 tube extra bytestream offer
- * - a muc tube extra bytestream offer
- */
-
- /* TODO: implement 1-1 tubes */
-
- node = gibber_xmpp_node_get_child_ns (si, "muc-stream",
- GIBBER_TELEPATHY_NS_TUBES);
- if (node != NULL)
- {
- const gchar *muc;
- TpHandle room_handle;
- SalutMucManager *muc_mgr;
-
- muc = gibber_xmpp_node_get_attribute (node, "muc");
- if (muc == NULL)
- {
- DEBUG ("muc-stream SI doesn't contain muc attribute");
- gibber_bytestream_iface_close (bytestream, NULL);
- goto out;
- }
-
- room_handle = tp_handle_lookup (room_repo, muc, NULL, NULL);
- if (room_handle == 0)
- {
- DEBUG ("Unknown room: %s\n", muc);
- gibber_bytestream_iface_close (bytestream, NULL);
- goto out;
- }
-
- g_object_get (priv->connection, "muc-manager", &muc_mgr, NULL);
- g_assert (muc_mgr != NULL);
-
- salut_muc_manager_handle_si_stream_request (muc_mgr,
- bytestream, room_handle, stream_id, stanza);
- g_object_unref (muc_mgr);
- }
- else
- {
- GError e = { GIBBER_XMPP_ERROR, XMPP_ERROR_BAD_REQUEST,
- "Invalid tube SI request: expected <tube>, <stream> or "
- "<muc-stream>" };
-
- DEBUG ("Invalid tube SI request");
- gibber_bytestream_iface_close (bytestream, &e);
- goto out;
- }
-
-out:
- g_slist_free (stream_methods);
- return;
-}
-
-void
-salut_bytestream_manager_dispose (GObject *object)
-{
- SalutBytestreamManager *self = SALUT_BYTESTREAM_MANAGER (object);
- SalutBytestreamManagerPrivate *priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (
- self);
-
- if (priv->dispose_has_run)
- return;
-
- priv->dispose_has_run = TRUE;
-
- g_object_unref (priv->im_manager);
- g_object_unref (priv->muc_manager);
- g_object_unref (priv->xmpp_connection_manager);
-
- if (G_OBJECT_CLASS (salut_bytestream_manager_parent_class)->dispose)
- G_OBJECT_CLASS (salut_bytestream_manager_parent_class)->dispose (object);
-}
-
-void
-salut_bytestream_manager_finalize (GObject *object)
-{
- SalutBytestreamManager *self = SALUT_BYTESTREAM_MANAGER (object);
- SalutBytestreamManagerPrivate *priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (
- self);
-
- g_free (priv->host_name_fqdn);
-
- if (G_OBJECT_CLASS (salut_bytestream_manager_parent_class)->finalize)
- G_OBJECT_CLASS (salut_bytestream_manager_parent_class)->finalize (object);
-}
-
-static void
-salut_bytestream_manager_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SalutBytestreamManager *self = SALUT_BYTESTREAM_MANAGER (object);
- SalutBytestreamManagerPrivate *priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (
- self);
-
- switch (property_id)
- {
- case PROP_CONNECTION:
- g_value_set_object (value, priv->connection);
- break;
- case PROP_HOST_NAME_FQDN:
- g_value_set_string (value, priv->host_name_fqdn);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- break;
- }
-}
-
-static void
-salut_bytestream_manager_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SalutBytestreamManager *self = SALUT_BYTESTREAM_MANAGER (object);
- SalutBytestreamManagerPrivate *priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (
- self);
-
- switch (property_id)
- {
- case PROP_CONNECTION:
- priv->connection = g_value_get_object (value);
- break;
- case PROP_HOST_NAME_FQDN:
- g_free (priv->host_name_fqdn);
- priv->host_name_fqdn = g_value_dup_string (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- break;
- }
-}
-
-static GObject *
-salut_bytestream_manager_constructor (GType type,
- guint n_props,
- GObjectConstructParam *props)
-{
- GObject *obj;
- SalutBytestreamManager *self;
- SalutBytestreamManagerPrivate *priv;
-
- obj = G_OBJECT_CLASS (salut_bytestream_manager_parent_class)->
- constructor (type, n_props, props);
-
- self = SALUT_BYTESTREAM_MANAGER (obj);
- priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (self);
-
- g_assert (priv->connection != NULL);
- g_object_get (priv->connection,
- "im-manager", &(priv->im_manager),
- "muc-manager", &(priv->muc_manager),
- "xmpp-connection-manager", &(priv->xmpp_connection_manager),
- NULL);
- g_assert (priv->im_manager != NULL);
- g_assert (priv->muc_manager != NULL);
- g_assert (priv->xmpp_connection_manager != NULL);
- g_assert (priv->host_name_fqdn != NULL);
-
- salut_xmpp_connection_manager_add_stanza_filter (
- priv->xmpp_connection_manager, NULL, si_request_filter,
- si_request_cb, self);
-
- return obj;
-}
-
-static void
-salut_bytestream_manager_class_init (
- SalutBytestreamManagerClass *salut_bytestream_manager_class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (salut_bytestream_manager_class);
- GParamSpec *param_spec;
-
- g_type_class_add_private (salut_bytestream_manager_class,
- sizeof (SalutBytestreamManagerPrivate));
-
- object_class->constructor = salut_bytestream_manager_constructor;
- object_class->dispose = salut_bytestream_manager_dispose;
- object_class->finalize = salut_bytestream_manager_finalize;
-
- object_class->get_property = salut_bytestream_manager_get_property;
- object_class->set_property = salut_bytestream_manager_set_property;
-
- param_spec = g_param_spec_object (
- "connection",
- "SalutConnection object",
- "Salut Connection that owns the connection for this bytestream channel",
- SALUT_TYPE_CONNECTION,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
-
- param_spec = g_param_spec_string (
- "host-name-fqdn",
- "host name FQDN",
- "The FQDN host name that will be used by OOB bytestreams",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- g_object_class_install_property (object_class, PROP_HOST_NAME_FQDN,
- param_spec);
-}
-
-SalutBytestreamManager *
-salut_bytestream_manager_new (SalutConnection *conn,
- const gchar *host_name_fqdn)
-{
- g_return_val_if_fail (SALUT_IS_CONNECTION (conn), NULL);
-
- return g_object_new (
- SALUT_TYPE_BYTESTREAM_MANAGER,
- "connection", conn,
- "host-name-fqdn", host_name_fqdn,
- NULL);
-}
-
-/**
- * salut_bytestream_manager_make_stream_init_iq
- *
- * @from: your contact
- * @to: the contact to who you want to offer the stream
- * @stream_id: the stream ID of the new stream
- * @profile: the profile associated with the stream
- *
- * Create a SI request IQ as described in XEP-0095.
- *
- */
-GibberXmppStanza *
-salut_bytestream_manager_make_stream_init_iq (const gchar *from,
- const gchar *to,
- const gchar *stream_id,
- const gchar *profile)
-{
- return gibber_xmpp_stanza_build (
- GIBBER_STANZA_TYPE_IQ, GIBBER_STANZA_SUB_TYPE_SET,
- from, to,
- GIBBER_NODE, "si",
- GIBBER_NODE_XMLNS, GIBBER_XMPP_NS_SI,
- GIBBER_NODE_ATTRIBUTE, "id", stream_id,
- GIBBER_NODE_ATTRIBUTE, "profile", profile,
- GIBBER_NODE_ATTRIBUTE, "mime-type", "binary/octect-stream",
- GIBBER_NODE, "feature",
- GIBBER_NODE_XMLNS, GIBBER_XMPP_NS_FEATURENEG,
- GIBBER_NODE, "x",
- GIBBER_NODE_XMLNS, GIBBER_XMPP_NS_DATA,
- GIBBER_NODE_ATTRIBUTE, "type", "form",
- GIBBER_NODE, "field",
- GIBBER_NODE_ATTRIBUTE, "var", "stream-method",
- GIBBER_NODE_ATTRIBUTE, "type", "list-single",
-
- GIBBER_NODE, "option",
- GIBBER_NODE, "value",
- GIBBER_NODE_TEXT, GIBBER_XMPP_NS_OOB,
- GIBBER_NODE_END,
- GIBBER_NODE_END,
-
- GIBBER_NODE, "option",
- GIBBER_NODE, "value",
- GIBBER_NODE_TEXT, GIBBER_XMPP_NS_IBB,
- GIBBER_NODE_END,
- GIBBER_NODE_END,
-
- GIBBER_NODE_END,
- GIBBER_NODE_END,
- GIBBER_NODE_END,
- GIBBER_NODE_END, GIBBER_STANZA_END);
-}
-
-struct streaminit_reply_cb_data
-{
- SalutBytestreamManager *self;
- gchar *stream_id;
- SalutBytestreamManagerNegotiateReplyFunc func;
- gpointer user_data;
- gchar *iq_id;
- SalutContact *contact;
- GibberXmppStanza *stanza;
-};
-
-static struct streaminit_reply_cb_data *
-streaminit_reply_cb_data_new (void)
-{
- return g_slice_new0 (struct streaminit_reply_cb_data);
-}
-
-static void
-streaminit_reply_cb_data_free (struct streaminit_reply_cb_data *data)
-{
- g_free (data->stream_id);
- g_free (data->iq_id);
-
- if (data->contact != NULL)
- g_object_unref (data->contact);
-
- if (data->stanza != NULL)
- g_object_unref (data->stanza);
-
- g_slice_free (struct streaminit_reply_cb_data, data);
-}
-
-static gboolean
-si_request_reply_filter (SalutXmppConnectionManager *manager,
- GibberXmppConnection *connection,
- GibberXmppStanza *stanza,
- SalutContact *contact,
- gpointer user_data)
-{
- struct streaminit_reply_cb_data *data =
- (struct streaminit_reply_cb_data *) user_data;
- GibberStanzaType type;
- GibberStanzaSubType sub_type;
- const gchar *iq_id;
-
- gibber_xmpp_stanza_get_type_info (stanza, &type, &sub_type);
- if (type != GIBBER_STANZA_TYPE_IQ)
- return FALSE;
-
- if (sub_type != GIBBER_STANZA_SUB_TYPE_RESULT &&
- sub_type != GIBBER_STANZA_SUB_TYPE_ERROR)
- return FALSE;
-
- iq_id = gibber_xmpp_node_get_attribute (stanza->node, "id");
- return (!tp_strdiff (iq_id, data->iq_id));
-}
-
-static gboolean
-check_bytestream_oob_peer_addr (GibberBytestreamOOB *bytestream,
- struct sockaddr *addr,
- socklen_t addrlen,
- gpointer user_data)
-{
- SalutBytestreamManager *self = SALUT_BYTESTREAM_MANAGER (user_data);
- SalutBytestreamManagerPrivate *priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (
- self);
- TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
- (TpBaseConnection *) priv->connection, TP_HANDLE_TYPE_CONTACT);
- TpHandle handle;
- SalutContactManager *contact_mgr;
- SalutContact *contact;
- gchar *peer;
- gboolean result;
-
- g_object_get (bytestream, "peer-id", &peer, NULL);
- g_assert (peer != NULL);
-
- handle = tp_handle_lookup (contact_repo, peer, NULL, NULL);
- g_assert (handle != 0);
- g_free (peer);
-
- g_object_get (priv->connection, "contact-manager", &contact_mgr, NULL);
- g_assert (contact_mgr != NULL);
-
- contact = salut_contact_manager_get_contact (contact_mgr, handle);
- g_object_unref (contact_mgr);
- if (contact == NULL)
- return FALSE;
-
- result = salut_contact_has_address (contact, addr, addrlen);
- g_object_unref (contact);
-
- return result;
-}
-
-static void
-si_request_reply_cb (SalutXmppConnectionManager *manager,
- GibberXmppConnection *connection,
- GibberXmppStanza *stanza,
- SalutContact *contact,
- gpointer user_data)
-{
- struct streaminit_reply_cb_data *data =
- (struct streaminit_reply_cb_data *) user_data;
- SalutBytestreamManagerPrivate *priv =
- SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (data->self);
- GibberStanzaSubType sub_type;
- GibberXmppNode *si, *feature, *x;
- GibberBytestreamIface *bytestream = NULL;
- const gchar *from, *stream_method, *stream_init_id;
- GSList *x_children;
-
- salut_xmpp_connection_manager_remove_stanza_filter (
- manager, connection, si_request_reply_filter, si_request_reply_cb, data);
-
- DEBUG ("received SI request response");
-
- gibber_xmpp_stanza_get_type_info (stanza, NULL, &sub_type);
- if (sub_type != GIBBER_STANZA_SUB_TYPE_RESULT)
- {
- DEBUG ("stream %s declined", data->stream_id);
- goto END;
- }
-
- /* stream accepted */
- stream_init_id = gibber_xmpp_node_get_attribute (stanza->node, "id");
-
- from = gibber_xmpp_node_get_attribute (stanza->node, "from");
- if (from == NULL)
- {
- DEBUG ("got a message without a from field");
- goto END;
- }
-
- si = gibber_xmpp_node_get_child_ns (stanza->node, "si",
- GIBBER_XMPP_NS_SI);
- if (si == NULL)
- {
- DEBUG ("got a SI reply without a si field");
- goto END;
- }
-
- feature = gibber_xmpp_node_get_child_ns (si, "feature",
- GIBBER_XMPP_NS_FEATURENEG);
- if (feature == NULL)
- {
- DEBUG ("got a SI reply without a feature field");
- goto END;
- }
-
- x = gibber_xmpp_node_get_child_ns (feature, "x", GIBBER_XMPP_NS_DATA);
- if (x == NULL)
- {
- DEBUG ("got a SI reply without a x field");
- goto END;
- }
-
- for (x_children = x->children; x_children;
- x_children = g_slist_next (x_children))
- {
- GibberXmppNode *value, *field = x_children->data;
-
- if (tp_strdiff (gibber_xmpp_node_get_attribute (field, "var"),
- "stream-method"))
- /* some future field, ignore it */
- continue;
-
- value = gibber_xmpp_node_get_child (field, "value");
- if (value == NULL)
- {
- DEBUG ("SI reply's stream-method field "
- "doesn't contain stream-method value");
- goto END;
- }
-
- stream_method = value->content;
-
- if (!tp_strdiff (stream_method, GIBBER_XMPP_NS_OOB))
- {
- /* Remote user have accepted the stream */
- DEBUG ("remote user chose a OOB bytestream");
- bytestream = g_object_new (GIBBER_TYPE_BYTESTREAM_OOB,
- "xmpp-connection", connection,
- "stream-id", data->stream_id,
- "state", GIBBER_BYTESTREAM_STATE_INITIATING,
- "self-id", priv->connection->name,
- "peer-id", from,
- "stream-init-id", NULL,
- "host", priv->host_name_fqdn,
- NULL);
- gibber_bytestream_oob_set_check_addr_func (
- GIBBER_BYTESTREAM_OOB (bytestream), check_bytestream_oob_peer_addr,
- data->self);
- }
- else if (!tp_strdiff (stream_method, GIBBER_XMPP_NS_IBB))
- {
- /* Remote user have accepted the stream */
- DEBUG ("remote user chose a IBB bytestream");
- bytestream = g_object_new (GIBBER_TYPE_BYTESTREAM_IBB,
- "xmpp-connection", connection,
- "stream-id", data->stream_id,
- "state", GIBBER_BYTESTREAM_STATE_INITIATING,
- "self-id", priv->connection->name,
- "peer-id", from,
- "stream-init-id", NULL,
- NULL);
- }
- else
- {
- DEBUG ("Remote user chose an unsupported stream method");
- goto END;
- }
-
- /* no need to parse the rest of the fields, we've found the one we
- * wanted */
- break;
-
- }
-
- if (bytestream == NULL)
- goto END;
-
- DEBUG ("stream %s accepted. Start to initiate it", data->stream_id);
-
- /* As bytestreams are not XCM aware, they can't take/release
- * the connection so we do it for them.
- * We'll release it when the bytestream will be closed */
- salut_xmpp_connection_manager_take_connection (priv->xmpp_connection_manager,
- connection);
-
- g_signal_connect (bytestream, "state-changed",
- G_CALLBACK (bytestream_state_changed), priv->xmpp_connection_manager);
-
- /* Let's start the initiation of the stream */
- if (!gibber_bytestream_iface_initiate (bytestream))
- {
- /* Initiation failed. */
- gibber_bytestream_iface_close (bytestream, NULL);
- bytestream = NULL;
- }
-
-END:
- /* user callback */
- data->func (bytestream, data->stream_id, stanza,
- data->user_data);
-
- streaminit_reply_cb_data_free (data);
-}
-
-static gboolean
-send_si_request (SalutBytestreamManager *self,
- GibberXmppConnection *connection,
- struct streaminit_reply_cb_data *data,
- GError **error)
-{
- SalutBytestreamManagerPrivate *priv =
- SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (self);
- const gchar *iq_id;
-
- iq_id = gibber_xmpp_node_get_attribute (data->stanza->node, "id");
- if (iq_id != NULL)
- {
- data->iq_id = g_strdup (iq_id);
- }
- else
- {
- data->iq_id = gibber_xmpp_connection_new_id (connection);
- gibber_xmpp_node_set_attribute (data->stanza->node, "id", data->iq_id);
- }
-
- /* Register a filter to catch the response of the SI request */
- salut_xmpp_connection_manager_add_stanza_filter (
- priv->xmpp_connection_manager, connection,
- si_request_reply_filter, si_request_reply_cb, data);
-
- /* FIXME: set a timer ?
- * Or we could listen for the XMPP connection closed signal and so use
- * XCM's timer as we didn't ref the connection yet */
- if (!gibber_xmpp_connection_send (connection, data->stanza, error))
- {
- salut_xmpp_connection_manager_remove_stanza_filter (
- priv->xmpp_connection_manager, connection,
- si_request_reply_filter, si_request_reply_cb, data);
-
- streaminit_reply_cb_data_free (data);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-xmpp_connection_manager_new_connection_cb (SalutXmppConnectionManager *mgr,
- GibberXmppConnection *connection,
- SalutContact *contact,
- gpointer user_data)
-{
- struct streaminit_reply_cb_data *data =
- (struct streaminit_reply_cb_data *) user_data;
-
- if (data->contact != contact)
- /* Not the connection we are waiting for */
- return;
-
- DEBUG ("got connection with %s. Send SI request", contact->name);
- send_si_request (data->self, connection, data, NULL);
-
- g_signal_handlers_disconnect_matched (mgr, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
- NULL, data);
-}
-
-static void
-xmpp_connection_manager_connection_failed_cb (SalutXmppConnectionManager *mgr,
- GibberXmppConnection *connection,
- SalutContact *contact,
- GQuark domain,
- gint code,
- gchar *message,
- gpointer user_data)
-{
- struct streaminit_reply_cb_data *data =
- (struct streaminit_reply_cb_data *) user_data;
-
- if (data->contact != contact)
- /* Not the connection we are waiting for */
- return;
-
- DEBUG ("connection with %s failed: %s. Can't send SI request", contact->name,
- message);
-
- /* Call the user callback without bytestream to inform him the SI request
- * failed */
- data->func (NULL, data->stream_id, NULL,
- data->user_data);
-
- g_signal_handlers_disconnect_matched (mgr, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
- NULL, data);
- streaminit_reply_cb_data_free (data);
-}
-
-/*
- * salut_bytestream_manager_negotiate_stream:
- *
- * @contact: the contact to who send the SI request
- * @stanza: the SI negotiation IQ (created using
- * salut_bytestream_manager_make_stream_init_iq)
- * @stream_id: the stream identifier
- * @func: the callback to call when we receive the answser of the request
- * @user_data: user data to pass to the callback
- * @error: pointer in which to return a GError in case of failure.
- *
- * Send a Stream Initiation (XEP-0095) request.
- */
-gboolean
-salut_bytestream_manager_negotiate_stream (SalutBytestreamManager *self,
- SalutContact *contact,
- GibberXmppStanza *stanza,
- const gchar *stream_id,
- SalutBytestreamManagerNegotiateReplyFunc func,
- gpointer user_data,
- GError **error)
-{
- SalutBytestreamManagerPrivate *priv;
- struct streaminit_reply_cb_data *data;
- GibberXmppConnection *connection = NULL;
- SalutXmppConnectionManagerRequestConnectionResult request_result;
-
- g_assert (SALUT_IS_BYTESTREAM_MANAGER (self));
- g_assert (stream_id != NULL);
- g_assert (func != NULL);
-
- priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (self);
-
- data = streaminit_reply_cb_data_new ();
- data->self = self;
- data->stream_id = g_strdup (stream_id);
- data->func = func;
- data->user_data = user_data;
- data->contact = g_object_ref (contact);
- data->stanza = g_object_ref (stanza);
-
- DEBUG ("request XMPP connection with %s to send the SI request",
- contact->name);
-
- /* We need a XMPP connection to send the SI request */
- request_result = salut_xmpp_connection_manager_request_connection (
- priv->xmpp_connection_manager, contact, &connection, error);
-
- if (request_result ==
- SALUT_XMPP_CONNECTION_MANAGER_REQUEST_CONNECTION_RESULT_DONE)
- {
- DEBUG ("got the connection with %s, send the SI request",
- data->contact->name);
-
- return send_si_request (self, connection, data, error);
- }
- else if (request_result ==
- SALUT_XMPP_CONNECTION_MANAGER_REQUEST_CONNECTION_RESULT_PENDING)
- {
- DEBUG ("connection with %s pending. Wait before send the SI request",
- contact->name);
-
- g_signal_connect (priv->xmpp_connection_manager, "new-connection",
- G_CALLBACK (xmpp_connection_manager_new_connection_cb), data);
- g_signal_connect (priv->xmpp_connection_manager, "connection-failed",
- G_CALLBACK (xmpp_connection_manager_connection_failed_cb), data);
-
- return TRUE;
- }
- else
- {
- DEBUG ("can't request connection with %s", contact->name);
- streaminit_reply_cb_data_free (data);
- return FALSE;
- }
-}
diff --git a/src/salut-bytestream-manager.h b/src/salut-bytestream-manager.h
deleted file mode 100644
index e641995..0000000
--- a/src/salut-bytestream-manager.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * salut-bytestream-manager.h - Header for SalutBytestreamManager
- * Copyright (C) 2007 Collabora Ltd.
- *
- * 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 __SALUT_BYTESTREAM_MANAGER_H__
-#define __SALUT_BYTESTREAM_MANAGER_H__
-
-#include <glib-object.h>
-#include "salut-xmpp-connection-manager.h"
-#include "salut-contact.h"
-
-#include <gibber/gibber-linklocal-transport.h>
-#include <gibber/gibber-bytestream-iface.h>
-
-G_BEGIN_DECLS
-
-typedef struct _SalutBytestreamManager SalutBytestreamManager;
-typedef struct _SalutBytestreamManagerClass SalutBytestreamManagerClass;
-
-struct _SalutBytestreamManagerClass {
- GObjectClass parent_class;
-};
-
-struct _SalutBytestreamManager {
- GObject parent;
-
- gpointer priv;
-};
-
-
-GType salut_bytestream_manager_get_type (void);
-
-/* TYPE MACROS */
-#define SALUT_TYPE_BYTESTREAM_MANAGER \
- (salut_bytestream_manager_get_type ())
-#define SALUT_BYTESTREAM_MANAGER(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), SALUT_TYPE_BYTESTREAM_MANAGER, \
- SalutBytestreamManager))
-#define SALUT_BYTESTREAM_MANAGER_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), SALUT_TYPE_BYTESTREAM_MANAGER, \
- SalutBytestreamManagerClass))
-#define SALUT_IS_BYTESTREAM_MANAGER(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), SALUT_TYPE_BYTESTREAM_MANAGER))
-#define SALUT_IS_BYTESTREAM_MANAGER_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass), SALUT_TYPE_BYTESTREAM_MANAGER))
-#define SALUT_BYTESTREAM_MANAGER_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), SALUT_TYPE_BYTESTREAM_MANAGER, \
- SalutBytestreamManagerClass))
-
-typedef void (* SalutBytestreamManagerNegotiateReplyFunc) (
- GibberBytestreamIface *bytestream, const gchar *stream_id,
- GibberXmppStanza *stanza, gpointer user_data);
-
-SalutBytestreamManager *
-salut_bytestream_manager_new (SalutConnection *connection,
- const gchar *host_name_fqdn);
-
-GibberXmppStanza *
-salut_bytestream_manager_make_stream_init_iq (const gchar *from,
- const gchar *to, const gchar *stream_id, const gchar *profile);
-
-gboolean
-salut_bytestream_manager_negotiate_stream (SalutBytestreamManager *self,
- SalutContact *contact, GibberXmppStanza *stanza, const gchar *stream_id,
- SalutBytestreamManagerNegotiateReplyFunc func, gpointer user_data,
- GError **error);
-
-#endif /* #ifndef __SALUT_BYTESTREAM_MANAGER_H__*/
diff --git a/src/salut-connection.c b/src/salut-connection.c
index 381fe24..7d2e747 100644
--- a/src/salut-connection.c
+++ b/src/salut-connection.c
@@ -40,7 +40,7 @@
#include "salut-contact.h"
#include "salut-self.h"
#include "salut-xmpp-connection-manager.h"
-#include "salut-bytestream-manager.h"
+#include "salut-si-bytestream-manager.h"
#ifdef ENABLE_OLPC
#include "salut-olpc-activity-manager.h"
diff --git a/src/salut-si-bytestream-manager.c b/src/salut-si-bytestream-manager.c
new file mode 100644
index 0000000..7024574
--- /dev/null
+++ b/src/salut-si-bytestream-manager.c
@@ -0,0 +1,1063 @@
+/*
+ * salut-bytestream-manager.c - Source for SalutBytestreamManager
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * 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 "salut-si-bytestream-manager.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gibber/gibber-bytestream-ibb.h>
+#include <gibber/gibber-bytestream-oob.h>
+#include <gibber/gibber-xmpp-stanza.h>
+#include <gibber/gibber-namespaces.h>
+#include <gibber/gibber-xmpp-error.h>
+#include <gibber/gibber-iq-helper.h>
+
+#include "salut-im-manager.h"
+#include "salut-muc-manager.h"
+
+#define DEBUG_FLAG DEBUG_BYTESTREAM_MGR
+#include "debug.h"
+
+G_DEFINE_TYPE (SalutBytestreamManager, salut_bytestream_manager, G_TYPE_OBJECT)
+
+/* properties */
+enum
+{
+ PROP_CONNECTION = 1,
+ PROP_HOST_NAME_FQDN,
+ LAST_PROPERTY
+};
+
+/* private structure */
+typedef struct _SalutBytestreamManagerPrivate SalutBytestreamManagerPrivate;
+
+struct _SalutBytestreamManagerPrivate
+{
+ SalutConnection *connection;
+ SalutImManager *im_manager;
+ SalutMucManager *muc_manager;
+ SalutXmppConnectionManager *xmpp_connection_manager;
+ gchar *host_name_fqdn;
+
+ gboolean dispose_has_run;
+};
+
+#define SALUT_BYTESTREAM_MANAGER_GET_PRIVATE(obj) \
+ ((SalutBytestreamManagerPrivate *) ((SalutBytestreamManager *)obj)->priv)
+
+static void
+salut_bytestream_manager_init (SalutBytestreamManager *self)
+{
+ SalutBytestreamManagerPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ SALUT_TYPE_BYTESTREAM_MANAGER, SalutBytestreamManagerPrivate);
+
+ self->priv = priv;
+
+ priv->dispose_has_run = FALSE;
+}
+
+/* Filter for SI request (XEP-0095) */
+static gboolean
+si_request_filter (SalutXmppConnectionManager *xcm,
+ GibberXmppConnection *conn,
+ GibberXmppStanza *stanza,
+ SalutContact *contact,
+ gpointer user_data)
+{
+ GibberStanzaType type;
+ GibberStanzaSubType sub_type;
+
+ gibber_xmpp_stanza_get_type_info (stanza, &type, &sub_type);
+ if (type != GIBBER_STANZA_TYPE_IQ)
+ return FALSE;
+
+ if (sub_type != GIBBER_STANZA_SUB_TYPE_SET)
+ return FALSE;
+
+ return (gibber_xmpp_node_get_child_ns (stanza->node, "si",
+ GIBBER_XMPP_NS_SI) != NULL);
+}
+
+static gboolean
+streaminit_parse_request (GibberXmppStanza *stanza,
+ const gchar **profile,
+ const gchar **from,
+ const gchar **stream_id,
+ const gchar **stream_init_id,
+ const gchar **mime_type,
+ GSList **stream_methods)
+{
+ GibberXmppNode *iq, *si, *feature, *x;
+ GSList *x_children, *field_children;
+
+ iq = stanza->node;
+
+ *stream_init_id = gibber_xmpp_node_get_attribute (iq, "id");
+
+ *from = gibber_xmpp_node_get_attribute (stanza->node, "from");
+ if (*from == NULL)
+ {
+ DEBUG ("got a message without a from field");
+ return FALSE;
+ }
+
+ /* Parse <si> */
+ si = gibber_xmpp_node_get_child_ns (iq, "si", GIBBER_XMPP_NS_SI);
+ if (si == NULL)
+ return FALSE;
+
+ *stream_id = gibber_xmpp_node_get_attribute (si, "id");
+ if (*stream_id == NULL)
+ {
+ DEBUG ("got a SI request without a stream id field");
+ return FALSE;
+ }
+
+ *mime_type = gibber_xmpp_node_get_attribute (si, "mime-type");
+ /* if no mime_type is defined, XEP-0095 says to assume "binary/octect-stream"
+ * which is presumably a typo for "application/octet-stream" */
+
+ *profile = gibber_xmpp_node_get_attribute (si, "profile");
+ if (*profile == NULL)
+ {
+ DEBUG ("got a SI request without a profile field");
+ return FALSE;
+ }
+
+ /* Parse <feature> */
+ feature = gibber_xmpp_node_get_child_ns (si, "feature",
+ GIBBER_XMPP_NS_FEATURENEG);
+ if (feature == NULL)
+ {
+ DEBUG ("got a SI request without a feature field");
+ return FALSE;
+ }
+
+ x = gibber_xmpp_node_get_child_ns (feature, "x", GIBBER_XMPP_NS_DATA);
+ if (x == NULL)
+ {
+ DEBUG ("got a SI request without a X data field");
+ return FALSE;
+ }
+
+ for (x_children = x->children; x_children;
+ x_children = g_slist_next (x_children))
+ {
+ GibberXmppNode *field = x_children->data;
+
+ if (tp_strdiff (gibber_xmpp_node_get_attribute (field, "var"),
+ "stream-method"))
+ /* some future field, ignore it */
+ continue;
+
+ if (tp_strdiff (gibber_xmpp_node_get_attribute (field, "type"),
+ "list-single"))
+ {
+ DEBUG ( "SI request's stream-method field was "
+ "not of type list-single");
+ return FALSE;
+ }
+
+ /* Get the stream methods offered */
+ *stream_methods = NULL;
+ for (field_children = field->children; field_children;
+ field_children = g_slist_next (field_children))
+ {
+ GibberXmppNode *stream_method, *value;
+ const gchar *stream_method_str;
+
+ stream_method = (GibberXmppNode *) field_children->data;
+
+ value = gibber_xmpp_node_get_child (stream_method, "value");
+ if (value == NULL)
+ continue;
+
+ stream_method_str = value->content;
+ if (!tp_strdiff (stream_method_str, ""))
+ continue;
+
+ DEBUG ("Got stream-method %s", stream_method_str);
+
+ /* Append to the stream_methods list */
+ *stream_methods = g_slist_append (*stream_methods,
+ (gchar *) stream_method_str);
+ }
+
+ /* no need to parse the rest of the fields, we've found the one we
+ * wanted */
+ break;
+ }
+
+ if (*stream_methods == NULL)
+ {
+ DEBUG ("got a SI request without stream method proposed");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+bytestream_state_changed (GibberBytestreamIface *bytestream,
+ GibberBytestreamState state,
+ SalutXmppConnectionManager *mgr)
+{
+ if (state == GIBBER_BYTESTREAM_STATE_CLOSED)
+ {
+ GibberXmppConnection *connection;
+
+ DEBUG ("bytestream closed, release the connection");
+ g_object_get (bytestream, "xmpp-connection", &connection, NULL);
+
+ salut_xmpp_connection_manager_release_connection (mgr, connection);
+
+ g_object_unref (connection);
+ g_object_unref (bytestream);
+ }
+}
+
+GibberBytestreamIface *
+choose_bytestream_method (SalutBytestreamManager *self,
+ GSList *stream_methods,
+ GibberXmppConnection *connection,
+ SalutContact *contact,
+ const gchar *stream_id,
+ const gchar *stream_init_id)
+{
+ SalutBytestreamManagerPrivate *priv =
+ SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (self);
+ GSList *l;
+
+ /* We create the stream according the stream method chosen.
+ * User has to accept it */
+
+ /* check OOB */
+ for (l = stream_methods; l != NULL; l = l->next)
+ {
+ if (!tp_strdiff (l->data, GIBBER_XMPP_NS_OOB))
+ {
+ DEBUG ("choose OOB in methods list");
+ return g_object_new (GIBBER_TYPE_BYTESTREAM_OOB,
+ "xmpp-connection", connection,
+ "stream-id", stream_id,
+ "state", GIBBER_BYTESTREAM_STATE_LOCAL_PENDING,
+ "self-id", priv->connection->name,
+ "peer-id", contact->name,
+ "stream-init-id", stream_init_id,
+ NULL);
+ }
+ }
+
+ /* check IBB */
+ for (l = stream_methods; l != NULL; l = l->next)
+ {
+ if (!tp_strdiff (l->data, GIBBER_XMPP_NS_IBB))
+ {
+ DEBUG ("choose IBB in methods list");
+ return g_object_new (GIBBER_TYPE_BYTESTREAM_IBB,
+ "xmpp-connection", connection,
+ "stream-id", stream_id,
+ "state", GIBBER_BYTESTREAM_STATE_LOCAL_PENDING,
+ "self-id", priv->connection->name,
+ "peer-id", contact->name,
+ "stream-init-id", stream_init_id,
+ NULL);
+ }
+ }
+
+ return NULL;
+}
+
+static void
+si_request_cb (SalutXmppConnectionManager *xcm,
+ GibberXmppConnection *connection,
+ GibberXmppStanza *stanza,
+ SalutContact *contact,
+ gpointer user_data)
+{
+ SalutBytestreamManager *self = SALUT_BYTESTREAM_MANAGER (user_data);
+ SalutBytestreamManagerPrivate *priv =
+ SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (self);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
+ (TpBaseConnection *) priv->connection, TP_HANDLE_TYPE_CONTACT);
+ TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
+ (TpBaseConnection *) priv->connection, TP_HANDLE_TYPE_ROOM);
+ TpHandle peer_handle;
+ GibberBytestreamIface *bytestream = NULL;
+ GibberXmppNode *si, *node;
+ const gchar *profile, *from, *stream_id, *stream_init_id, *mime_type;
+ GSList *stream_methods = NULL;
+
+ /* after this point, the message is for us, so in all cases we either handle
+ * it or send an error reply */
+
+ if (!streaminit_parse_request (stanza, &profile, &from, &stream_id,
+ &stream_init_id, &mime_type, &stream_methods))
+ {
+ GibberXmppStanza *reply;
+
+ reply = gibber_iq_helper_new_error_reply (stanza, XMPP_ERROR_BAD_REQUEST,
+ "failed to parse SI request");
+ gibber_xmpp_connection_send (connection, reply, NULL);
+
+ g_object_unref (reply);
+ return;
+ }
+
+ si = gibber_xmpp_node_get_child_ns (stanza->node, "si", GIBBER_XMPP_NS_SI);
+ g_assert (si != NULL);
+
+ DEBUG ("received a SI request");
+
+ peer_handle = tp_handle_lookup (contact_repo, from, NULL, NULL);
+ if (peer_handle == 0)
+ {
+ goto out;
+ }
+
+ /* check stream method */
+ bytestream = choose_bytestream_method (self, stream_methods, connection,
+ contact, stream_id, stream_init_id);
+
+ if (bytestream == NULL)
+ {
+ GibberXmppStanza *reply;
+
+ DEBUG ("SI request doesn't contain any supported stream method.");
+ reply = gibber_iq_helper_new_error_reply (stanza,
+ XMPP_ERROR_SI_NO_VALID_STREAMS, NULL);
+
+ gibber_xmpp_connection_send (connection, reply, NULL);
+
+ g_object_unref (reply);
+ goto out;
+ }
+
+ /* Now that we have a bytestream, it's responsible for declining the IQ
+ * if needed. */
+
+ /* As bytestreams are not XCM aware, they can't take/release
+ * the connection so we do it for them.
+ * We'll release it when the bytestream will be closed */
+ salut_xmpp_connection_manager_take_connection (priv->xmpp_connection_manager,
+ connection);
+
+ g_signal_connect (bytestream, "state-changed",
+ G_CALLBACK (bytestream_state_changed), priv->xmpp_connection_manager);
+
+ /* We inform the right manager we received a SI request */
+ if (tp_strdiff (profile, GIBBER_TELEPATHY_NS_TUBES))
+ {
+ GError e = { GIBBER_XMPP_ERROR, XMPP_ERROR_SI_BAD_PROFILE, "" };
+ DEBUG ("SI profile unsupported: %s", profile);
+
+ gibber_bytestream_iface_close (bytestream, &e);
+ goto out;
+ }
+
+ /* A Tubes SI request can be:
+ * - a 1-1 new tube offer
+ * - a 1-1 tube extra bytestream offer
+ * - a muc tube extra bytestream offer
+ */
+
+ /* TODO: implement 1-1 tubes */
+
+ node = gibber_xmpp_node_get_child_ns (si, "muc-stream",
+ GIBBER_TELEPATHY_NS_TUBES);
+ if (node != NULL)
+ {
+ const gchar *muc;
+ TpHandle room_handle;
+ SalutMucManager *muc_mgr;
+
+ muc = gibber_xmpp_node_get_attribute (node, "muc");
+ if (muc == NULL)
+ {
+ DEBUG ("muc-stream SI doesn't contain muc attribute");
+ gibber_bytestream_iface_close (bytestream, NULL);
+ goto out;
+ }
+
+ room_handle = tp_handle_lookup (room_repo, muc, NULL, NULL);
+ if (room_handle == 0)
+ {
+ DEBUG ("Unknown room: %s\n", muc);
+ gibber_bytestream_iface_close (bytestream, NULL);
+ goto out;
+ }
+
+ g_object_get (priv->connection, "muc-manager", &muc_mgr, NULL);
+ g_assert (muc_mgr != NULL);
+
+ salut_muc_manager_handle_si_stream_request (muc_mgr,
+ bytestream, room_handle, stream_id, stanza);
+ g_object_unref (muc_mgr);
+ }
+ else
+ {
+ GError e = { GIBBER_XMPP_ERROR, XMPP_ERROR_BAD_REQUEST,
+ "Invalid tube SI request: expected <tube>, <stream> or "
+ "<muc-stream>" };
+
+ DEBUG ("Invalid tube SI request");
+ gibber_bytestream_iface_close (bytestream, &e);
+ goto out;
+ }
+
+out:
+ g_slist_free (stream_methods);
+ return;
+}
+
+void
+salut_bytestream_manager_dispose (GObject *object)
+{
+ SalutBytestreamManager *self = SALUT_BYTESTREAM_MANAGER (object);
+ SalutBytestreamManagerPrivate *priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (
+ self);
+
+ if (priv->dispose_has_run)
+ return;
+
+ priv->dispose_has_run = TRUE;
+
+ g_object_unref (priv->im_manager);
+ g_object_unref (priv->muc_manager);
+ g_object_unref (priv->xmpp_connection_manager);
+
+ if (G_OBJECT_CLASS (salut_bytestream_manager_parent_class)->dispose)
+ G_OBJECT_CLASS (salut_bytestream_manager_parent_class)->dispose (object);
+}
+
+void
+salut_bytestream_manager_finalize (GObject *object)
+{
+ SalutBytestreamManager *self = SALUT_BYTESTREAM_MANAGER (object);
+ SalutBytestreamManagerPrivate *priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (
+ self);
+
+ g_free (priv->host_name_fqdn);
+
+ if (G_OBJECT_CLASS (salut_bytestream_manager_parent_class)->finalize)
+ G_OBJECT_CLASS (salut_bytestream_manager_parent_class)->finalize (object);
+}
+
+static void
+salut_bytestream_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SalutBytestreamManager *self = SALUT_BYTESTREAM_MANAGER (object);
+ SalutBytestreamManagerPrivate *priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (
+ self);
+
+ switch (property_id)
+ {
+ case PROP_CONNECTION:
+ g_value_set_object (value, priv->connection);
+ break;
+ case PROP_HOST_NAME_FQDN:
+ g_value_set_string (value, priv->host_name_fqdn);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+salut_bytestream_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SalutBytestreamManager *self = SALUT_BYTESTREAM_MANAGER (object);
+ SalutBytestreamManagerPrivate *priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (
+ self);
+
+ switch (property_id)
+ {
+ case PROP_CONNECTION:
+ priv->connection = g_value_get_object (value);
+ break;
+ case PROP_HOST_NAME_FQDN:
+ g_free (priv->host_name_fqdn);
+ priv->host_name_fqdn = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+salut_bytestream_manager_constructor (GType type,
+ guint n_props,
+ GObjectConstructParam *props)
+{
+ GObject *obj;
+ SalutBytestreamManager *self;
+ SalutBytestreamManagerPrivate *priv;
+
+ obj = G_OBJECT_CLASS (salut_bytestream_manager_parent_class)->
+ constructor (type, n_props, props);
+
+ self = SALUT_BYTESTREAM_MANAGER (obj);
+ priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (self);
+
+ g_assert (priv->connection != NULL);
+ g_object_get (priv->connection,
+ "im-manager", &(priv->im_manager),
+ "muc-manager", &(priv->muc_manager),
+ "xmpp-connection-manager", &(priv->xmpp_connection_manager),
+ NULL);
+ g_assert (priv->im_manager != NULL);
+ g_assert (priv->muc_manager != NULL);
+ g_assert (priv->xmpp_connection_manager != NULL);
+ g_assert (priv->host_name_fqdn != NULL);
+
+ salut_xmpp_connection_manager_add_stanza_filter (
+ priv->xmpp_connection_manager, NULL, si_request_filter,
+ si_request_cb, self);
+
+ return obj;
+}
+
+static void
+salut_bytestream_manager_class_init (
+ SalutBytestreamManagerClass *salut_bytestream_manager_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (salut_bytestream_manager_class);
+ GParamSpec *param_spec;
+
+ g_type_class_add_private (salut_bytestream_manager_class,
+ sizeof (SalutBytestreamManagerPrivate));
+
+ object_class->constructor = salut_bytestream_manager_constructor;
+ object_class->dispose = salut_bytestream_manager_dispose;
+ object_class->finalize = salut_bytestream_manager_finalize;
+
+ object_class->get_property = salut_bytestream_manager_get_property;
+ object_class->set_property = salut_bytestream_manager_set_property;
+
+ param_spec = g_param_spec_object (
+ "connection",
+ "SalutConnection object",
+ "Salut Connection that owns the connection for this bytestream channel",
+ SALUT_TYPE_CONNECTION,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
+
+ param_spec = g_param_spec_string (
+ "host-name-fqdn",
+ "host name FQDN",
+ "The FQDN host name that will be used by OOB bytestreams",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_HOST_NAME_FQDN,
+ param_spec);
+}
+
+SalutBytestreamManager *
+salut_bytestream_manager_new (SalutConnection *conn,
+ const gchar *host_name_fqdn)
+{
+ g_return_val_if_fail (SALUT_IS_CONNECTION (conn), NULL);
+
+ return g_object_new (
+ SALUT_TYPE_BYTESTREAM_MANAGER,
+ "connection", conn,
+ "host-name-fqdn", host_name_fqdn,
+ NULL);
+}
+
+/**
+ * salut_bytestream_manager_make_stream_init_iq
+ *
+ * @from: your contact
+ * @to: the contact to who you want to offer the stream
+ * @stream_id: the stream ID of the new stream
+ * @profile: the profile associated with the stream
+ *
+ * Create a SI request IQ as described in XEP-0095.
+ *
+ */
+GibberXmppStanza *
+salut_bytestream_manager_make_stream_init_iq (const gchar *from,
+ const gchar *to,
+ const gchar *stream_id,
+ const gchar *profile)
+{
+ return gibber_xmpp_stanza_build (
+ GIBBER_STANZA_TYPE_IQ, GIBBER_STANZA_SUB_TYPE_SET,
+ from, to,
+ GIBBER_NODE, "si",
+ GIBBER_NODE_XMLNS, GIBBER_XMPP_NS_SI,
+ GIBBER_NODE_ATTRIBUTE, "id", stream_id,
+ GIBBER_NODE_ATTRIBUTE, "profile", profile,
+ GIBBER_NODE_ATTRIBUTE, "mime-type", "binary/octect-stream",
+ GIBBER_NODE, "feature",
+ GIBBER_NODE_XMLNS, GIBBER_XMPP_NS_FEATURENEG,
+ GIBBER_NODE, "x",
+ GIBBER_NODE_XMLNS, GIBBER_XMPP_NS_DATA,
+ GIBBER_NODE_ATTRIBUTE, "type", "form",
+ GIBBER_NODE, "field",
+ GIBBER_NODE_ATTRIBUTE, "var", "stream-method",
+ GIBBER_NODE_ATTRIBUTE, "type", "list-single",
+
+ GIBBER_NODE, "option",
+ GIBBER_NODE, "value",
+ GIBBER_NODE_TEXT, GIBBER_XMPP_NS_OOB,
+ GIBBER_NODE_END,
+ GIBBER_NODE_END,
+
+ GIBBER_NODE, "option",
+ GIBBER_NODE, "value",
+ GIBBER_NODE_TEXT, GIBBER_XMPP_NS_IBB,
+ GIBBER_NODE_END,
+ GIBBER_NODE_END,
+
+ GIBBER_NODE_END,
+ GIBBER_NODE_END,
+ GIBBER_NODE_END,
+ GIBBER_NODE_END, GIBBER_STANZA_END);
+}
+
+struct streaminit_reply_cb_data
+{
+ SalutBytestreamManager *self;
+ gchar *stream_id;
+ SalutBytestreamManagerNegotiateReplyFunc func;
+ gpointer user_data;
+ gchar *iq_id;
+ SalutContact *contact;
+ GibberXmppStanza *stanza;
+};
+
+static struct streaminit_reply_cb_data *
+streaminit_reply_cb_data_new (void)
+{
+ return g_slice_new0 (struct streaminit_reply_cb_data);
+}
+
+static void
+streaminit_reply_cb_data_free (struct streaminit_reply_cb_data *data)
+{
+ g_free (data->stream_id);
+ g_free (data->iq_id);
+
+ if (data->contact != NULL)
+ g_object_unref (data->contact);
+
+ if (data->stanza != NULL)
+ g_object_unref (data->stanza);
+
+ g_slice_free (struct streaminit_reply_cb_data, data);
+}
+
+static gboolean
+si_request_reply_filter (SalutXmppConnectionManager *manager,
+ GibberXmppConnection *connection,
+ GibberXmppStanza *stanza,
+ SalutContact *contact,
+ gpointer user_data)
+{
+ struct streaminit_reply_cb_data *data =
+ (struct streaminit_reply_cb_data *) user_data;
+ GibberStanzaType type;
+ GibberStanzaSubType sub_type;
+ const gchar *iq_id;
+
+ gibber_xmpp_stanza_get_type_info (stanza, &type, &sub_type);
+ if (type != GIBBER_STANZA_TYPE_IQ)
+ return FALSE;
+
+ if (sub_type != GIBBER_STANZA_SUB_TYPE_RESULT &&
+ sub_type != GIBBER_STANZA_SUB_TYPE_ERROR)
+ return FALSE;
+
+ iq_id = gibber_xmpp_node_get_attribute (stanza->node, "id");
+ return (!tp_strdiff (iq_id, data->iq_id));
+}
+
+static gboolean
+check_bytestream_oob_peer_addr (GibberBytestreamOOB *bytestream,
+ struct sockaddr *addr,
+ socklen_t addrlen,
+ gpointer user_data)
+{
+ SalutBytestreamManager *self = SALUT_BYTESTREAM_MANAGER (user_data);
+ SalutBytestreamManagerPrivate *priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (
+ self);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
+ (TpBaseConnection *) priv->connection, TP_HANDLE_TYPE_CONTACT);
+ TpHandle handle;
+ SalutContactManager *contact_mgr;
+ SalutContact *contact;
+ gchar *peer;
+ gboolean result;
+
+ g_object_get (bytestream, "peer-id", &peer, NULL);
+ g_assert (peer != NULL);
+
+ handle = tp_handle_lookup (contact_repo, peer, NULL, NULL);
+ g_assert (handle != 0);
+ g_free (peer);
+
+ g_object_get (priv->connection, "contact-manager", &contact_mgr, NULL);
+ g_assert (contact_mgr != NULL);
+
+ contact = salut_contact_manager_get_contact (contact_mgr, handle);
+ g_object_unref (contact_mgr);
+ if (contact == NULL)
+ return FALSE;
+
+ result = salut_contact_has_address (contact, addr, addrlen);
+ g_object_unref (contact);
+
+ return result;
+}
+
+static void
+si_request_reply_cb (SalutXmppConnectionManager *manager,
+ GibberXmppConnection *connection,
+ GibberXmppStanza *stanza,
+ SalutContact *contact,
+ gpointer user_data)
+{
+ struct streaminit_reply_cb_data *data =
+ (struct streaminit_reply_cb_data *) user_data;
+ SalutBytestreamManagerPrivate *priv =
+ SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (data->self);
+ GibberStanzaSubType sub_type;
+ GibberXmppNode *si, *feature, *x;
+ GibberBytestreamIface *bytestream = NULL;
+ const gchar *from, *stream_method, *stream_init_id;
+ GSList *x_children;
+
+ salut_xmpp_connection_manager_remove_stanza_filter (
+ manager, connection, si_request_reply_filter, si_request_reply_cb, data);
+
+ DEBUG ("received SI request response");
+
+ gibber_xmpp_stanza_get_type_info (stanza, NULL, &sub_type);
+ if (sub_type != GIBBER_STANZA_SUB_TYPE_RESULT)
+ {
+ DEBUG ("stream %s declined", data->stream_id);
+ goto END;
+ }
+
+ /* stream accepted */
+ stream_init_id = gibber_xmpp_node_get_attribute (stanza->node, "id");
+
+ from = gibber_xmpp_node_get_attribute (stanza->node, "from");
+ if (from == NULL)
+ {
+ DEBUG ("got a message without a from field");
+ goto END;
+ }
+
+ si = gibber_xmpp_node_get_child_ns (stanza->node, "si",
+ GIBBER_XMPP_NS_SI);
+ if (si == NULL)
+ {
+ DEBUG ("got a SI reply without a si field");
+ goto END;
+ }
+
+ feature = gibber_xmpp_node_get_child_ns (si, "feature",
+ GIBBER_XMPP_NS_FEATURENEG);
+ if (feature == NULL)
+ {
+ DEBUG ("got a SI reply without a feature field");
+ goto END;
+ }
+
+ x = gibber_xmpp_node_get_child_ns (feature, "x", GIBBER_XMPP_NS_DATA);
+ if (x == NULL)
+ {
+ DEBUG ("got a SI reply without a x field");
+ goto END;
+ }
+
+ for (x_children = x->children; x_children;
+ x_children = g_slist_next (x_children))
+ {
+ GibberXmppNode *value, *field = x_children->data;
+
+ if (tp_strdiff (gibber_xmpp_node_get_attribute (field, "var"),
+ "stream-method"))
+ /* some future field, ignore it */
+ continue;
+
+ value = gibber_xmpp_node_get_child (field, "value");
+ if (value == NULL)
+ {
+ DEBUG ("SI reply's stream-method field "
+ "doesn't contain stream-method value");
+ goto END;
+ }
+
+ stream_method = value->content;
+
+ if (!tp_strdiff (stream_method, GIBBER_XMPP_NS_OOB))
+ {
+ /* Remote user have accepted the stream */
+ DEBUG ("remote user chose a OOB bytestream");
+ bytestream = g_object_new (GIBBER_TYPE_BYTESTREAM_OOB,
+ "xmpp-connection", connection,
+ "stream-id", data->stream_id,
+ "state", GIBBER_BYTESTREAM_STATE_INITIATING,
+ "self-id", priv->connection->name,
+ "peer-id", from,
+ "stream-init-id", NULL,
+ "host", priv->host_name_fqdn,
+ NULL);
+ gibber_bytestream_oob_set_check_addr_func (
+ GIBBER_BYTESTREAM_OOB (bytestream), check_bytestream_oob_peer_addr,
+ data->self);
+ }
+ else if (!tp_strdiff (stream_method, GIBBER_XMPP_NS_IBB))
+ {
+ /* Remote user have accepted the stream */
+ DEBUG ("remote user chose a IBB bytestream");
+ bytestream = g_object_new (GIBBER_TYPE_BYTESTREAM_IBB,
+ "xmpp-connection", connection,
+ "stream-id", data->stream_id,
+ "state", GIBBER_BYTESTREAM_STATE_INITIATING,
+ "self-id", priv->connection->name,
+ "peer-id", from,
+ "stream-init-id", NULL,
+ NULL);
+ }
+ else
+ {
+ DEBUG ("Remote user chose an unsupported stream method");
+ goto END;
+ }
+
+ /* no need to parse the rest of the fields, we've found the one we
+ * wanted */
+ break;
+
+ }
+
+ if (bytestream == NULL)
+ goto END;
+
+ DEBUG ("stream %s accepted. Start to initiate it", data->stream_id);
+
+ /* As bytestreams are not XCM aware, they can't take/release
+ * the connection so we do it for them.
+ * We'll release it when the bytestream will be closed */
+ salut_xmpp_connection_manager_take_connection (priv->xmpp_connection_manager,
+ connection);
+
+ g_signal_connect (bytestream, "state-changed",
+ G_CALLBACK (bytestream_state_changed), priv->xmpp_connection_manager);
+
+ /* Let's start the initiation of the stream */
+ if (!gibber_bytestream_iface_initiate (bytestream))
+ {
+ /* Initiation failed. */
+ gibber_bytestream_iface_close (bytestream, NULL);
+ bytestream = NULL;
+ }
+
+END:
+ /* user callback */
+ data->func (bytestream, data->stream_id, stanza,
+ data->user_data);
+
+ streaminit_reply_cb_data_free (data);
+}
+
+static gboolean
+send_si_request (SalutBytestreamManager *self,
+ GibberXmppConnection *connection,
+ struct streaminit_reply_cb_data *data,
+ GError **error)
+{
+ SalutBytestreamManagerPrivate *priv =
+ SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (self);
+ const gchar *iq_id;
+
+ iq_id = gibber_xmpp_node_get_attribute (data->stanza->node, "id");
+ if (iq_id != NULL)
+ {
+ data->iq_id = g_strdup (iq_id);
+ }
+ else
+ {
+ data->iq_id = gibber_xmpp_connection_new_id (connection);
+ gibber_xmpp_node_set_attribute (data->stanza->node, "id", data->iq_id);
+ }
+
+ /* Register a filter to catch the response of the SI request */
+ salut_xmpp_connection_manager_add_stanza_filter (
+ priv->xmpp_connection_manager, connection,
+ si_request_reply_filter, si_request_reply_cb, data);
+
+ /* FIXME: set a timer ?
+ * Or we could listen for the XMPP connection closed signal and so use
+ * XCM's timer as we didn't ref the connection yet */
+ if (!gibber_xmpp_connection_send (connection, data->stanza, error))
+ {
+ salut_xmpp_connection_manager_remove_stanza_filter (
+ priv->xmpp_connection_manager, connection,
+ si_request_reply_filter, si_request_reply_cb, data);
+
+ streaminit_reply_cb_data_free (data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+xmpp_connection_manager_new_connection_cb (SalutXmppConnectionManager *mgr,
+ GibberXmppConnection *connection,
+ SalutContact *contact,
+ gpointer user_data)
+{
+ struct streaminit_reply_cb_data *data =
+ (struct streaminit_reply_cb_data *) user_data;
+
+ if (data->contact != contact)
+ /* Not the connection we are waiting for */
+ return;
+
+ DEBUG ("got connection with %s. Send SI request", contact->name);
+ send_si_request (data->self, connection, data, NULL);
+
+ g_signal_handlers_disconnect_matched (mgr, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
+ NULL, data);
+}
+
+static void
+xmpp_connection_manager_connection_failed_cb (SalutXmppConnectionManager *mgr,
+ GibberXmppConnection *connection,
+ SalutContact *contact,
+ GQuark domain,
+ gint code,
+ gchar *message,
+ gpointer user_data)
+{
+ struct streaminit_reply_cb_data *data =
+ (struct streaminit_reply_cb_data *) user_data;
+
+ if (data->contact != contact)
+ /* Not the connection we are waiting for */
+ return;
+
+ DEBUG ("connection with %s failed: %s. Can't send SI request", contact->name,
+ message);
+
+ /* Call the user callback without bytestream to inform him the SI request
+ * failed */
+ data->func (NULL, data->stream_id, NULL,
+ data->user_data);
+
+ g_signal_handlers_disconnect_matched (mgr, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
+ NULL, data);
+ streaminit_reply_cb_data_free (data);
+}
+
+/*
+ * salut_bytestream_manager_negotiate_stream:
+ *
+ * @contact: the contact to who send the SI request
+ * @stanza: the SI negotiation IQ (created using
+ * salut_bytestream_manager_make_stream_init_iq)
+ * @stream_id: the stream identifier
+ * @func: the callback to call when we receive the answser of the request
+ * @user_data: user data to pass to the callback
+ * @error: pointer in which to return a GError in case of failure.
+ *
+ * Send a Stream Initiation (XEP-0095) request.
+ */
+gboolean
+salut_bytestream_manager_negotiate_stream (SalutBytestreamManager *self,
+ SalutContact *contact,
+ GibberXmppStanza *stanza,
+ const gchar *stream_id,
+ SalutBytestreamManagerNegotiateReplyFunc func,
+ gpointer user_data,
+ GError **error)
+{
+ SalutBytestreamManagerPrivate *priv;
+ struct streaminit_reply_cb_data *data;
+ GibberXmppConnection *connection = NULL;
+ SalutXmppConnectionManagerRequestConnectionResult request_result;
+
+ g_assert (SALUT_IS_BYTESTREAM_MANAGER (self));
+ g_assert (stream_id != NULL);
+ g_assert (func != NULL);
+
+ priv = SALUT_BYTESTREAM_MANAGER_GET_PRIVATE (self);
+
+ data = streaminit_reply_cb_data_new ();
+ data->self = self;
+ data->stream_id = g_strdup (stream_id);
+ data->func = func;
+ data->user_data = user_data;
+ data->contact = g_object_ref (contact);
+ data->stanza = g_object_ref (stanza);
+
+ DEBUG ("request XMPP connection with %s to send the SI request",
+ contact->name);
+
+ /* We need a XMPP connection to send the SI request */
+ request_result = salut_xmpp_connection_manager_request_connection (
+ priv->xmpp_connection_manager, contact, &connection, error);
+
+ if (request_result ==
+ SALUT_XMPP_CONNECTION_MANAGER_REQUEST_CONNECTION_RESULT_DONE)
+ {
+ DEBUG ("got the connection with %s, send the SI request",
+ data->contact->name);
+
+ return send_si_request (self, connection, data, error);
+ }
+ else if (request_result ==
+ SALUT_XMPP_CONNECTION_MANAGER_REQUEST_CONNECTION_RESULT_PENDING)
+ {
+ DEBUG ("connection with %s pending. Wait before send the SI request",
+ contact->name);
+
+ g_signal_connect (priv->xmpp_connection_manager, "new-connection",
+ G_CALLBACK (xmpp_connection_manager_new_connection_cb), data);
+ g_signal_connect (priv->xmpp_connection_manager, "connection-failed",
+ G_CALLBACK (xmpp_connection_manager_connection_failed_cb), data);
+
+ return TRUE;
+ }
+ else
+ {
+ DEBUG ("can't request connection with %s", contact->name);
+ streaminit_reply_cb_data_free (data);
+ return FALSE;
+ }
+}
diff --git a/src/salut-si-bytestream-manager.h b/src/salut-si-bytestream-manager.h
new file mode 100644
index 0000000..e641995
--- /dev/null
+++ b/src/salut-si-bytestream-manager.h
@@ -0,0 +1,83 @@
+/*
+ * salut-bytestream-manager.h - Header for SalutBytestreamManager
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * 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 __SALUT_BYTESTREAM_MANAGER_H__
+#define __SALUT_BYTESTREAM_MANAGER_H__
+
+#include <glib-object.h>
+#include "salut-xmpp-connection-manager.h"
+#include "salut-contact.h"
+
+#include <gibber/gibber-linklocal-transport.h>
+#include <gibber/gibber-bytestream-iface.h>
+
+G_BEGIN_DECLS
+
+typedef struct _SalutBytestreamManager SalutBytestreamManager;
+typedef struct _SalutBytestreamManagerClass SalutBytestreamManagerClass;
+
+struct _SalutBytestreamManagerClass {
+ GObjectClass parent_class;
+};
+
+struct _SalutBytestreamManager {
+ GObject parent;
+
+ gpointer priv;
+};
+
+
+GType salut_bytestream_manager_get_type (void);
+
+/* TYPE MACROS */
+#define SALUT_TYPE_BYTESTREAM_MANAGER \
+ (salut_bytestream_manager_get_type ())
+#define SALUT_BYTESTREAM_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), SALUT_TYPE_BYTESTREAM_MANAGER, \
+ SalutBytestreamManager))
+#define SALUT_BYTESTREAM_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), SALUT_TYPE_BYTESTREAM_MANAGER, \
+ SalutBytestreamManagerClass))
+#define SALUT_IS_BYTESTREAM_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), SALUT_TYPE_BYTESTREAM_MANAGER))
+#define SALUT_IS_BYTESTREAM_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), SALUT_TYPE_BYTESTREAM_MANAGER))
+#define SALUT_BYTESTREAM_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), SALUT_TYPE_BYTESTREAM_MANAGER, \
+ SalutBytestreamManagerClass))
+
+typedef void (* SalutBytestreamManagerNegotiateReplyFunc) (
+ GibberBytestreamIface *bytestream, const gchar *stream_id,
+ GibberXmppStanza *stanza, gpointer user_data);
+
+SalutBytestreamManager *
+salut_bytestream_manager_new (SalutConnection *connection,
+ const gchar *host_name_fqdn);
+
+GibberXmppStanza *
+salut_bytestream_manager_make_stream_init_iq (const gchar *from,
+ const gchar *to, const gchar *stream_id, const gchar *profile);
+
+gboolean
+salut_bytestream_manager_negotiate_stream (SalutBytestreamManager *self,
+ SalutContact *contact, GibberXmppStanza *stanza, const gchar *stream_id,
+ SalutBytestreamManagerNegotiateReplyFunc func, gpointer user_data,
+ GError **error);
+
+#endif /* #ifndef __SALUT_BYTESTREAM_MANAGER_H__*/
diff --git a/src/tube-stream.c b/src/tube-stream.c
index b855cf4..07d328b 100644
--- a/src/tube-stream.c
+++ b/src/tube-stream.c
@@ -46,7 +46,7 @@
#include "signals-marshal.h"
#include "salut-connection.h"
#include "tube-iface.h"
-#include "salut-bytestream-manager.h"
+#include "salut-si-bytestream-manager.h"
#include "salut-contact-manager.h"
static void
--
1.5.6.5
More information about the Telepathy-commits
mailing list