maiku.vv: a4aa548f: Restructure Jingle code to more easily s...
maiku at soc.pidgin.im
maiku at soc.pidgin.im
Sun Oct 19 01:13:03 EDT 2008
-----------------------------------------------------------------
Revision: a4aa548f12b557cc419b1567e6902eb124d0cf06
Ancestor: 33c389f28f8fbefb95f7cf1bc22730ffd1d92bcb
Author: maiku at soc.pidgin.im
Date: 2008-10-19T04:37:23
Branch: im.pidgin.maiku.vv
URL: http://d.pidgin.im/viewmtn/revision/info/a4aa548f12b557cc419b1567e6902eb124d0cf06
Renamed entries:
libpurple/protocols/jabber/jingle.c to libpurple/protocols/jabber/jingle/jingle.c
libpurple/protocols/jabber/jingle.h to libpurple/protocols/jabber/jingle/jingle.h
Added files:
libpurple/protocols/jabber/jingle/content.c
libpurple/protocols/jabber/jingle/content.h
libpurple/protocols/jabber/jingle/session.c
libpurple/protocols/jabber/jingle/session.h
libpurple/protocols/jabber/jingle/transport.c
libpurple/protocols/jabber/jingle/transport.h
Added directories:
libpurple/protocols/jabber/jingle
Modified files:
libpurple/marshallers.list libpurple/media.c
libpurple/media.h libpurple/mediamanager.h
libpurple/protocols/jabber/Makefile.am
libpurple/protocols/jabber/Makefile.mingw
libpurple/protocols/jabber/disco.c
libpurple/protocols/jabber/iq.c
libpurple/protocols/jabber/jabber.c
libpurple/protocols/jabber/jabber.h
libpurple/protocols/jabber/jingle/jingle.c
libpurple/protocols/jabber/jingle/jingle.h pidgin/gtkconv.c
pidgin/gtkmedia.c
ChangeLog:
Restructure Jingle code to more easily support multiple application types.
Actually negotiate a rawudp transport rather than pretending to use iceudp.
-------------- next part --------------
============================================================
--- libpurple/protocols/jabber/jingle/content.c 01b3233f21296d737dddacfa12fe1162c9cfeee8
+++ libpurple/protocols/jabber/jingle/content.c 01b3233f21296d737dddacfa12fe1162c9cfeee8
@@ -0,0 +1,455 @@
+/**
+ * @file content.c
+ *
+ * purple
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "config.h"
+#include "debug.h"
+#include "content.h"
+#include "jingle.h"
+
+#include <string.h>
+
+struct _JingleContentPrivate
+{
+ JingleSession *session;
+ gchar *description_type;
+ gchar *creator;
+ gchar *disposition;
+ gchar *name;
+ gchar *senders;
+ JingleTransport *transport;
+ JingleTransport *pending_transport;
+};
+
+#define JINGLE_CONTENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), JINGLE_TYPE_CONTENT, JingleContentPrivate))
+
+static void jingle_content_class_init (JingleContentClass *klass);
+static void jingle_content_init (JingleContent *content);
+static void jingle_content_finalize (GObject *object);
+static void jingle_content_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void jingle_content_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static xmlnode *jingle_content_to_xml_internal(JingleContent *content, xmlnode *jingle, JingleActionType action);
+static JingleContent *jingle_content_parse_internal(xmlnode *content);
+
+static GObjectClass *parent_class = NULL;
+
+enum {
+ PROP_0,
+ PROP_SESSION,
+ PROP_CREATOR,
+ PROP_DISPOSITION,
+ PROP_NAME,
+ PROP_SENDERS,
+ PROP_TRANSPORT,
+ PROP_PENDING_TRANSPORT,
+};
+
+GType
+jingle_content_get_type()
+{
+ static GType type = 0;
+
+ if (type == 0) {
+ static const GTypeInfo info = {
+ sizeof(JingleContentClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) jingle_content_class_init,
+ NULL,
+ NULL,
+ sizeof(JingleContent),
+ 0,
+ (GInstanceInitFunc) jingle_content_init,
+ NULL
+ };
+ type = g_type_register_static(G_TYPE_OBJECT, "JingleContent", &info, 0);
+ }
+ return type;
+}
+
+static void
+jingle_content_class_init (JingleContentClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass*)klass;
+ parent_class = g_type_class_peek_parent(klass);
+
+ gobject_class->finalize = jingle_content_finalize;
+ gobject_class->set_property = jingle_content_set_property;
+ gobject_class->get_property = jingle_content_get_property;
+ klass->to_xml = jingle_content_to_xml_internal;
+ klass->parse = jingle_content_parse_internal;
+
+ g_object_class_install_property(gobject_class, PROP_SESSION,
+ g_param_spec_object("session",
+ "Jingle Session",
+ "The jingle session parent of this content.",
+ JINGLE_TYPE_SESSION,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property(gobject_class, PROP_CREATOR,
+ g_param_spec_string("creator",
+ "Creator",
+ "The participant that created this content.",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+ g_object_class_install_property(gobject_class, PROP_DISPOSITION,
+ g_param_spec_string("disposition",
+ "Disposition",
+ "The disposition of the content.",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+ g_object_class_install_property(gobject_class, PROP_NAME,
+ g_param_spec_string("name",
+ "Name",
+ "The name of this content.",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+ g_object_class_install_property(gobject_class, PROP_SENDERS,
+ g_param_spec_string("senders",
+ "Senders",
+ "The sender of this content.",
+ NULL,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+ g_object_class_install_property(gobject_class, PROP_TRANSPORT,
+ g_param_spec_object("transport",
+ "transport",
+ "The transport of this content.",
+ JINGLE_TYPE_TRANSPORT,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+ g_object_class_install_property(gobject_class, PROP_PENDING_TRANSPORT,
+ g_param_spec_object("pending-transport",
+ "Pending transport",
+ "The pending transport contained within this content",
+ JINGLE_TYPE_TRANSPORT,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private(klass, sizeof(JingleContentPrivate));
+}
+
+static void
+jingle_content_init (JingleContent *content)
+{
+ content->priv = JINGLE_CONTENT_GET_PRIVATE(content);
+ memset(content->priv, 0, sizeof(content->priv));
+}
+
+static void
+jingle_content_finalize (GObject *content)
+{
+ JingleContentPrivate *priv = JINGLE_CONTENT_GET_PRIVATE(content);
+ purple_debug_info("jingle","jingle_content_finalize\n");
+
+ g_free(priv->description_type);
+ g_free(priv->creator);
+ g_free(priv->disposition);
+ g_free(priv->name);
+ g_free(priv->senders);
+ g_object_unref(priv->transport);
+ if (priv->pending_transport)
+ g_object_unref(priv->pending_transport);
+
+ parent_class->finalize(content);
+}
+
+static void
+jingle_content_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ JingleContent *content;
+ g_return_if_fail(JINGLE_IS_CONTENT(object));
+
+ content = JINGLE_CONTENT(object);
+
+ switch (prop_id) {
+ case PROP_SESSION:
+ content->priv->session = g_value_get_object(value);
+ break;
+ case PROP_CREATOR:
+ g_free(content->priv->creator);
+ content->priv->creator = g_value_dup_string(value);
+ break;
+ case PROP_DISPOSITION:
+ g_free(content->priv->disposition);
+ content->priv->disposition = g_value_dup_string(value);
+ break;
+ case PROP_NAME:
+ g_free(content->priv->name);
+ content->priv->name = g_value_dup_string(value);
+ break;
+ case PROP_SENDERS:
+ g_free(content->priv->senders);
+ content->priv->senders = g_value_dup_string(value);
+ break;
+ case PROP_TRANSPORT:
+ if (content->priv->transport)
+ g_object_unref(content->priv->transport);
+ content->priv->transport = g_value_get_object(value);
+ g_object_ref(content->priv->transport);
+ break;
+ case PROP_PENDING_TRANSPORT:
+ if (content->priv->pending_transport)
+ g_object_unref(content->priv->pending_transport);
+ content->priv->pending_transport = g_value_get_object(value);
+ g_object_ref(content->priv->pending_transport);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+jingle_content_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ JingleContent *content;
+ g_return_if_fail(JINGLE_IS_CONTENT(object));
+
+ content = JINGLE_CONTENT(object);
+
+ switch (prop_id) {
+ case PROP_SESSION:
+ g_value_set_object(value, content->priv->session);
+ break;
+ case PROP_CREATOR:
+ g_value_set_string(value, content->priv->creator);
+ break;
+ case PROP_DISPOSITION:
+ g_value_set_string(value, content->priv->disposition);
+ break;
+ case PROP_NAME:
+ g_value_set_string(value, content->priv->name);
+ break;
+ case PROP_SENDERS:
+ g_value_set_string(value, content->priv->senders);
+ break;
+ case PROP_TRANSPORT:
+ g_value_set_object(value, content->priv->transport);
+ break;
+ case PROP_PENDING_TRANSPORT:
+ g_value_set_object(value, content->priv->pending_transport);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+JingleContent *
+jingle_content_create(const gchar *type, const gchar *creator,
+ const gchar *disposition, const gchar *name,
+ const gchar *senders, JingleTransport *transport)
+{
+
+
+ JingleContent *content = g_object_new(jingle_get_type(type),
+ "creator", creator,
+ "disposition", disposition != NULL ? disposition : "session",
+ "name", name,
+ "senders", senders != NULL ? senders : "both",
+ "transport", transport,
+ NULL);
+ return content;
+}
+
+JingleSession *jingle_content_get_session(JingleContent *content)
+{
+ JingleSession *session;
+ g_object_get(content, "session", &session, NULL);
+ return session;
+}
+
+const gchar *
+jingle_content_get_description_type(JingleContent *content)
+{
+ return JINGLE_CONTENT_GET_CLASS(content)->description_type;
+}
+
+gchar *
+jingle_content_get_creator(JingleContent *content)
+{
+ gchar *creator;
+ g_object_get(content, "creator", &creator, NULL);
+ return creator;
+}
+
+gchar *
+jingle_content_get_disposition(JingleContent *content)
+{
+ gchar *disposition;
+ g_object_get(content, "disposition", &disposition, NULL);
+ return disposition;
+}
+
+gchar *
+jingle_content_get_name(JingleContent *content)
+{
+ gchar *name;
+ g_object_get(content, "name", &name, NULL);
+ return name;
+}
+
+gchar *
+jingle_content_get_senders(JingleContent *content)
+{
+ gchar *senders;
+ g_object_get(content, "senders", &senders, NULL);
+ return senders;
+}
+
+JingleTransport *
+jingle_content_get_transport(JingleContent *content)
+{
+ JingleTransport *transport;
+ g_object_get(content, "transport", &transport, NULL);
+ return transport;
+}
+
+void
+jingle_content_set_session(JingleContent *content, JingleSession *session)
+{
+ JINGLE_IS_CONTENT(content);
+ JINGLE_IS_SESSION(session);
+ g_object_set(content, "session", session, NULL);
+}
+
+JingleTransport *
+jingle_content_get_pending_transport(JingleContent *content)
+{
+ JingleTransport *pending_transport;
+ g_object_get(content, "pending_transport", &pending_transport, NULL);
+ return pending_transport;
+}
+
+void
+jingle_content_set_pending_transport(JingleContent *content, JingleTransport *transport)
+{
+ g_object_set(content, "pending-transport", transport, NULL);
+}
+
+void
+jingle_content_accept_transport(JingleContent *content)
+{
+ if (content->priv->transport)
+ g_object_unref(content->priv->transport);
+ content->priv->transport = content->priv->pending_transport;
+ content->priv->pending_transport = NULL;
+}
+
+void
+jingle_content_remove_pending_transport(JingleContent *content)
+{
+ if (content->priv->pending_transport) {
+ g_object_unref(content->priv->pending_transport);
+ content->priv->pending_transport = NULL;
+ }
+}
+
+void
+jingle_content_modify(JingleContent *content, const gchar *senders)
+{
+ g_object_set(content, "senders", senders, NULL);
+}
+
+static JingleContent *
+jingle_content_parse_internal(xmlnode *content)
+{
+ xmlnode *description = xmlnode_get_child(content, "description");
+ const gchar *type = xmlnode_get_namespace(description);
+ const gchar *creator = xmlnode_get_attrib(content, "creator");
+ const gchar *disposition = xmlnode_get_attrib(content, "disposition");
+ const gchar *senders = xmlnode_get_attrib(content, "senders");
+ const gchar *name = xmlnode_get_attrib(content, "name");
+ JingleTransport *transport =
+ jingle_transport_parse(xmlnode_get_child(content, "transport"));
+
+ if (senders == NULL)
+ senders = "both";
+
+ return jingle_content_create(type, creator, disposition, name, senders, transport);
+}
+
+JingleContent *
+jingle_content_parse(xmlnode *content)
+{
+ const gchar *type = xmlnode_get_namespace(xmlnode_get_child(content, "description"));
+ return JINGLE_CONTENT_CLASS(g_type_class_ref(jingle_get_type(type)))->parse(content);
+}
+
+static xmlnode *
+jingle_content_to_xml_internal(JingleContent *content, xmlnode *jingle, JingleActionType action)
+{
+ xmlnode *node = xmlnode_new_child(jingle, "content");
+ gchar *creator = jingle_content_get_creator(content);
+ gchar *name = jingle_content_get_name(content);
+ gchar *senders = jingle_content_get_senders(content);
+ gchar *disposition = jingle_content_get_disposition(content);
+
+ xmlnode_set_attrib(node, "creator", creator);
+ xmlnode_set_attrib(node, "name", name);
+ xmlnode_set_attrib(node, "senders", senders);
+ if (strcmp("session", disposition))
+ xmlnode_set_attrib(node, "disposition", disposition);
+
+ g_free(disposition);
+ g_free(senders);
+ g_free(name);
+ g_free(creator);
+
+ if (action != JINGLE_CONTENT_REMOVE) {
+ JingleTransport *transport;
+
+ if (action != JINGLE_TRANSPORT_ACCEPT &&
+ action != JINGLE_TRANSPORT_INFO &&
+ action != JINGLE_TRANSPORT_REJECT &&
+ action != JINGLE_TRANSPORT_REPLACE) {
+ xmlnode *description = xmlnode_new_child(node, "description");
+
+ xmlnode_set_namespace(description,
+ jingle_content_get_description_type(content));
+ }
+
+ if (action != JINGLE_TRANSPORT_REJECT && action == JINGLE_TRANSPORT_REPLACE)
+ transport = jingle_content_get_pending_transport(content);
+ else
+ transport = jingle_content_get_transport(content);
+
+ jingle_transport_to_xml(transport, node, action);
+ }
+
+ return node;
+}
+
+xmlnode *
+jingle_content_to_xml(JingleContent *content, xmlnode *jingle, JingleActionType action)
+{
+ g_return_val_if_fail(JINGLE_IS_CONTENT(content), NULL);
+ return JINGLE_CONTENT_GET_CLASS(content)->to_xml(content, jingle, action);
+}
+
+void
+jingle_content_handle_action(JingleContent *content, xmlnode *jingle, JingleActionType action)
+{
+ g_return_if_fail(JINGLE_IS_CONTENT(content));
+ JINGLE_CONTENT_GET_CLASS(content)->handle_action(content, jingle, action);
+}
+
============================================================
--- libpurple/protocols/jabber/jingle/content.h 4ffbaaf6762b87423a3abe7200e4bb8e3a82d850
+++ libpurple/protocols/jabber/jingle/content.h 4ffbaaf6762b87423a3abe7200e4bb8e3a82d850
@@ -0,0 +1,117 @@
+/**
+ * @file content.h
+ *
+ * purple
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef JINGLE_CONTENT_H
+#define JINGLE_CONTENT_H
+
+
+#include "jabber.h"
+#include "jingle.h"
+#include "session.h"
+#include "transport.h"
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define JINGLE_TYPE_CONTENT (jingle_content_get_type())
+#define JINGLE_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), JINGLE_TYPE_CONTENT, JingleContent))
+#define JINGLE_CONTENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), JINGLE_TYPE_CONTENT, JingleContentClass))
+#define JINGLE_IS_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), JINGLE_TYPE_CONTENT))
+#define JINGLE_IS_CONTENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), JINGLE_TYPE_CONTENT))
+#define JINGLE_CONTENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), JINGLE_TYPE_CONTENT, JingleContentClass))
+
+/** @copydoc _JingleContent */
+typedef struct _JingleContent JingleContent;
+/** @copydoc _JingleContentClass */
+typedef struct _JingleContentClass JingleContentClass;
+/** @copydoc _JingleContentPrivate */
+typedef struct _JingleContentPrivate JingleContentPrivate;
+
+/** The content class */
+struct _JingleContentClass
+{
+ GObjectClass parent_class; /**< The parent class. */
+
+ xmlnode *(*to_xml) (JingleContent *content, xmlnode *jingle, JingleActionType action);
+ JingleContent *(*parse) (xmlnode *content);
+ void (*handle_action) (JingleContent *content, xmlnode *jingle, JingleActionType action);
+ const gchar *description_type;
+};
+
+/** The content class's private data */
+struct _JingleContent
+{
+ GObject parent; /**< The parent of this object. */
+ JingleContentPrivate *priv; /**< The private data of this object. */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Gets the content class's GType
+ *
+ * @return The content class's GType.
+ */
+GType jingle_content_get_type(void);
+
+JingleContent *jingle_content_create(const gchar *type, const gchar *creator,
+ const gchar *disposition, const gchar *name,
+ const gchar *senders, JingleTransport *transport);
+
+JingleSession *jingle_content_get_session(JingleContent *content);
+const gchar *jingle_content_get_description_type(JingleContent *content);
+gchar *jingle_content_get_creator(JingleContent *content);
+gchar *jingle_content_get_disposition(JingleContent *content);
+gchar *jingle_content_get_name(JingleContent *content);
+gchar *jingle_content_get_senders(JingleContent *content);
+JingleTransport *jingle_content_get_transport(JingleContent *content);
+JingleTransport *jingle_content_get_pending_transport(JingleContent *content);
+
+void jingle_content_set_session(JingleContent *content, JingleSession *session);
+void jingle_content_set_pending_transport(JingleContent *content, JingleTransport *transport);
+void jingle_content_accept_transport(JingleContent *content);
+void jingle_content_remove_pending_transport(JingleContent *content);
+void jingle_content_modify(JingleContent *content, const gchar *senders);
+
+#define jingle_content_create_content_accept(session) \
+ jingle_session_to_packet(session, JINGLE_CONTENT_ACCEPT)
+#define jingle_content_create_content_add(session) \
+ jingle_session_to_packet(session, JINGLE_CONTENT_ADD)
+#define jingle_content_create_content_modify(session) \
+ jingle_session_to_packet(session, JINGLE_CONTENT_MODIFY)
+#define jingle_content_create_content_remove(session) \
+ jingle_session_to_packet(session, JINGLE_CONTENT_REMOVE)
+
+JingleContent *jingle_content_parse(xmlnode *content);
+xmlnode *jingle_content_to_xml(JingleContent *content, xmlnode *jingle, JingleActionType action);
+void jingle_content_handle_action(JingleContent *content, xmlnode *jingle, JingleActionType action);
+
+#ifdef __cplusplus
+}
+#endif
+
+G_END_DECLS
+
+#endif /* JINGLE_CONTENT_H */
+
============================================================
--- libpurple/protocols/jabber/jingle/session.c b329e823dd3176d11c39756a63a12cb5ef99a648
+++ libpurple/protocols/jabber/jingle/session.c b329e823dd3176d11c39756a63a12cb5ef99a648
@@ -0,0 +1,588 @@
+/**
+ * @file session.c
+ *
+ * purple
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "config.h"
+#include "content.h"
+#include "debug.h"
+#include "session.h"
+#include "jingle.h"
+
+#include <string.h>
+
+struct _JingleSessionPrivate
+{
+ gchar *sid;
+ JabberStream *js;
+ gchar *remote_jid;
+ gchar *local_jid;
+ gboolean is_initiator;
+ gboolean state;
+ GList *contents;
+ GList *pending_contents;
+};
+
+#define JINGLE_SESSION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), JINGLE_TYPE_SESSION, JingleSessionPrivate))
+
+static void jingle_session_class_init (JingleSessionClass *klass);
+static void jingle_session_init (JingleSession *session);
+static void jingle_session_finalize (GObject *object);
+static void jingle_session_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void jingle_session_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+
+static GObjectClass *parent_class = NULL;
+
+enum {
+ PROP_0,
+ PROP_SID,
+ PROP_JS,
+ PROP_REMOTE_JID,
+ PROP_LOCAL_JID,
+ PROP_IS_INITIATOR,
+ PROP_STATE,
+ PROP_CONTENTS,
+ PROP_PENDING_CONTENTS,
+};
+
+GType
+jingle_session_get_type()
+{
+ static GType type = 0;
+
+ if (type == 0) {
+ static const GTypeInfo info = {
+ sizeof(JingleSessionClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) jingle_session_class_init,
+ NULL,
+ NULL,
+ sizeof(JingleSession),
+ 0,
+ (GInstanceInitFunc) jingle_session_init,
+ NULL
+ };
+ type = g_type_register_static(G_TYPE_OBJECT, "JingleSession", &info, 0);
+ }
+ return type;
+}
+
+static void
+jingle_session_class_init (JingleSessionClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass*)klass;
+ parent_class = g_type_class_peek_parent(klass);
+
+ gobject_class->finalize = jingle_session_finalize;
+ gobject_class->set_property = jingle_session_set_property;
+ gobject_class->get_property = jingle_session_get_property;
+
+ g_object_class_install_property(gobject_class, PROP_SID,
+ g_param_spec_string("sid",
+ "Session ID",
+ "The unique session ID of the Jingle Session.",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+ g_object_class_install_property(gobject_class, PROP_JS,
+ g_param_spec_pointer("js",
+ "JabberStream",
+ "The Jabber stream associated with this session.",
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+ g_object_class_install_property(gobject_class, PROP_REMOTE_JID,
+ g_param_spec_string("remote-jid",
+ "Remote JID",
+ "The JID of the remote participant.",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+ g_object_class_install_property(gobject_class, PROP_LOCAL_JID,
+ g_param_spec_string("local-jid",
+ "Local JID",
+ "The JID of the local participant.",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+ g_object_class_install_property(gobject_class, PROP_IS_INITIATOR,
+ g_param_spec_boolean("is-initiator",
+ "Is Initiator",
+ "Whether or not the local JID is the initiator of the session.",
+ FALSE,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+ g_object_class_install_property(gobject_class, PROP_STATE,
+ g_param_spec_boolean("state",
+ "State",
+ "The state of the session (PENDING=FALSE, ACTIVE=TRUE).",
+ FALSE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property(gobject_class, PROP_CONTENTS,
+ g_param_spec_pointer("contents",
+ "Contents",
+ "The active contents contained within this session",
+ G_PARAM_READABLE));
+
+ g_object_class_install_property(gobject_class, PROP_PENDING_CONTENTS,
+ g_param_spec_pointer("pending-contents",
+ "Pending contents",
+ "The pending contents contained within this session",
+ G_PARAM_READABLE));
+
+ g_type_class_add_private(klass, sizeof(JingleSessionPrivate));
+}
+
+static void
+jingle_session_init (JingleSession *session)
+{
+ session->priv = JINGLE_SESSION_GET_PRIVATE(session);
+ memset(session->priv, 0, sizeof(session->priv));
+}
+
+static void
+jingle_session_finalize (GObject *session)
+{
+ JingleSessionPrivate *priv = JINGLE_SESSION_GET_PRIVATE(session);
+ purple_debug_info("jingle","jingle_session_finalize\n");
+
+ g_hash_table_remove(priv->js->sessions, priv->sid);
+
+ g_free(priv->sid);
+ g_free(priv->remote_jid);
+ g_free(priv->local_jid);
+
+ for (; priv->contents; priv->contents =
+ g_list_delete_link(priv->contents, priv->contents)) {
+ g_object_unref(priv->contents->data);
+ }
+ for (; priv->pending_contents; priv->pending_contents =
+ g_list_delete_link(priv->pending_contents, priv->pending_contents)) {
+ g_object_unref(priv->pending_contents->data);
+ }
+
+ parent_class->finalize(session);
+}
+
+static void
+jingle_session_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ JingleSession *session;
+ g_return_if_fail(JINGLE_IS_SESSION(object));
+
+ session = JINGLE_SESSION(object);
+
+ switch (prop_id) {
+ case PROP_SID:
+ g_free(session->priv->sid);
+ session->priv->sid = g_value_dup_string(value);
+ break;
+ case PROP_JS:
+ session->priv->js = g_value_get_pointer(value);
+ break;
+ case PROP_REMOTE_JID:
+ g_free(session->priv->remote_jid);
+ session->priv->remote_jid = g_value_dup_string(value);
+ break;
+ case PROP_LOCAL_JID:
+ g_free(session->priv->local_jid);
+ session->priv->local_jid = g_value_dup_string(value);
+ break;
+ case PROP_IS_INITIATOR:
+ session->priv->is_initiator = g_value_get_boolean(value);
+ break;
+ case PROP_STATE:
+ session->priv->state = g_value_get_boolean(value);
+ break;
+ case PROP_CONTENTS:
+ session->priv->contents = g_value_get_pointer(value);
+ break;
+ case PROP_PENDING_CONTENTS:
+ session->priv->pending_contents = g_value_get_pointer(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+jingle_session_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ JingleSession *session;
+ g_return_if_fail(JINGLE_IS_SESSION(object));
+
+ session = JINGLE_SESSION(object);
+
+ switch (prop_id) {
+ case PROP_SID:
+ g_value_set_string(value, session->priv->sid);
+ break;
+ case PROP_JS:
+ g_value_set_pointer(value, session->priv->js);
+ break;
+ case PROP_REMOTE_JID:
+ g_value_set_string(value, session->priv->remote_jid);
+ break;
+ case PROP_LOCAL_JID:
+ g_value_set_string(value, session->priv->local_jid);
+ break;
+ case PROP_IS_INITIATOR:
+ g_value_set_boolean(value, session->priv->is_initiator);
+ break;
+ case PROP_STATE:
+ g_value_set_boolean(value, session->priv->state);
+ break;
+ case PROP_CONTENTS:
+ g_value_set_pointer(value, session->priv->contents);
+ break;
+ case PROP_PENDING_CONTENTS:
+ g_value_set_pointer(value, session->priv->pending_contents);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+JingleSession *
+jingle_session_create(JabberStream *js, const gchar *sid,
+ const gchar *local_jid, const gchar *remote_jid,
+ gboolean is_initiator)
+{
+ JingleSession *session = g_object_new(jingle_session_get_type(),
+ "js", js,
+ "sid", sid,
+ "local-jid", local_jid,
+ "remote-jid", remote_jid,
+ "is_initiator", is_initiator,
+ NULL);
+
+ /* insert it into the hash table */
+ if (!js->sessions) {
+ purple_debug_info("jingle",
+ "Creating hash table for sessions\n");
+ js->sessions = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+ purple_debug_info("jingle",
+ "inserting session with key: %s into table\n", sid);
+ g_hash_table_insert(js->sessions, g_strdup(sid), session);
+
+ return session;
+}
+
+JabberStream *
+jingle_session_get_js(JingleSession *session)
+{
+ JabberStream *js;
+ g_object_get(session, "js", &js, NULL);
+ return js;
+}
+
+gchar *
+jingle_session_get_sid(JingleSession *session)
+{
+ gchar *sid;
+ g_object_get(session, "sid", &sid, NULL);
+ return sid;
+}
+
+gchar *
+jingle_session_get_local_jid(JingleSession *session)
+{
+ gchar *local_jid;
+ g_object_get(session, "local-jid", &local_jid, NULL);
+ return local_jid;
+}
+
+gchar *
+jingle_session_get_remote_jid(JingleSession *session)
+{
+ gchar *remote_jid;
+ g_object_get(session, "remote-jid", &remote_jid, NULL);
+ return remote_jid;
+}
+
+gboolean
+jingle_session_is_initiator(JingleSession *session)
+{
+ gboolean is_initiator;
+ g_object_get(session, "is-initiator", &is_initiator, NULL);
+ return is_initiator;
+}
+
+gboolean
+jingle_session_get_state(JingleSession *session)
+{
+ gboolean state;
+ g_object_get(session, "state", &state, NULL);
+ return state;
+}
+
+GList *
+jingle_session_get_contents(JingleSession *session)
+{
+ GList *contents;
+ g_object_get(session, "contents", &contents, NULL);
+ return contents;
+}
+
+GList *
+jingle_session_get_pending_contents(JingleSession *session)
+{
+ GList *pending_contents;
+ g_object_get(session, "pending-contents", &pending_contents, NULL);
+ return pending_contents;
+}
+
+JingleSession *
+jingle_session_find_by_sid(JabberStream *js, const gchar *sid)
+{
+ purple_debug_info("jingle", "find_by_id %s\n", sid);
+ purple_debug_info("jingle", "lookup: %p\n", (js->sessions) ?
+ g_hash_table_lookup(js->sessions, sid) : NULL);
+ return (JingleSession *) (js->sessions) ?
+ g_hash_table_lookup(js->sessions, sid) : NULL;
+}
+
+JingleSession *
+jingle_session_find_by_jid(JabberStream *js, const gchar *jid)
+{
+ GList *values = (js->sessions) ?
+ g_hash_table_get_values(js->sessions) : NULL;
+ gboolean use_bare = strchr(jid, '/') == NULL;
+
+ for (; values; values = g_list_delete_link(values, values)) {
+ JingleSession *session = (JingleSession *)values->data;
+ gchar *remote_jid = jingle_session_get_remote_jid(session);
+ gchar *cmp_jid = use_bare ? jabber_get_bare_jid(remote_jid)
+ : g_strdup(remote_jid);
+ g_free(remote_jid);
+ if (!strcmp(jid, cmp_jid)) {
+ g_free(cmp_jid);
+ g_list_free(values);
+ return session;
+ }
+ g_free(cmp_jid);
+ }
+
+ return NULL;
+}
+
+static xmlnode *
+jingle_add_jingle_packet(JingleSession *session,
+ JabberIq *iq, JingleActionType action)
+{
+ xmlnode *jingle = iq ?
+ xmlnode_new_child(iq->node, "jingle") :
+ xmlnode_new("jingle");
+ gchar *local_jid = jingle_session_get_local_jid(session);
+ gchar *remote_jid = jingle_session_get_remote_jid(session);
+
+ xmlnode_set_namespace(jingle, JINGLE);
+ xmlnode_set_attrib(jingle, "action", jingle_get_action_name(action));
+
+ if (jingle_session_is_initiator(session)) {
+ xmlnode_set_attrib(jingle, "initiator",
+ jingle_session_get_local_jid(session));
+ xmlnode_set_attrib(jingle, "responder",
+ jingle_session_get_remote_jid(session));
+ } else {
+ xmlnode_set_attrib(jingle, "initiator",
+ jingle_session_get_remote_jid(session));
+ xmlnode_set_attrib(jingle, "responder",
+ jingle_session_get_local_jid(session));
+ }
+
+ g_free(local_jid);
+ g_free(remote_jid);
+
+ xmlnode_set_attrib(jingle, "sid", jingle_session_get_sid(session));
+
+ return jingle;
+}
+
+JabberIq *
+jingle_session_create_ack(JingleSession *session, const xmlnode *jingle)
+{
+ JabberIq *result = jabber_iq_new(
+ jingle_session_get_js(session),
+ JABBER_IQ_RESULT);
+ xmlnode *packet = xmlnode_get_parent(jingle);
+ jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
+ xmlnode_set_attrib(result->node, "from", xmlnode_get_attrib(packet, "to"));
+ xmlnode_set_attrib(result->node, "to", xmlnode_get_attrib(packet, "from"));
+ return result;
+}
+
+static JabberIq *
+jingle_create_iq(JingleSession *session)
+{
+ JabberStream *js = jingle_session_get_js(session);
+ JabberIq *result = jabber_iq_new(js, JABBER_IQ_SET);
+ gchar *from = jingle_session_get_local_jid(session);
+ gchar *to = jingle_session_get_remote_jid(session);
+
+ xmlnode_set_attrib(result->node, "from", from);
+ xmlnode_set_attrib(result->node, "to", to);
+
+ g_free(from);
+ g_free(to);
+ return result;
+}
+
+xmlnode *
+jingle_session_to_xml(JingleSession *session, xmlnode *jingle, JingleActionType action)
+{
+ if (action != JINGLE_SESSION_INFO && action != JINGLE_SESSION_TERMINATE) {
+ GList *iter;
+ if (action == JINGLE_CONTENT_ACCEPT
+ || action == JINGLE_CONTENT_ADD
+ || action == JINGLE_CONTENT_REMOVE)
+ iter = jingle_session_get_pending_contents(session);
+ else
+ iter = jingle_session_get_contents(session);
+
+ for (; iter; iter = g_list_next(iter)) {
+ jingle_content_to_xml(iter->data, jingle, action);
+ }
+ }
+ return jingle;
+}
+
+JabberIq *
+jingle_session_to_packet(JingleSession *session, JingleActionType action)
+{
+ JabberIq *iq = jingle_create_iq(session);
+ xmlnode *jingle = jingle_add_jingle_packet(session, iq, action);
+ jingle_session_to_xml(session, jingle, action);
+ return iq;
+}
+
+void jingle_session_handle_action(JingleSession *session, xmlnode *jingle, JingleActionType action)
+{
+ GList *iter;
+ if (action == JINGLE_CONTENT_ADD || action == JINGLE_CONTENT_REMOVE)
+ iter = jingle_session_get_pending_contents(session);
+ else
+ iter = jingle_session_get_contents(session);
+
+ for (; iter; iter = g_list_next(iter)) {
+ jingle_content_handle_action(iter->data, jingle, action);
+ }
+}
+
+JingleContent *
+jingle_session_find_content(JingleSession *session, const gchar *name, const gchar *creator)
+{
+ GList *iter = session->priv->contents;
+ for (; iter; iter = g_list_next(iter)) {
+ JingleContent *content = iter->data;
+ gchar *cname = jingle_content_get_name(content);
+ gchar *ccreator = jingle_content_get_creator(content);
+ gboolean result = (!strcmp(name, cname) && !strcmp(creator, ccreator));
+
+ g_free(cname);
+ g_free(ccreator);
+
+ if (result == TRUE)
+ return content;
+ }
+ return NULL;
+}
+
+JingleContent *
+jingle_session_find_pending_content(JingleSession *session, const gchar *name, const gchar *creator)
+{
+ GList *iter = session->priv->pending_contents;
+ for (; iter; iter = g_list_next(iter)) {
+ JingleContent *content = iter->data;
+ gchar *cname = jingle_content_get_name(content);
+ gchar *ccreator = jingle_content_get_creator(content);
+ gboolean result = (!strcmp(name, cname) && !strcmp(creator, ccreator));
+
+ g_free(cname);
+ g_free(ccreator);
+
+ if (result == TRUE)
+ return content;
+ }
+ return NULL;
+}
+
+void
+jingle_session_add_content(JingleSession *session, JingleContent* content)
+{
+ session->priv->contents =
+ g_list_append(session->priv->contents, content);
+ jingle_content_set_session(content, session);
+}
+
+void
+jingle_session_remove_content(JingleSession *session, const gchar *name, const gchar *creator)
+{
+ JingleContent *content =
+ jingle_session_find_content(session, name, creator);
+
+ if (content) {
+ session->priv->contents =
+ g_list_remove(session->priv->contents, content);
+ g_object_unref(content);
+ }
+}
+
+void
+jingle_session_add_pending_content(JingleSession *session, JingleContent* content)
+{
+ session->priv->pending_contents =
+ g_list_append(session->priv->pending_contents, content);
+ jingle_content_set_session(content, session);
+}
+
+void
+jingle_session_remove_pending_content(JingleSession *session, const gchar *name, const gchar *creator)
+{
+ JingleContent *content = jingle_session_find_pending_content(session, name, creator);
+
+ if (content) {
+ session->priv->pending_contents =
+ g_list_remove(session->priv->pending_contents, content);
+ g_object_unref(content);
+ }
+}
+
+void
+jingle_session_accept_content(JingleSession *session, const gchar *name, const gchar *creator)
+{
+ JingleContent *content = jingle_session_find_pending_content(session, name, creator);
+
+ if (content) {
+ g_object_ref(content);
+ jingle_session_remove_pending_content(session, name, creator);
+ jingle_session_add_content(session, content);
+ }
+}
+
+void
+jingle_session_accept_session(JingleSession *session)
+{
+ session->priv->state = TRUE;
+}
+
============================================================
--- libpurple/protocols/jabber/jingle/session.h 20f11bbcafd0e335f768dcfb2c3f53d367fd771f
+++ libpurple/protocols/jabber/jingle/session.h 20f11bbcafd0e335f768dcfb2c3f53d367fd771f
@@ -0,0 +1,122 @@
+/**
+ * @file session.h
+ *
+ * purple
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef JINGLE_SESSION_H
+#define JINGLE_SESSION_H
+
+#include "iq.h"
+#include "jabber.h"
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define JINGLE_TYPE_SESSION (jingle_session_get_type())
+#define JINGLE_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), JINGLE_TYPE_SESSION, JingleSession))
+#define JINGLE_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), JINGLE_TYPE_SESSION, JingleSessionClass))
+#define JINGLE_IS_SESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), JINGLE_TYPE_SESSION))
+#define JINGLE_IS_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), JINGLE_TYPE_SESSION))
+#define JINGLE_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), JINGLE_TYPE_SESSION, JingleSessionClass))
+
+/** @copydoc _JingleSession */
+typedef struct _JingleSession JingleSession;
+/** @copydoc _JingleSessionClass */
+typedef struct _JingleSessionClass JingleSessionClass;
+/** @copydoc _JingleSessionPrivate */
+typedef struct _JingleSessionPrivate JingleSessionPrivate;
+
+/** The session class */
+struct _JingleSessionClass
+{
+ GObjectClass parent_class; /**< The parent class. */
+};
+
+/** The session class's private data */
+struct _JingleSession
+{
+ GObject parent; /**< The parent of this object. */
+ JingleSessionPrivate *priv; /**< The private data of this object. */
+};
+
+struct _JingleContent;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Gets the session class's GType
+ *
+ * @return The session class's GType.
+ */
+GType jingle_session_get_type(void);
+
+JingleSession *jingle_session_create(JabberStream *js, const gchar *sid,
+ const gchar *local_jid, const gchar *remote_jid,
+ gboolean is_initiator);
+JabberStream *jingle_session_get_js(JingleSession *session);
+gchar *jingle_session_get_sid(JingleSession *session);
+gchar *jingle_session_get_local_jid(JingleSession *session);
+gchar *jingle_session_get_remote_jid(JingleSession *session);
+gboolean jingle_session_is_initiator(JingleSession *session);
+gboolean jingle_session_get_state(JingleSession *session);
+
+GList *jingle_session_get_contents(JingleSession *session);
+GList *jingle_session_get_pending_contents(JingleSession *session);
+
+JingleSession *jingle_session_find_by_sid(JabberStream *js, const gchar *sid);
+JingleSession *jingle_session_find_by_jid(JabberStream *js, const gchar *jid);
+
+JabberIq *jingle_session_create_ack(JingleSession *session, const xmlnode *jingle);
+xmlnode *jingle_session_to_xml(JingleSession *session, xmlnode *parent, JingleActionType action);
+JabberIq *jingle_session_to_packet(JingleSession *session, JingleActionType action);
+
+void jingle_session_handle_action(JingleSession *session, xmlnode *jingle, JingleActionType action);
+
+#define jingle_session_create_session_accept(session) \
+ jingle_session_to_packet(session, JINGLE_SESSION_ACCEPT)
+#define jingle_session_create_session_info(session) \
+ jingle_session_to_packet(session, JINGLE_SESSION_INFO)
+#define jingle_session_create_session_initiate(session) \
+ jingle_session_to_packet(session, JINGLE_SESSION_INITIATE)
+#define jingle_session_create_session_terminate(session) \
+ jingle_session_to_packet(session, JINGLE_SESSION_TERMINATE)
+
+struct _JingleContent *jingle_session_find_content(JingleSession *session,
+ const gchar *name, const gchar *creator);
+struct _JingleContent *jingle_session_find_pending_content(JingleSession *session,
+ const gchar *name, const gchar *creator);
+
+void jingle_session_add_content(JingleSession *session, struct _JingleContent* content);
+void jingle_session_remove_content(JingleSession *session, const gchar *name, const gchar *creator);
+void jingle_session_add_pending_content(JingleSession *session, struct _JingleContent* content);
+void jingle_session_remove_pending_content(JingleSession *session, const gchar *name, const gchar *creator);
+void jingle_session_accept_content(JingleSession *session, const gchar *name, const gchar *creator);
+void jingle_session_accept_session(JingleSession *session);
+
+#ifdef __cplusplus
+}
+#endif
+
+G_END_DECLS
+
+#endif /* JINGLE_SESSION_H */
+
============================================================
--- libpurple/protocols/jabber/jingle/transport.c d716de3c7c369e67ad2ac01504eb1dff0d15d646
+++ libpurple/protocols/jabber/jingle/transport.c d716de3c7c369e67ad2ac01504eb1dff0d15d646
@@ -0,0 +1,172 @@
+/**
+ * @file transport.c
+ *
+ * purple
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "transport.h"
+#include "jingle.h"
+#include "debug.h"
+
+#include <string.h>
+
+struct _JingleTransportPrivate
+{
+ void *dummy;
+};
+
+#define JINGLE_TRANSPORT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), JINGLE_TYPE_TRANSPORT, JingleTransportPrivate))
+
+static void jingle_transport_class_init (JingleTransportClass *klass);
+static void jingle_transport_init (JingleTransport *transport);
+static void jingle_transport_finalize (GObject *object);
+static void jingle_transport_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void jingle_transport_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+JingleTransport *jingle_transport_parse_internal(xmlnode *transport);
+xmlnode *jingle_transport_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action);
+
+static GObjectClass *parent_class = NULL;
+
+enum {
+ PROP_0,
+};
+
+GType
+jingle_transport_get_type()
+{
+ static GType type = 0;
+
+ if (type == 0) {
+ static const GTypeInfo info = {
+ sizeof(JingleTransportClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) jingle_transport_class_init,
+ NULL,
+ NULL,
+ sizeof(JingleTransport),
+ 0,
+ (GInstanceInitFunc) jingle_transport_init,
+ NULL
+ };
+ type = g_type_register_static(G_TYPE_OBJECT, "JingleTransport", &info, 0);
+ }
+ return type;
+}
+
+static void
+jingle_transport_class_init (JingleTransportClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass*)klass;
+ parent_class = g_type_class_peek_parent(klass);
+
+ gobject_class->finalize = jingle_transport_finalize;
+ gobject_class->set_property = jingle_transport_set_property;
+ gobject_class->get_property = jingle_transport_get_property;
+ klass->to_xml = jingle_transport_to_xml_internal;
+ klass->parse = jingle_transport_parse_internal;
+
+ g_type_class_add_private(klass, sizeof(JingleTransportPrivate));
+}
+
+static void
+jingle_transport_init (JingleTransport *transport)
+{
+ transport->priv = JINGLE_TRANSPORT_GET_PRIVATE(transport);
+ memset(transport->priv, 0, sizeof(transport->priv));
+}
+
+static void
+jingle_transport_finalize (GObject *transport)
+{
+ /* JingleTransportPrivate *priv = JINGLE_TRANSPORT_GET_PRIVATE(transport); */
+ purple_debug_info("jingle","jingle_transport_finalize\n");
+
+ parent_class->finalize(transport);
+}
+
+static void
+jingle_transport_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ JingleTransport *transport;
+ g_return_if_fail(JINGLE_IS_TRANSPORT(object));
+
+ transport = JINGLE_TRANSPORT(object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+jingle_transport_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ JingleTransport *transport;
+ g_return_if_fail(JINGLE_IS_TRANSPORT(object));
+
+ transport = JINGLE_TRANSPORT(object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+JingleTransport *
+jingle_transport_create(const gchar *type)
+{
+ return g_object_new(jingle_get_type(type), NULL);
+}
+
+const gchar *
+jingle_transport_get_transport_type(JingleTransport *transport)
+{
+ return JINGLE_TRANSPORT_GET_CLASS(transport)->transport_type;
+}
+
+JingleTransport *
+jingle_transport_parse_internal(xmlnode *transport)
+{
+ const gchar *type = xmlnode_get_namespace(transport);
+ return jingle_transport_create(type);
+}
+
+xmlnode *
+jingle_transport_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action)
+{
+ xmlnode *node = xmlnode_new_child(content, "transport");
+ xmlnode_set_namespace(node, jingle_transport_get_transport_type(transport));
+ return node;
+}
+
+JingleTransport *
+jingle_transport_parse(xmlnode *transport)
+{
+ const gchar *type = xmlnode_get_namespace(transport);
+ return JINGLE_TRANSPORT_CLASS(g_type_class_ref(jingle_get_type(type)))->parse(transport);
+}
+
+xmlnode *
+jingle_transport_to_xml(JingleTransport *transport, xmlnode *content, JingleActionType action)
+{
+ g_return_val_if_fail(JINGLE_IS_TRANSPORT(transport), NULL);
+ return JINGLE_TRANSPORT_GET_CLASS(transport)->to_xml(transport, content, action);
+}
+
============================================================
--- libpurple/protocols/jabber/jingle/transport.h ae235a20b76fa0919657f07711bd188ba213cd06
+++ libpurple/protocols/jabber/jingle/transport.h ae235a20b76fa0919657f07711bd188ba213cd06
@@ -0,0 +1,95 @@
+/**
+ * @file transport.h
+ *
+ * purple
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef JINGLE_TRANSPORT_H
+#define JINGLE_TRANSPORT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "jingle.h"
+#include "xmlnode.h"
+
+G_BEGIN_DECLS
+
+#define JINGLE_TYPE_TRANSPORT (jingle_transport_get_type())
+#define JINGLE_TRANSPORT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), JINGLE_TYPE_TRANSPORT, JingleTransport))
+#define JINGLE_TRANSPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), JINGLE_TYPE_TRANSPORT, JingleTransportClass))
+#define JINGLE_IS_TRANSPORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), JINGLE_TYPE_TRANSPORT))
+#define JINGLE_IS_TRANSPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), JINGLE_TYPE_TRANSPORT))
+#define JINGLE_TRANSPORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), JINGLE_TYPE_TRANSPORT, JingleTransportClass))
+
+/** @copydoc _JingleTransport */
+typedef struct _JingleTransport JingleTransport;
+/** @copydoc _JingleTransportClass */
+typedef struct _JingleTransportClass JingleTransportClass;
+/** @copydoc _JingleTransportPrivate */
+typedef struct _JingleTransportPrivate JingleTransportPrivate;
+
+/** The transport class */
+struct _JingleTransportClass
+{
+ GObjectClass parent_class; /**< The parent class. */
+
+ const gchar *transport_type;
+ xmlnode *(*to_xml) (JingleTransport *transport, xmlnode *content, JingleActionType action);
+ JingleTransport *(*parse) (xmlnode *transport);
+};
+
+/** The transport class's private data */
+struct _JingleTransport
+{
+ GObject parent; /**< The parent of this object. */
+ JingleTransportPrivate *priv; /**< The private data of this object. */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Gets the transport class's GType
+ *
+ * @return The transport class's GType.
+ */
+GType jingle_transport_get_type(void);
+
+JingleTransport *jingle_transport_create(const gchar *type);
+const gchar *jingle_transport_get_transport_type(JingleTransport *transport);
+void jingle_transport_add_candidate();
+
+#define jingle_transport_create_transport_accept(session) \
+ jingle_session_to_packet(session, JINGLE_TRANSPORT_ACCEPT)
+#define jingle_transport_create_transport_info(session) \
+ jingle_session_to_packet(session, JINGLE_TRANSPORT_INFO)
+#define jingle_transport_create_transport_replace(session) \
+ jingle_session_to_packet(session, JINGLE_TRANSPORT_REPLACE)
+
+JingleTransport *jingle_transport_parse(xmlnode *transport);
+xmlnode *jingle_transport_to_xml(JingleTransport *transport, xmlnode *content, JingleActionType action);
+
+#ifdef __cplusplus
+}
+#endif
+
+G_END_DECLS
+
+#endif /* JINGLE_TRANSPORT_H */
+
============================================================
--- libpurple/marshallers.list ba136efaa6bc72e65bd763daf96b47d91f60dacb
+++ libpurple/marshallers.list bfb697fadbe0572456e8cf27a7bb435ec8ac957f
@@ -1,3 +1,4 @@ BOOLEAN:OBJECT
VOID:BOXED,BOXED
VOID:POINTER,POINTER,OBJECT
BOOLEAN:OBJECT
+VOID:STRING,STRING
============================================================
--- libpurple/media.c 5c6fb6e8b18c47210149f378ad13362893ebd872
+++ libpurple/media.c a85c4b6c35e3a05cd350956d763628ac0371b5ec
@@ -210,8 +210,8 @@ purple_media_class_init (PurpleMediaClas
G_TYPE_POINTER, FS_TYPE_CANDIDATE);
purple_media_signals[CANDIDATES_PREPARED] = g_signal_new("candidates-prepared", G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+ purple_smarshal_VOID__STRING_STRING,
+ G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
purple_media_signals[CANDIDATE_PAIR] = g_signal_new("candidate-pair", G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
purple_smarshal_VOID__BOXED_BOXED,
@@ -675,7 +675,7 @@ media_bus_call(GstBus *bus, GstMessage *
if (session->session == fssession) {
g_signal_emit(session->media,
purple_media_signals[CODECS_READY],
- 0, &session->id);
+ 0, session->id);
g_list_free(sessions);
break;
}
@@ -1003,7 +1003,8 @@ purple_media_candidates_prepared_cb(FsSt
g_object_get(stream, "participant", &participant, NULL);
g_object_get(participant, "cname", &name, NULL);
g_object_unref(participant);
- g_signal_emit(session->media, purple_media_signals[CANDIDATES_PREPARED], 0);
+ g_signal_emit(session->media, purple_media_signals[CANDIDATES_PREPARED],
+ 0, session->id, name);
g_free(name);
}
============================================================
--- libpurple/media.h 6f2ed391b1ff575ec8d6be06c724c9f607c8ffa6
+++ libpurple/media.h a2b8ef361aaf020ebfca4cc94215e9ba2ee9b8af
@@ -27,6 +27,8 @@
#ifndef __MEDIA_H_
#define __MEDIA_H_
+#include "internal.h"
+
#ifdef USE_VV
#include <gst/gst.h>
============================================================
--- libpurple/mediamanager.h 1d76568a5e16cefbe758c13b67b111a0119b4d7c
+++ libpurple/mediamanager.h be079e183348622c80191c6bc685a7f356c69179
@@ -27,6 +27,8 @@
#ifndef __MEDIA_MANAGER_H_
#define __MEDIA_MANAGER_H_
+#include "internal.h"
+
#ifdef USE_VV
#include <glib.h>
============================================================
--- libpurple/protocols/jabber/Makefile.am 694f33c99e46111ffcbbf5d1212119a86d16e66f
+++ libpurple/protocols/jabber/Makefile.am d0a9460acc175df28269e6414bc9b97214d6a6e3
@@ -19,8 +19,18 @@ JABBERSOURCES = auth.c \
iq.h \
jabber.c \
jabber.h \
- jingle.c \
- jingle.h \
+ jingle/jingle.c \
+ jingle/jingle.h \
+ jingle/content.c \
+ jingle/content.h \
+ jingle/rawudp.c \
+ jingle/rawudp.h \
+ jingle/rtp.c \
+ jingle/rtp.h \
+ jingle/session.c \
+ jingle/session.h \
+ jingle/transport.c \
+ jingle/transport.h \
jutil.c \
jutil.h \
message.c \
============================================================
--- libpurple/protocols/jabber/Makefile.mingw f3643645466cd2453f5c5ed6294505921b2c264d
+++ libpurple/protocols/jabber/Makefile.mingw 27ec8591215b3914ceca10919335977c35b941b9
@@ -52,6 +52,12 @@ C_SRC = \
google.c \
iq.c \
jabber.c \
+ jingle/jingle.c \
+ jingle/content.c \
+ jingle/rawudp.c \
+ jingle/rtp.c \
+ jingle/session.c \
+ jingle/transport.c \
jutil.c \
message.c \
oob.c \
============================================================
--- libpurple/protocols/jabber/disco.c 2f4ccf6bda7c02f7a08e3d75a363bc08551971c3
+++ libpurple/protocols/jabber/disco.c 690e81b0db44b88517eb2c2b6c2c9d255c5750a9
@@ -28,6 +28,7 @@
#include "iq.h"
#include "disco.h"
#include "jabber.h"
+#include "jingle/jingle.h"
#include "presence.h"
#include "roster.h"
#include "pep.h"
@@ -157,10 +158,10 @@ void jabber_disco_info_parse(JabberStrea
SUPPORT_FEATURE("http://www.google.com/transport/p2p");
SUPPORT_FEATURE("http://www.google.com/transport/raw-udp");
SUPPORT_FEATURE("http://www.google.com/session/phone");
- SUPPORT_FEATURE("urn:xmpp:tmp:jingle");
- SUPPORT_FEATURE("urn:xmpp:tmp:jingle:apps:rtp#audio");
- SUPPORT_FEATURE("urn:xmpp:tmp:jingle:apps:rtp#video");
- SUPPORT_FEATURE("urn:xmpp:tmp:jingle:transports:ice-udp");
+ SUPPORT_FEATURE(JINGLE);
+ SUPPORT_FEATURE(JINGLE_APP_RTP_SUPPORT_AUDIO);
+ SUPPORT_FEATURE(JINGLE_APP_RTP_SUPPORT_VIDEO);
+ SUPPORT_FEATURE(JINGLE_TRANSPORT_RAWUDP);
#endif
} else {
const char *ext = NULL;
============================================================
--- libpurple/protocols/jabber/iq.c f715b80fdfea312a504998b8c99ec7beeedb90d6
+++ libpurple/protocols/jabber/iq.c 2ba4af13eb38a1dd69d242f77daa2bedfb8baa70
@@ -28,7 +28,7 @@
#include "disco.h"
#include "google.h"
#include "iq.h"
-#include "jingle.h"
+#include "jingle/jingle.h"
#include "oob.h"
#include "roster.h"
#include "si.h"
@@ -360,8 +360,8 @@ void jabber_iq_parse(JabberStream *js, x
}
#ifdef USE_VV
- if (xmlnode_get_child_with_namespace(packet, "jingle", "urn:xmpp:tmp:jingle")) {
- jabber_jingle_session_parse(js, packet);
+ if (xmlnode_get_child_with_namespace(packet, "jingle", JINGLE)) {
+ jingle_parse(js, packet);
return;
}
#endif
@@ -406,7 +406,7 @@ void jabber_iq_init(void)
jabber_iq_register_handler("jabber:iq:register", jabber_register_parse);
jabber_iq_register_handler("urn:xmpp:ping", urn_xmpp_ping_parse);
#ifdef USE_VV
- jabber_iq_register_handler("urn:xmpp:tmp:jingle", jabber_jingle_session_parse);
+ jabber_iq_register_handler(JINGLE, jingle_parse);
#endif
}
============================================================
--- libpurple/protocols/jabber/jabber.c 68180be7732f3e99125b2af7da7189821c6e0c43
+++ libpurple/protocols/jabber/jabber.c 899b2d222941c576c1c87cdcbad5333cd130257b
@@ -56,13 +56,13 @@
#include "xdata.h"
#include "pep.h"
#include "adhoccommands.h"
-#include "jingle.h"
+#include "jingle/jingle.h"
+#include "jingle/rtp.h"
+
#ifdef USE_VV
#include <gst/farsight/fs-conference-iface.h>
-#define XEP_0167_AUDIO_CAP "urn:xmpp:tmp:jingle:apps:rtp#audio"
-#define XEP_0167_VIDEO_CAP "urn:xmpp:tmp:jingle:apps:rtp#video"
#define GTALK_CAP "http://www.google.com/session/phone"
#endif
@@ -1285,7 +1285,7 @@ void jabber_close(PurpleConnection *gc)
#ifdef USE_VV
/* Close all of the open Jingle sessions on this stream */
- jabber_jingle_session_terminate_sessions(js);
+ jingle_terminate_sessions(js);
#endif
/* Don't perform any actions on the ssl connection
@@ -1923,7 +1923,7 @@ void jabber_convo_closed(PurpleConnectio
return;
#ifdef USE_VV
- jabber_jingle_session_terminate_session_media(js, who);
+ jingle_rtp_terminate_session(js, who);
#endif
if((jb = jabber_buddy_find(js, who, TRUE)) &&
(jbr = jabber_buddy_find_resource(jb, jid->resource))) {
@@ -2408,7 +2408,7 @@ jabber_initiate_media(PurpleConnection *
jabber_initiate_media(PurpleConnection *gc, const char *who,
PurpleMediaSessionType type)
{
- return jabber_jingle_session_initiate_media(gc->proto_data, who, type);
+ return jingle_rtp_initiate_media(gc->proto_data, who, type);
}
gboolean jabber_can_do_media(PurpleConnection *gc, const char *who,
@@ -2432,18 +2432,18 @@ gboolean jabber_can_do_media(PurpleConne
if (type == (PURPLE_MEDIA_AUDIO | PURPLE_MEDIA_VIDEO)) {
purple_debug_info("jabber",
"Checking audio/video XEP support for %s\n", who);
- return (jabber_buddy_has_capability(jb, XEP_0167_AUDIO_CAP) ||
+ return (jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_AUDIO) ||
jabber_buddy_has_capability(jb, GTALK_CAP)) &&
- jabber_buddy_has_capability(jb, XEP_0167_VIDEO_CAP);
+ jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_VIDEO);
} else if (type == (PURPLE_MEDIA_AUDIO)) {
purple_debug_info("jabber",
"Checking audio XEP support for %s\n", who);
- return jabber_buddy_has_capability(jb, XEP_0167_AUDIO_CAP) ||
+ return jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_AUDIO) ||
jabber_buddy_has_capability(jb, GTALK_CAP);
} else if (type == (PURPLE_MEDIA_VIDEO)) {
purple_debug_info("jabber",
"Checking video XEP support for %s\n", who);
- return jabber_buddy_has_capability(jb, XEP_0167_VIDEO_CAP);
+ return jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_VIDEO);
}
return FALSE;
============================================================
--- libpurple/protocols/jabber/jabber.h c819a7366cf4fe4cddc0b3641864ba0054bfd8c2
+++ libpurple/protocols/jabber/jabber.h 6052df5d93775724be3a37e725af235350e06f99
@@ -247,6 +247,7 @@ struct _JabberStream
#ifdef USE_VV
/* keep a hash table of JingleSessions */
GHashTable *sessions;
+ GHashTable *medias;
#endif
};
============================================================
--- libpurple/protocols/jabber/jingle.c 670d4292cd432fdf0bbee6dae2a1b999a3868915
+++ libpurple/protocols/jabber/jingle/jingle.c 1b1d91fa356e399ad194bf6fde29fcc74576f48c
@@ -1,4 +1,6 @@
/*
+ * @file jingle.c
+ *
* purple - Jabber Protocol Plugin
*
* This program is free software; you can redistribute it and/or modify
@@ -18,1440 +20,325 @@
*/
#include "config.h"
-#include "purple.h"
+#include "content.h"
+#include "debug.h"
#include "jingle.h"
-#include "xmlnode.h"
-#include "iq.h"
-
-#include <stdlib.h>
#include <string.h>
-#include <glib.h>
+#include "session.h"
+#include "rawudp.h"
+#include "rtp.h"
-#ifdef USE_VV
-
-#include <gst/farsight/fs-candidate.h>
-
-#define JINGLE "urn:xmpp:tmp:jingle"
-#define JINGLE_RTP "urn:xmpp:tmp:jingle:apps:rtp"
-#define JINGLE_RTP_INFO "urn:xmpp:tmp:jingle:apps:rtp:info"
-#define TRANSPORT_ICEUDP "urn:xmpp:tmp:jingle:transports:ice-udp"
-
-typedef enum {
- PENDING,
- GOT_ACK,
- ACCEPTED,
- ACTIVE
-} JingleSessionState;
-
-typedef struct {
- char *id;
- JabberStream *js;
- PurpleMedia *media;
- char *remote_jid;
- char *initiator;
- gboolean is_initiator;
- JingleSessionState state;
- GHashTable *contents; /* JingleSessionContent table */
-} JingleSession;
-
-typedef struct {
- gchar *name;
- JingleSession *session;
- gchar *creator;
- gchar *sender;
- gchar *transport_type;
- gchar *type;
- gchar *subtype;
-} JingleSessionContent;
-
-static void
-jabber_jingle_session_content_create_internal(JingleSession *session,
- const gchar *name,
- const gchar *creator,
- const gchar *sender,
- const gchar *transport_type,
- const gchar *type,
- const gchar *subtype)
+const gchar *
+jingle_get_action_name(JingleActionType action)
{
- JingleSessionContent *content = g_new0(JingleSessionContent, 1);
- content->session = session;
- content->name = g_strdup(name);
- content->creator = g_strdup(creator);
- content->sender = g_strdup(sender);
- content->transport_type = g_strdup(transport_type);
- content->type = g_strdup(type);
- content->subtype = g_strdup(subtype);
-
- if (!session->contents) {
- purple_debug_info("jingle", "Creating hash table for contents\n");
- session->contents = g_hash_table_new(g_str_hash, g_str_equal);
+ switch (action) {
+ case JINGLE_CONTENT_ACCEPT:
+ return "content-accept";
+ case JINGLE_CONTENT_ADD:
+ return "content-add";
+ case JINGLE_CONTENT_MODIFY:
+ return "content-modify";
+ case JINGLE_CONTENT_REMOVE:
+ return "content-remove";
+ case JINGLE_SESSION_ACCEPT:
+ return "session-accept";
+ case JINGLE_SESSION_INFO:
+ return "session-info";
+ case JINGLE_SESSION_INITIATE:
+ return "session-initiate";
+ case JINGLE_SESSION_TERMINATE:
+ return "session-terminate";
+ case JINGLE_TRANSPORT_ACCEPT:
+ return "transport-accept";
+ case JINGLE_TRANSPORT_INFO:
+ return "transport-info";
+ case JINGLE_TRANSPORT_REPLACE:
+ return "transport-replace";
+ default:
+ return "unknown-type";
}
- purple_debug_info("jingle", "inserting content with name == \"%s\" into table\n",
- content->name);
- g_hash_table_insert(session->contents, content->name, content);
}
-static void
-jabber_jingle_session_destroy_content(JingleSessionContent *content)
+JingleActionType
+jingle_get_action_type(const gchar *action)
{
- purple_debug_info("jingle", "destroying content with name == \"%s\"\n",
- content->name);
- g_hash_table_remove(content->session->contents, content->name);
- g_free(content->name);
- g_free(content->creator);
- g_free(content->sender);
- g_free(content->transport_type);
- g_free(content->type);
- g_free(content->subtype);
- g_free(content);
+ if (!strcmp(action, "content-accept"))
+ return JINGLE_CONTENT_ACCEPT;
+ else if (!strcmp(action, "content-add"))
+ return JINGLE_CONTENT_ADD;
+ else if (!strcmp(action, "content-modify"))
+ return JINGLE_CONTENT_MODIFY;
+ else if (!strcmp(action, "content-remove"))
+ return JINGLE_CONTENT_REMOVE;
+ else if (!strcmp(action, "session-accept"))
+ return JINGLE_SESSION_ACCEPT;
+ else if (!strcmp(action, "session-info"))
+ return JINGLE_SESSION_INFO;
+ else if (!strcmp(action, "session-initiate"))
+ return JINGLE_SESSION_INITIATE;
+ else if (!strcmp(action, "session-terminate"))
+ return JINGLE_SESSION_TERMINATE;
+ else if (!strcmp(action, "transport-accept"))
+ return JINGLE_TRANSPORT_ACCEPT;
+ else if (!strcmp(action, "transport-info"))
+ return JINGLE_TRANSPORT_INFO;
+ else if (!strcmp(action, "transport-replace"))
+ return JINGLE_TRANSPORT_REPLACE;
+ else
+ return JINGLE_UNKNOWN_TYPE;
}
-static const gchar *
-jabber_jingle_session_content_get_name(const JingleSessionContent *jsc)
+GType
+jingle_get_type(const gchar *type)
{
- return jsc->name;
+ if (!strcmp(type, JINGLE_APP_RTP))
+ return JINGLE_TYPE_RTP;
+#if 0
+ else if (!strcmp(type, JINGLE_APP_FT))
+ return JINGLE_TYPE_FT;
+ else if (!strcmp(type, JINGLE_APP_XML))
+ return JINGLE_TYPE_XML;
+#endif
+ else if (!strcmp(type, JINGLE_TRANSPORT_RAWUDP))
+ return JINGLE_TYPE_RAWUDP;
+#if 0
+ else if (!strcmp(type, JINGLE_TRANSPORT_ICEUDP))
+ return JINGLE_TYPE_ICEUDP;
+ else if (!strcmp(type, JINGLE_TRANSPORT_SOCKS))
+ return JINGLE_TYPE_SOCKS;
+ else if (!strcmp(type, JINGLE_TRANSPORT_IBB))
+ return JINGLE_TYPE_IBB;
+#endif
+ else
+ return G_TYPE_NONE;
}
-static JingleSession *
-jabber_jingle_session_content_get_session(const JingleSessionContent *jsc)
-{
- return jsc->session;
-}
-
-static const gchar *
-jabber_jingle_session_content_get_creator(const JingleSessionContent *jsc)
-{
- return jsc->creator;
-}
-
-static const gchar *
-jabber_jingle_session_content_get_sender(const JingleSessionContent *jsc)
-{
- return jsc->sender;
-}
-
-static const gchar *
-jabber_jingle_session_content_get_transport_type(const JingleSessionContent *jsc)
-{
- return jsc->transport_type;
-}
-
-static gboolean
-jabber_jingle_session_content_is_transport_type(const JingleSessionContent *jsc,
- const gchar *transport_type)
-{
- return !strcmp(jabber_jingle_session_content_get_transport_type(jsc),
- transport_type);
-}
-
-static const gchar *
-jabber_jingle_session_content_get_type(const JingleSessionContent *jsc)
-{
- return jsc->type;
-}
-
-static gboolean
-jabber_jingle_session_content_is_type(const JingleSessionContent *jsc,
- const gchar *type)
-{
- return !strcmp(jabber_jingle_session_content_get_type(jsc), type);
-}
-
-static gchar *
-jabber_jingle_session_content_get_subtype(const JingleSessionContent *jsc)
-{
- return jsc->subtype;
-}
-
-static gboolean
-jabber_jingle_session_content_is_vv_type(const JingleSessionContent *jsc,
- const gchar *media_type)
-{
- return jabber_jingle_session_content_is_type(jsc, JINGLE_RTP) &&
- !strcmp(jabber_jingle_session_content_get_subtype(jsc),
- media_type);
-}
-
static void
-jabber_jingle_session_content_set_sender(JingleSessionContent *jsc,
- const char *sender)
+jingle_handle_content_accept(JingleSession *session, xmlnode *jingle)
{
- if (jsc->sender)
- g_free(jsc->sender);
- jsc->sender = g_strdup(sender);
-}
+ xmlnode *content = xmlnode_get_child(jingle, "content");
+ jabber_iq_send(jingle_session_create_ack(session, jingle));
-static gboolean
-jabber_jingle_session_equal(gconstpointer a, gconstpointer b)
-{
- purple_debug_info("jingle",
- "jabber_jingle_session_equal, comparing %s and %s\n",
- ((JingleSession *)a)->id,
- ((JingleSession *)b)->id);
- return !strcmp(((JingleSession *) a)->id, ((JingleSession *) b)->id);
-}
-
-static JingleSession *
-jabber_jingle_session_create_internal(JabberStream *js,
- const char *id)
-{
- JingleSession *sess = g_new0(JingleSession, 1);
- sess->js = js;
-
- if (id) {
- sess->id = g_strdup(id);
- } else if (js) {
- /* init the session ID... */
- sess->id = jabber_get_next_id(js);
+ for (; content; content = xmlnode_get_next_twin(content)) {
+ const gchar *name = xmlnode_get_attrib(content, "name");
+ const gchar *creator = xmlnode_get_attrib(content, "creator");
+ jingle_session_accept_content(session, name, creator);
+ /* signal here */
}
-
- /* insert it into the hash table */
- if (!js->sessions) {
- purple_debug_info("jingle", "Creating hash table for sessions\n");
- js->sessions = g_hash_table_new(g_str_hash, g_str_equal);
- }
- purple_debug_info("jingle", "inserting session with key: %s into table\n",
- sess->id);
- g_hash_table_insert(js->sessions, sess->id, sess);
-
- sess->state = PENDING;
-
- return sess;
}
-static JabberStream *
-jabber_jingle_session_get_js(const JingleSession *sess)
-{
- return sess->js;
-}
-
-static JingleSession *
-jabber_jingle_session_create(JabberStream *js)
-{
- JingleSession *sess = jabber_jingle_session_create_internal(js, NULL);
- sess->is_initiator = TRUE;
- return sess;
-}
-
-static JingleSession *
-jabber_jingle_session_create_by_id(JabberStream *js, const char *id)
-{
- JingleSession *sess = jabber_jingle_session_create_internal(js, id);
- sess->is_initiator = FALSE;
- return sess;
-}
-
-static const char *
-jabber_jingle_session_get_id(const JingleSession *sess)
-{
- return sess->id;
-}
-
static void
-jabber_jingle_session_destroy(JingleSession *sess)
+jingle_handle_content_add(JingleSession *session, xmlnode *jingle)
{
- GList *contents;
- g_hash_table_remove(sess->js->sessions, sess->id);
- g_free(sess->id);
- g_free(sess->remote_jid);
- g_free(sess->initiator);
+ xmlnode *content = xmlnode_get_child(jingle, "content");
+ jabber_iq_send(jingle_session_create_ack(session, jingle));
- if (sess->media)
- g_object_unref(sess->media);
-
- for (contents = g_hash_table_get_values(sess->contents); contents;
- contents = g_list_delete_link(contents, contents))
- jabber_jingle_session_destroy_content(contents->data);
-
- g_free(sess);
-}
-
-static JingleSession *
-jabber_jingle_session_find_by_id(JabberStream *js, const char *id)
-{
- purple_debug_info("jingle", "find_by_id %s\n", id);
- purple_debug_info("jingle", "lookup: %p\n", (js->sessions) ?
- g_hash_table_lookup(js->sessions, id) : NULL);
- return (JingleSession *) (js->sessions) ?
- g_hash_table_lookup(js->sessions, id) : NULL;
-}
-
-static JingleSession *
-jabber_jingle_session_find_by_jid(JabberStream *js, const char *jid)
-{
- GList *values = (js->sessions) ?
- g_hash_table_get_values(js->sessions) : NULL;
- gboolean use_bare = strchr(jid, '/') == NULL;
-
- for (; values; values = g_list_delete_link(values, values)) {
- JingleSession *session = (JingleSession *)values->data;
- gchar *cmp_jid = use_bare ? jabber_get_bare_jid(session->remote_jid)
- : g_strdup(session->remote_jid);
- if (!strcmp(jid, cmp_jid)) {
- g_free(cmp_jid);
- g_list_free(values);
- return session;
+ for (; content; content = xmlnode_get_next_twin(content)) {
+ JingleContent *pending_content =
+ jingle_content_parse(content);
+ if (pending_content == NULL) {
+ purple_debug_error("jingle",
+ "Error parsing \"content-add\" content.\n");
+ /* XXX: send error here */
+ } else {
+ jingle_session_add_pending_content(session,
+ pending_content);
}
- g_free(cmp_jid);
}
- return NULL;
+ /* XXX: signal here */
}
-static GList *
-jabber_jingle_get_codecs(xmlnode *description)
-{
- GList *codecs = NULL;
- xmlnode *codec_element = NULL;
- const char *encoding_name,*id, *clock_rate;
- FsCodec *codec;
- const gchar *media = xmlnode_get_attrib(description, "media");
- FsMediaType type = !strcmp(media, "video") ? FS_MEDIA_TYPE_VIDEO :
- !strcmp(media, "audio") ? FS_MEDIA_TYPE_AUDIO : 0;
-
- for (codec_element = xmlnode_get_child(description, "payload-type") ;
- codec_element ;
- codec_element = xmlnode_get_next_twin(codec_element)) {
- xmlnode *param;
- gchar *codec_str;
- encoding_name = xmlnode_get_attrib(codec_element, "name");
-
- id = xmlnode_get_attrib(codec_element, "id");
- clock_rate = xmlnode_get_attrib(codec_element, "clockrate");
-
- codec = fs_codec_new(atoi(id), encoding_name,
- type,
- clock_rate ? atoi(clock_rate) : 0);
-
- for (param = xmlnode_get_child(codec_element, "parameter");
- param; param = xmlnode_get_next_twin(param)) {
- fs_codec_add_optional_parameter(codec,
- xmlnode_get_attrib(param, "name"),
- xmlnode_get_attrib(param, "value"));
- }
-
- codec_str = fs_codec_to_string(codec);
- purple_debug_fatal("jingle", "received codec: %s\n", codec_str);
- g_free(codec_str);
-
- codecs = g_list_append(codecs, codec);
- }
- return codecs;
-}
-
-static GList *
-jabber_jingle_get_candidates(const xmlnode *transport)
-{
- GList *candidates = NULL;
- xmlnode *candidate = NULL;
- FsCandidate *c;
-
- for (candidate = xmlnode_get_child(transport, "candidate") ;
- candidate ;
- candidate = xmlnode_get_next_twin(candidate)) {
- const char *type = xmlnode_get_attrib(candidate, "type");
- c = fs_candidate_new(xmlnode_get_attrib(candidate, "component"),
- atoi(xmlnode_get_attrib(candidate, "component")),
- strcmp(type, "host") == 0 ?
- FS_CANDIDATE_TYPE_HOST :
- strcmp(type, "prflx") == 0 ?
- FS_CANDIDATE_TYPE_PRFLX :
- strcmp(type, "relay") == 0 ?
- FS_CANDIDATE_TYPE_RELAY :
- strcmp(type, "srflx") == 0 ?
- FS_CANDIDATE_TYPE_SRFLX : 0,
- strcmp(xmlnode_get_attrib(candidate, "protocol"),
- "udp") == 0 ?
- FS_NETWORK_PROTOCOL_UDP :
- FS_NETWORK_PROTOCOL_TCP,
- xmlnode_get_attrib(candidate, "ip"),
- atoi(xmlnode_get_attrib(candidate, "port")));
- candidates = g_list_append(candidates, c);
- }
-
- return candidates;
-}
-
-static JingleSessionContent *
-jabber_jingle_session_get_content(const JingleSession *session,
- const char *name)
-{
- return (JingleSession *) name ?
- g_hash_table_lookup(session->contents, name) : NULL;
-}
-
-static GList *
-jabber_jingle_session_get_contents(const JingleSession *session)
-{
- return g_hash_table_get_values(session->contents);
-}
-
-static PurpleMedia *
-jabber_jingle_session_get_media(const JingleSession *sess)
-{
- return sess->media;
-}
-
static void
-jabber_jingle_session_set_media(JingleSession *sess, PurpleMedia *media)
+jingle_handle_content_modify(JingleSession *session, xmlnode *jingle)
{
- sess->media = media;
-}
+ xmlnode *content = xmlnode_get_child(jingle, "content");
+ jabber_iq_send(jingle_session_create_ack(session, jingle));
-static const char *
-jabber_jingle_session_get_remote_jid(const JingleSession *sess)
-{
- return sess->remote_jid;
-}
+ for (; content; content = xmlnode_get_next_twin(content)) {
+ const gchar *name = xmlnode_get_attrib(content, "name");
+ const gchar *creator = xmlnode_get_attrib(content, "creator");
+ JingleContent *local_content = jingle_session_find_content(session, name, creator);
-static void
-jabber_jingle_session_set_remote_jid(JingleSession *sess,
- const char *remote_jid)
-{
- if (sess->remote_jid)
- g_free(sess->remote_jid);
- sess->remote_jid = g_strdup(remote_jid);
-}
-
-static JingleSessionState
-jabber_jingle_session_get_state(JingleSession *sess)
-{
- return sess->state;
-}
-
-static void
-jabber_jingle_session_set_state(JingleSession *sess,
- JingleSessionState state)
-{
- sess->state = state;
-}
-
-
-static const char *
-jabber_jingle_session_get_initiator(const JingleSession *sess)
-{
- return sess->initiator;
-}
-
-static void
-jabber_jingle_session_set_initiator(JingleSession *sess,
- const char *initiator)
-{
- if (sess->initiator)
- g_free(sess->initiator);
- sess->initiator = g_strdup(initiator);
-}
-
-static gboolean
-jabber_jingle_session_is_initiator(const JingleSession *sess)
-{
- return sess->is_initiator;
-}
-
-static void
-jabber_jingle_session_add_payload_types(const JingleSessionContent *jsc,
- xmlnode *description,
- GList *codecs)
-{
- for (; codecs ; codecs = codecs->next) {
- FsCodec *codec = (FsCodec*)codecs->data;
- GList *iter = codec->optional_params;
- char id[8], clockrate[10], channels[10];
- gchar *codec_str;
- xmlnode *payload = xmlnode_new_child(description, "payload-type");
-
- g_snprintf(id, sizeof(id), "%d", codec->id);
- g_snprintf(clockrate, sizeof(clockrate), "%d", codec->clock_rate);
- g_snprintf(channels, sizeof(channels), "%d", codec->channels);
-
- xmlnode_set_attrib(payload, "name", codec->encoding_name);
- xmlnode_set_attrib(payload, "id", id);
- xmlnode_set_attrib(payload, "clockrate", clockrate);
- xmlnode_set_attrib(payload, "channels", channels);
-
- for (; iter; iter = g_list_next(iter)) {
- FsCodecParameter *fsparam = iter->data;
- xmlnode *param = xmlnode_new_child(payload, "parameter");
- xmlnode_set_attrib(param, "name", fsparam->name);
- xmlnode_set_attrib(param, "value", fsparam->value);
+ if (content != NULL) {
+ const gchar *senders = xmlnode_get_attrib(content, "senders");
+ gchar *local_senders = jingle_content_get_senders(local_content);
+ if (strcmp(senders, local_senders))
+ jingle_content_modify(local_content, senders);
+ g_free(local_senders);
+ } else {
+ purple_debug_error("jingle", "content_modify: unknown content\n");
+ /* XXX: send error */
}
-
- codec_str = fs_codec_to_string(codec);
- purple_debug_fatal("jingle", "adding codec: %s\n", codec_str);
- g_free(codec_str);
}
}
-static xmlnode *
-jabber_jingle_session_add_description_vv(const JingleSessionContent *jsc,
- xmlnode *description)
+static void
+jingle_handle_content_reject(JingleSession *session, xmlnode *jingle)
{
- xmlnode_set_attrib(description, "media",
- jabber_jingle_session_content_get_subtype(jsc));
- return description;
-}
+ xmlnode *content = xmlnode_get_child(jingle, "content");
+ jabber_iq_send(jingle_session_create_ack(session, jingle));
-static xmlnode *
-jabber_jingle_session_add_description(const JingleSessionContent *jsc,
- xmlnode *content)
-{
- xmlnode *description = xmlnode_new_child(content, "description");
- xmlnode_set_namespace(description,
- jabber_jingle_session_content_get_type(jsc));
-
- if (jabber_jingle_session_content_is_type(jsc, JINGLE_RTP))
- return jabber_jingle_session_add_description_vv(jsc, description);
- else
- return description;
-}
-
-static xmlnode *
-jabber_jingle_session_add_candidate_iceudp(xmlnode *transport,
- FsCandidate *c,
- FsCandidate *remote)
-{
- char port[8];
- char prio[8];
- char component[8];
- xmlnode *candidate = xmlnode_new_child(transport, "candidate");
-
- g_snprintf(port, sizeof(port), "%d", c->port);
- g_snprintf(prio, sizeof(prio), "%d", c->priority);
- g_snprintf(component, sizeof(component), "%d", c->component_id);
-
- xmlnode_set_attrib(candidate, "component", component);
- xmlnode_set_attrib(candidate, "foundation", "1"); /* what about this? */
- xmlnode_set_attrib(candidate, "generation", "0"); /* ? */
- xmlnode_set_attrib(candidate, "ip", c->ip);
- xmlnode_set_attrib(candidate, "network", "0"); /* ? */
- xmlnode_set_attrib(candidate, "port", port);
- xmlnode_set_attrib(candidate, "priority", prio); /* Is this correct? */
- xmlnode_set_attrib(candidate, "protocol",
- c->proto == FS_NETWORK_PROTOCOL_UDP ?
- "udp" : "tcp");
- if (c->username)
- xmlnode_set_attrib(transport, "ufrag", c->username);
- if (c->password)
- xmlnode_set_attrib(transport, "pwd", c->password);
-
- xmlnode_set_attrib(candidate, "type",
- c->type == FS_CANDIDATE_TYPE_HOST ?
- "host" :
- c->type == FS_CANDIDATE_TYPE_PRFLX ?
- "prflx" :
- c->type == FS_CANDIDATE_TYPE_RELAY ?
- "relay" :
- c->type == FS_CANDIDATE_TYPE_SRFLX ?
- "srflx" : NULL);
-
- /* relay */
- if (c->type == FS_CANDIDATE_TYPE_RELAY) {
- /* set rel-addr and rel-port? How? */
+ for (; content; content = xmlnode_get_next_twin(content)) {
+ const gchar *name = xmlnode_get_attrib(content, "name");
+ const gchar *creator = xmlnode_get_attrib(content, "creator");
+ jingle_session_remove_pending_content(session, name, creator);
+ /* signal here */
}
-
- if (remote) {
- char remote_port[8];
- g_snprintf(remote_port, sizeof(remote_port), "%d", remote->port);
- xmlnode_set_attrib(candidate, "rem-addr", remote->ip);
- xmlnode_set_attrib(candidate, "rem-port", remote_port);
- }
-
- return candidate;
}
-static xmlnode *
-jabber_jingle_session_add_transport(const JingleSessionContent *jsc,
- xmlnode *content)
+static void
+jingle_handle_content_remove(JingleSession *session, xmlnode *jingle)
{
- xmlnode *transport = xmlnode_new_child(content, "transport");
- const gchar *transport_type = jabber_jingle_session_content_get_transport_type(jsc);
- xmlnode_set_namespace(transport, transport_type);
- return transport;
-}
+ xmlnode *content = xmlnode_get_child(jingle, "content");
-static xmlnode *
-jabber_jingle_session_add_content(const JingleSessionContent *jsc,
- xmlnode *jingle)
-{
- xmlnode *content = xmlnode_new_child(jingle, "content");
- xmlnode_set_attrib(content, "creator",
- jabber_jingle_session_content_get_creator(jsc));
- xmlnode_set_attrib(content, "name",
- jabber_jingle_session_content_get_name(jsc));
- xmlnode_set_attrib(content, "sender",
- jabber_jingle_session_content_get_sender(jsc));
- return content;
-}
+ jabber_iq_send(jingle_session_create_ack(session, jingle));
-
-static xmlnode *
-jabber_jingle_session_add_jingle(const JingleSession *sess,
- JabberIq *iq, const char *action)
-{
- xmlnode *jingle = iq ? xmlnode_new_child(iq->node, "jingle") :
- xmlnode_new("jingle");
- xmlnode_set_namespace(jingle, JINGLE);
- xmlnode_set_attrib(jingle, "action", action);
- xmlnode_set_attrib(jingle, "initiator",
- jabber_jingle_session_get_initiator(sess));
- if (jabber_jingle_session_is_initiator(sess))
- xmlnode_set_attrib(jingle, "responder",
- jabber_jingle_session_get_remote_jid(sess));
- else {
- gchar *responder = g_strdup_printf("%s@%s/%s",
- sess->js->user->node,
- sess->js->user->domain,
- sess->js->user->resource);
- xmlnode_set_attrib(jingle, "responder", responder);
- g_free(responder);
+ for (; content; content = xmlnode_get_next_twin(content)) {
+ const gchar *name = xmlnode_get_attrib(content, "name");
+ const gchar *creator = xmlnode_get_attrib(content, "creator");
+ jingle_session_remove_content(session, name, creator);
}
- xmlnode_set_attrib(jingle, "sid", jabber_jingle_session_get_id(sess));
-
- return jingle;
}
-static JabberIq *
-jabber_jingle_session_create_ack(JingleSession *session, xmlnode *jingle)
+static void
+jingle_handle_session_accept(JingleSession *session, xmlnode *jingle)
{
- JabberIq *result = jabber_iq_new(
- jabber_jingle_session_get_js(session),
- JABBER_IQ_RESULT);
- xmlnode *packet = xmlnode_get_parent(jingle);
- jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
- xmlnode_set_attrib(result->node, "from", xmlnode_get_attrib(packet, "to"));
- xmlnode_set_attrib(result->node, "to", xmlnode_get_attrib(packet, "from"));
- return result;
-}
+ xmlnode *content = xmlnode_get_child(jingle, "content");
-static JabberIq *
-jabber_jingle_session_create_iq(const JingleSession *session)
-{
- JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
- JABBER_IQ_SET);
- gchar *from = g_strdup_printf("%s@%s/%s", session->js->user->node,
- session->js->user->domain,
- session->js->user->resource);
- xmlnode_set_attrib(result->node, "from", from);
- g_free(from);
- xmlnode_set_attrib(result->node, "to",
- jabber_jingle_session_get_remote_jid(session));
- return result;
-}
-#if 0
-static xmlnode *
-jabber_jingle_session_create_content_accept(const JingleSession *sess)
-{
- xmlnode *jingle =
- jabber_jingle_session_add_jingle(sess, NULL, "content-accept");
+ jabber_iq_send(jingle_session_create_ack(session, jingle));
- xmlnode *content = xmlnode_new_child(jingle, "content");
- xmlnode *description = jabber_jingle_session_create_description(sess);
-
- xmlnode_set_attrib(content, "creator", "initiator");
- xmlnode_set_attrib(content, "name", "audio-content");
- xmlnode_set_attrib(content, "profile", "RTP/AVP");
-
- xmlnode_insert_child(content, description);
-
- return jingle;
-}
-
-static xmlnode *
-jabber_jingle_session_create_content_replace(const JingleSession *sess,
- FsCandidate *native_candidate,
- FsCandidate *remote_candidate)
-{
- xmlnode *jingle =
- jabber_jingle_session_add_jingle(sess, NULL, "content-replace");
- xmlnode *content = NULL;
- xmlnode *transport = NULL;
-
- purple_debug_info("jingle", "creating content-modify for native candidate %s " \
- ", remote candidate %s\n", native_candidate->candidate_id,
- remote_candidate->candidate_id);
-
- content = xmlnode_new_child(jingle, "content");
- xmlnode_set_attrib(content, "creator", "initiator");
- xmlnode_set_attrib(content, "name", "audio-content");
- xmlnode_set_attrib(content, "profile", "RTP/AVP");
+ jingle_session_accept_session(session);
- /* get top codec from codec_intersection to put here... */
- /* later on this should probably handle changing codec */
-
- xmlnode_insert_child(content, jabber_jingle_session_create_description(sess));
-
- transport = xmlnode_new_child(content, "transport");
- xmlnode_set_namespace(transport, TRANSPORT_ICEUDP);
- jabber_jingle_session_add_candidate_iceudp(transport, native_candidate,
- remote_candidate);
-
- purple_debug_info("jingle", "End create content modify\n");
-
- return jingle;
-}
-#endif
-
-static JabberIq *
-jabber_jingle_session_create_session_accept(const JingleSession *session)
-{
- PurpleMedia *media = jabber_jingle_session_get_media(session);
- const gchar *remote_jid = jabber_jingle_session_get_remote_jid(session);
- JabberIq *request = jabber_jingle_session_create_iq(session);
- xmlnode *jingle =
- jabber_jingle_session_add_jingle(session, request,
- "session-accept");
- GList *contents = jabber_jingle_session_get_contents(session);
-
- for (; contents; contents = contents->next) {
- JingleSessionContent *jsc = contents->data;
- const gchar *content_name = jabber_jingle_session_content_get_name(jsc);
- xmlnode *content = jabber_jingle_session_add_content(jsc, jingle);
- xmlnode *description = jabber_jingle_session_add_description(jsc, content);
- xmlnode *transport = jabber_jingle_session_add_transport(jsc, content);
- if (jabber_jingle_session_content_is_type(jsc, JINGLE_RTP)) {
- GList *codecs = purple_media_get_negotiated_codecs(media,
- content_name);
- jabber_jingle_session_add_payload_types(jsc, description, codecs);
- fs_codec_list_destroy(codecs);
+ for (; content; content = xmlnode_get_next_twin(content)) {
+ const gchar *name = xmlnode_get_attrib(content, "name");
+ const gchar *creator = xmlnode_get_attrib(content, "creator");
+ JingleContent *content = jingle_session_find_content(session, name, creator);
+ if (content == NULL) {
+ purple_debug_error("jingle", "Error parsing content\n");
+ /* XXX: send error */
+ } else {
+ jingle_content_handle_action(content, jingle,
+ JINGLE_SESSION_ACCEPT);
}
- if (jabber_jingle_session_content_is_transport_type(jsc, TRANSPORT_ICEUDP)) {
- jabber_jingle_session_add_candidate_iceudp(transport,
- purple_media_get_local_candidate(media, content_name,
- remote_jid),
- purple_media_get_remote_candidate(media, content_name,
- remote_jid));
- }
}
-
- return request;
}
-static JabberIq *
-jabber_jingle_session_create_session_info(const JingleSession *session,
- const gchar *type)
-{
- JabberIq *request = jabber_jingle_session_create_iq(session);
- xmlnode *jingle =
- jabber_jingle_session_add_jingle(session, request,
- "session-info");
- xmlnode *info = xmlnode_new_child(jingle, type);
- xmlnode_set_namespace(info, JINGLE_RTP_INFO);
- return request;
-}
-
-static JabberIq *
-jabber_jingle_session_create_session_initiate(const JingleSession *session)
-{
- JabberIq *request = jabber_jingle_session_create_iq(session);
- xmlnode *jingle =
- jabber_jingle_session_add_jingle(session, request,
- "session-initiate");
- GList *contents = jabber_jingle_session_get_contents(session);
-
- for (; contents; contents = contents->next) {
- JingleSessionContent *jsc = contents->data;
- xmlnode *content = jabber_jingle_session_add_content(jsc, jingle);
- xmlnode *description = jabber_jingle_session_add_description(jsc, content);
- if (jabber_jingle_session_content_is_type(jsc, JINGLE_RTP)) {
- PurpleMedia *media = jabber_jingle_session_get_media(session);
- const gchar *content_name =
- jabber_jingle_session_content_get_name(jsc);
- GList *codecs = purple_media_get_local_codecs(media, content_name);
- jabber_jingle_session_add_payload_types(jsc, description, codecs);
- fs_codec_list_destroy(codecs);
- }
- jabber_jingle_session_add_transport(jsc, content);
- }
-
- return request;
-}
-
-static JabberIq *
-jabber_jingle_session_create_session_terminate(const JingleSession *sess,
- const char *reasoncode,
- const char *reasontext)
-{
- JabberIq *request = jabber_jingle_session_create_iq(sess);
- xmlnode *jingle =
- jabber_jingle_session_add_jingle(sess, request,
- "session-terminate");
- xmlnode *reason = xmlnode_new_child(jingle, "reason");
- xmlnode_new_child(reason, reasoncode);
- if (reasontext) {
- xmlnode *text = xmlnode_new_child(reason, "text");
- xmlnode_insert_data(text, reasontext, strlen(reasontext));
- }
-
- return request;
-}
-
-static JabberIq *
-jabber_jingle_session_create_transport_info(const JingleSessionContent *jsc,
- FsCandidate *candidate)
-{
- JingleSession *session =
- jabber_jingle_session_content_get_session(jsc);
- JabberIq *request = jabber_jingle_session_create_iq(session);
- xmlnode *jingle =
- jabber_jingle_session_add_jingle(session, request,
- "transport-info");
- xmlnode *content = jabber_jingle_session_add_content(jsc, jingle);
- xmlnode *transport = jabber_jingle_session_add_transport(jsc, content);
- jabber_jingle_session_add_candidate_iceudp(transport, candidate, NULL);
- return request;
-}
-#if 0
static void
-jabber_jingle_session_send_content_accept(JingleSession *session)
+jingle_handle_session_info(JingleSession *session, xmlnode *jingle)
{
- JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
- JABBER_IQ_SET);
- xmlnode *jingle = jabber_jingle_session_create_content_accept(session);
- xmlnode_set_attrib(result->node, "to",
- jabber_jingle_session_get_remote_jid(session));
-
- xmlnode_insert_child(result->node, jingle);
- jabber_iq_send(result);
+ jabber_iq_send(jingle_session_create_ack(session, jingle));
+ /* XXX: call signal */
}
-#endif
static void
-jabber_jingle_session_accept(JingleSession *session)
+jingle_handle_session_initiate(JingleSession *session, xmlnode *jingle)
{
- if (jabber_jingle_session_get_state(session) == ACCEPTED &&
- purple_media_candidates_prepared(
- jabber_jingle_session_get_media(session),
- jabber_jingle_session_get_remote_jid(session))) {
- jabber_iq_send(jabber_jingle_session_create_session_accept(session));
-
- purple_debug_info("jingle", "Sent session accept.\n");
- jabber_jingle_session_set_state(session, ACTIVE);
- }
-}
+ xmlnode *content = xmlnode_get_child(jingle, "content");
-static void
-jabber_jingle_session_send_session_accept(JingleSession *session)
-{
- /* create transport-info packages */
- PurpleMedia *media = jabber_jingle_session_get_media(session);
- GList *contents = jabber_jingle_session_get_contents(session);
- const gchar *remote_jid = jabber_jingle_session_get_remote_jid(session);
- for (; contents; contents = contents->next) {
- JingleSessionContent *jsc = contents->data;
- GList *candidates = purple_media_get_local_candidates(
- media,
- jabber_jingle_session_content_get_name(jsc),
- remote_jid);
- purple_debug_info("jingle",
- "jabber_session_candidates_prepared: %d candidates\n",
- g_list_length(candidates));
- for (; candidates; candidates = candidates->next) {
- FsCandidate *candidate = candidates->data;
- JabberIq *result = jabber_jingle_session_create_transport_info(jsc,
- candidate);
- jabber_iq_send(result);
+ for (; content; content = xmlnode_get_next_twin(content)) {
+ JingleContent *parsed_content = jingle_content_parse(content);
+ if (parsed_content == NULL) {
+ purple_debug_error("jingle", "Error parsing content\n");
+ /* XXX: send error */
+ } else {
+ jingle_session_add_content(session, parsed_content);
+ jingle_content_handle_action(parsed_content, jingle,
+ JINGLE_SESSION_INITIATE);
}
- fs_candidate_list_destroy(candidates);
-
- purple_debug_info("jingle", "codec intersection: %i\n",
- g_list_length(purple_media_get_negotiated_codecs(media,
- jabber_jingle_session_content_get_name(jsc))));
}
- jabber_jingle_session_set_state(session, ACCEPTED);
- jabber_jingle_session_accept(session);
+ jabber_iq_send(jingle_session_create_ack(session, jingle));
}
static void
-jabber_jingle_session_send_session_reject(JingleSession *session)
+jingle_handle_session_terminate(JingleSession *session, xmlnode *jingle)
{
- jabber_iq_send(jabber_jingle_session_create_session_terminate(session,
- "decline", NULL));
- jabber_jingle_session_destroy(session);
-}
+ jabber_iq_send(jingle_session_create_ack(session, jingle));
-static void
-jabber_jingle_session_send_session_terminate(JingleSession *session)
-{
- jabber_iq_send(jabber_jingle_session_create_session_terminate(session,
- "no-error", NULL));
- jabber_jingle_session_destroy(session);
+ jingle_session_handle_action(session, jingle,
+ JINGLE_SESSION_TERMINATE);
+ /* display reason? */
+ g_object_unref(session);
}
static void
-jabber_jingle_session_content_create_media(JingleSession *session,
- PurpleMediaSessionType type)
+jingle_handle_transport_accept(JingleSession *session, xmlnode *jingle)
{
- gchar sender[10] = "";
+ xmlnode *content = xmlnode_get_child(jingle, "content");
- if (type & PURPLE_MEDIA_AUDIO) {
- if ((type & PURPLE_MEDIA_AUDIO) == PURPLE_MEDIA_SEND_AUDIO)
- strcpy(sender, "initiator");
- else if ((type & PURPLE_MEDIA_AUDIO) == PURPLE_MEDIA_RECV_AUDIO)
- strcpy(sender, "responder");
- else
- strcpy(sender, "both");
- jabber_jingle_session_content_create_internal(session,
- "audio-content", "initiator", sender,
- TRANSPORT_ICEUDP, JINGLE_RTP, "audio");
+ jabber_iq_send(jingle_session_create_ack(session, jingle));
+
+ for (; content; content = xmlnode_get_next_twin(content)) {
+ const gchar *name = xmlnode_get_attrib(content, "name");
+ const gchar *creator = xmlnode_get_attrib(content, "creator");
+ JingleContent *content = jingle_session_find_content(session, name, creator);
+ jingle_content_accept_transport(content);
}
- if (type & PURPLE_MEDIA_VIDEO) {
- if ((type & PURPLE_MEDIA_VIDEO) == PURPLE_MEDIA_SEND_VIDEO)
- strcpy(sender, "initiator");
- else if ((type & PURPLE_MEDIA_VIDEO) == PURPLE_MEDIA_RECV_VIDEO)
- strcpy(sender, "responder");
- else
- strcpy(sender, "both");
- jabber_jingle_session_content_create_internal(session,
- "video-content", "initiator", sender,
- TRANSPORT_ICEUDP, JINGLE_RTP, "video");
- }
}
static void
-jabber_jingle_session_content_create_parse(JingleSession *session,
- xmlnode *content)
+jingle_handle_transport_info(JingleSession *session, xmlnode *jingle)
{
- xmlnode *description = xmlnode_get_child(content, "description");
- xmlnode *transport = xmlnode_get_child(content, "transport");
+ xmlnode *content = xmlnode_get_child(jingle, "content");
- const gchar *creator = xmlnode_get_attrib(content, "creator");
- const gchar *sender = xmlnode_get_attrib(content, "sender");
- const gchar *subtype = xmlnode_get_attrib(description, "media");
+ jabber_iq_send(jingle_session_create_ack(session, jingle));
- jabber_jingle_session_content_create_internal(session,
- xmlnode_get_attrib(content, "name"),
- creator ? creator : "initiator",
- sender ? sender : "both",
- xmlnode_get_namespace(transport),
- xmlnode_get_namespace(description),
- subtype);
-}
-
-static void
-jabber_jingle_session_new_candidate_cb(PurpleMedia *media,
- const gchar *session_id,
- const gchar *name,
- FsCandidate *candidate,
- JingleSession *session)
-{
- if (jabber_jingle_session_get_state(session) == GOT_ACK ||
- jabber_jingle_session_get_state(session) == ACTIVE) {
- JingleSessionContent *jsc = jabber_jingle_session_get_content(session,
- session_id);
- jabber_iq_send(jabber_jingle_session_create_transport_info(jsc,
- candidate));
- }
-}
-
-/* callback called when a pair of transport candidates (local and remote)
- has been established */
-static void
-jabber_jingle_session_candidate_pair_established_cb(PurpleMedia *media,
- FsCandidate *native_candidate,
- FsCandidate *remote_candidate,
- JingleSession *session)
-{
- if (!jabber_jingle_session_is_initiator(session)) {
- jabber_jingle_session_accept(session);
- }
-}
-
-static void
-jabber_jingle_session_initiate_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
-{
- const char *from = xmlnode_get_attrib(packet, "from");
- JingleSession *session = jabber_jingle_session_find_by_jid(js, from);
- PurpleMedia *media;
- GList *contents;
-
- if (!session) {
- /* respond with an error here */
- purple_debug_error("jingle", "Received session-initiate ack"
- " to nonexistent session\n");
- return;
- }
-
- media = session->media;
-
- if (!strcmp(xmlnode_get_attrib(packet, "type"), "error")) {
- purple_media_got_hangup(media);
- return;
- }
-
- /* catch errors */
- if (xmlnode_get_child(packet, "error")) {
- purple_media_got_hangup(media);
- return;
- }
-
- /* create transport-info packages */
- contents = jabber_jingle_session_get_contents(session);
- for (; contents; contents = contents->next) {
- JingleSessionContent *jsc = contents->data;
- GList *candidates = purple_media_get_local_candidates(
- jabber_jingle_session_get_media(session),
- jabber_jingle_session_content_get_name(jsc),
- jabber_jingle_session_get_remote_jid(session));
- purple_debug_info("jingle",
- "jabber_session_candidates_prepared: %d candidates\n",
- g_list_length(candidates));
- for (; candidates; candidates = candidates->next) {
- FsCandidate *candidate = candidates->data;
- JabberIq *result = jabber_jingle_session_create_transport_info(jsc,
- candidate);
- jabber_iq_send(result);
+ for (; content; content = xmlnode_get_next_twin(content)) {
+ const gchar *name = xmlnode_get_attrib(content, "name");
+ const gchar *creator = xmlnode_get_attrib(content, "creator");
+ JingleContent *content = jingle_session_find_content(session, name, creator);
+ if (content == NULL) {
+ purple_debug_error("jingle", "Error parsing content\n");
+ /* XXX: send error */
+ } else {
+ jingle_content_handle_action(content, jingle,
+ JINGLE_TRANSPORT_INFO);
}
- fs_candidate_list_destroy(candidates);
}
-
- jabber_jingle_session_set_state(session, GOT_ACK);
}
static void
-jabber_jingle_session_codecs_ready_cb(PurpleMedia *media,
- const gchar *sess_id,
- JingleSession *session)
+jingle_handle_transport_reject(JingleSession *session, xmlnode *jingle)
{
- GList *contents = jabber_jingle_session_get_contents(session);
- for (; contents; contents = g_list_delete_link(contents, contents)) {
- JingleSessionContent *jsc = contents->data;
- if (!purple_media_codecs_ready(media,
- jabber_jingle_session_content_get_name(jsc))) {
- break;
- }
- }
+ xmlnode *content = xmlnode_get_child(jingle, "content");
- if (contents != NULL)
- g_list_free(contents);
- else if (jabber_jingle_session_is_initiator(session)
- && jabber_jingle_session_get_state(session) == PENDING) {
- JabberIq *request;
-
- /* create request */
- request = jabber_jingle_session_create_session_initiate(session);
- jabber_iq_set_callback(request, jabber_jingle_session_initiate_result_cb, NULL);
-
- /* send request to other part */
- jabber_iq_send(request);
- } else {
- jabber_jingle_session_accept(session);
- }
-}
-
-static gboolean
-jabber_jingle_session_initiate_media_internal(JingleSession *session,
- const char *initiator,
- const char *remote_jid)
-{
- PurpleMedia *media = NULL;
- GList *contents = jabber_jingle_session_get_contents(session);
-
- media = purple_media_manager_create_media(purple_media_manager_get(),
- session->js->gc, "fsrtpconference", remote_jid);
-
- jabber_jingle_session_set_remote_jid(session, remote_jid);
- jabber_jingle_session_set_initiator(session, initiator);
-
- if (!media) {
- purple_debug_error("jingle", "Couldn't create media session\n");
- return FALSE;
- }
-
- jabber_jingle_session_set_media(session, media);
-
- for (; contents; contents = g_list_delete_link(contents, contents)) {
- JingleSessionContent *jsc = contents->data;
- gboolean result = FALSE;
- const gchar *sender = jabber_jingle_session_content_get_sender(jsc);
- FsStreamDirection direction = FS_DIRECTION_NONE;
-
- if (!strcmp(sender, "initiator"))
- direction = FS_DIRECTION_SEND;
- else if(!strcmp(sender, "responder"))
- direction = FS_DIRECTION_RECV;
- else
- direction = FS_DIRECTION_BOTH;
-
- if (!jabber_jingle_session_is_initiator(session)
- && direction != FS_DIRECTION_BOTH) {
- if (direction == FS_DIRECTION_SEND)
- direction = FS_DIRECTION_RECV;
- else
- direction = FS_DIRECTION_SEND;
- }
-
- /* these will need to be changed to "nice" once the libnice transmitter is finished */
- if (jabber_jingle_session_content_is_vv_type(jsc, "audio")) {
- result = purple_media_add_stream(media, "audio-content", remote_jid,
- purple_media_from_fs(FS_MEDIA_TYPE_AUDIO, direction),
- "rawudp", 0, NULL);
- purple_debug_info("jingle", "Created Jingle audio session\n");
- }
- else if (jabber_jingle_session_content_is_vv_type(jsc, "video")) {
- result = purple_media_add_stream(media, "video-content", remote_jid,
- purple_media_from_fs(FS_MEDIA_TYPE_VIDEO, direction),
- "rawudp", 0, NULL);
- purple_debug_info("jingle", "Created Jingle video session\n");
- }
-
- if (!result) {
- purple_debug_error("jingle", "Couldn't create stream\n");
- purple_media_hangup(media);
- return FALSE;
- }
- }
-
- /* connect callbacks */
- g_signal_connect_swapped(G_OBJECT(media), "accepted",
- G_CALLBACK(jabber_jingle_session_send_session_accept), session);
- g_signal_connect_swapped(G_OBJECT(media), "reject",
- G_CALLBACK(jabber_jingle_session_send_session_reject), session);
- g_signal_connect_swapped(G_OBJECT(media), "hangup",
- G_CALLBACK(jabber_jingle_session_send_session_terminate), session);
- g_signal_connect(G_OBJECT(media), "new-candidate",
- G_CALLBACK(jabber_jingle_session_new_candidate_cb), session);
- g_signal_connect(G_OBJECT(media), "candidate-pair",
- G_CALLBACK(jabber_jingle_session_candidate_pair_established_cb), session);
- g_signal_connect(G_OBJECT(media), "codecs-ready",
- G_CALLBACK(jabber_jingle_session_codecs_ready_cb), session);
-
- purple_media_ready(media);
-
- return TRUE;
-}
-
-PurpleMedia *
-jabber_jingle_session_initiate_media(JabberStream *js, const char *who,
- PurpleMediaSessionType type)
-{
- /* create content negotiation */
- JingleSession *session;
- JabberBuddy *jb;
- JabberBuddyResource *jbr;
+ jabber_iq_send(jingle_session_create_ack(session, jingle));
- char *jid = NULL, *me = NULL;
-
- /* construct JID to send to */
- jb = jabber_buddy_find(js, who, FALSE);
- if (!jb) {
- purple_debug_error("jingle", "Could not find Jabber buddy\n");
- return NULL;
+ for (; content; content = xmlnode_get_next_twin(content)) {
+ const gchar *name = xmlnode_get_attrib(content, "name");
+ const gchar *creator = xmlnode_get_attrib(content, "creator");
+ JingleContent *content = jingle_session_find_content(session, name, creator);
+ jingle_content_remove_pending_transport(content);
}
- jbr = jabber_buddy_find_resource(jb, NULL);
- if (!jbr) {
- purple_debug_error("jingle", "Could not find buddy's resource\n");
- }
-
- if ((strchr(who, '/') == NULL) && jbr && (jbr->name != NULL)) {
- jid = g_strdup_printf("%s/%s", who, jbr->name);
- } else {
- jid = g_strdup(who);
- }
-
- session = jabber_jingle_session_create(js);
- jabber_jingle_session_content_create_media(session, type);
-
- /* set ourselves as initiator */
- me = g_strdup_printf("%s@%s/%s", js->user->node, js->user->domain, js->user->resource);
-
- if (!jabber_jingle_session_initiate_media_internal(session, me, jid)) {
- g_free(jid);
- g_free(me);
- jabber_jingle_session_destroy(session);
- return NULL;
- }
-
- g_free(jid);
- g_free(me);
-
- return session->media;
}
-void
-jabber_jingle_session_terminate_session_media(JabberStream *js, const gchar *who)
-{
- JingleSession *session;
-
- session = jabber_jingle_session_find_by_jid(js, who);
-
- if (session)
- purple_media_hangup(session->media);
-}
-
-void
-jabber_jingle_session_terminate_sessions(JabberStream *js)
-{
- GList *values = js->sessions ?
- g_hash_table_get_values(js->sessions) : NULL;
-
- for (; values; values = g_list_delete_link(values, values)) {
- JingleSession *session = (JingleSession *)values->data;
- purple_media_hangup(session->media);
- }
-}
-
static void
-jabber_jingle_session_handle_content_replace(JingleSession *session, xmlnode *jingle)
+jingle_handle_transport_replace(JingleSession *session, xmlnode *jingle)
{
-#if 0
- xmlnode *jingle = xmlnode_get_child(packet, "jingle");
- const char *sid = xmlnode_get_attrib(jingle, "sid");
- JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
-
- if (!jabber_jingle_session_is_initiator(session) && session->session_started) {
- JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT);
- JabberIq *accept = jabber_iq_new(js, JABBER_IQ_SET);
- xmlnode *content_accept = NULL;
-
- /* send acknowledement */
- xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
- xmlnode_set_attrib(result->node, "to", xmlnode_get_attrib(packet, "from"));
- jabber_iq_send(result);
-
- /* send content-accept */
- content_accept = jabber_jingle_session_create_content_accept(session);
- xmlnode_set_attrib(accept->node, "id", xmlnode_get_attrib(packet, "id"));
- xmlnode_set_attrib(accept->node, "to", xmlnode_get_attrib(packet, "from"));
- xmlnode_insert_child(accept->node, content_accept);
-
- jabber_iq_send(accept);
- }
-#endif
-}
-
-static void
-jabber_jingle_session_handle_session_accept(JingleSession *session, xmlnode *jingle)
-{
xmlnode *content = xmlnode_get_child(jingle, "content");
- const char *action = xmlnode_get_attrib(jingle, "action");
- GList *remote_codecs = NULL;
- GList *remote_transports = NULL;
- GList *codec_intersection;
- FsCodec *top = NULL;
- xmlnode *description = NULL;
- xmlnode *transport = NULL;
- /* We should probably check validity of the incoming XML... */
+ jabber_iq_send(jingle_session_create_ack(session, jingle));
- for (content = xmlnode_get_child(jingle, "content"); content;
- content = xmlnode_get_next_twin(content)) {
- description = xmlnode_get_child(content, "description");
- transport = xmlnode_get_child(content, "transport");
+ for (; content; content = xmlnode_get_next_twin(content)) {
+ const gchar *name = xmlnode_get_attrib(content, "name");
+ const gchar *creator = xmlnode_get_attrib(content, "creator");
+ xmlnode *xmltransport = xmlnode_get_child(content, "transport");
+ JingleTransport *transport = jingle_transport_parse(xmltransport);
+ JingleContent *content = jingle_session_find_content(session, name, creator);
- /* fetch codecs from remote party */
- purple_debug_info("jingle", "get codecs from session-accept\n");
- remote_codecs = jabber_jingle_get_codecs(description);
- purple_debug_info("jingle", "get transport candidates from session accept\n");
- remote_transports = jabber_jingle_get_candidates(transport);
-
- purple_debug_info("jingle", "Got %d codecs from responder\n",
- g_list_length(remote_codecs));
- purple_debug_info("jingle", "Got %d transport candidates from responder\n",
- g_list_length(remote_transports));
-
- purple_debug_info("jingle", "Setting remote codecs on stream\n");
-
- if (!purple_media_set_remote_codecs(session->media,
- xmlnode_get_attrib(content, "name"),
- jabber_jingle_session_get_remote_jid(session),
- remote_codecs)) {
- purple_media_reject(jabber_jingle_session_get_media(session));
- return;
- }
-
- codec_intersection = purple_media_get_negotiated_codecs(session->media,
- xmlnode_get_attrib(content, "name"));
- purple_debug_info("jingle", "codec_intersection contains %d elems\n",
- g_list_length(codec_intersection));
- /* get the top codec */
- if (g_list_length(codec_intersection) > 0) {
- top = (FsCodec *) codec_intersection->data;
- purple_debug_info("jingle", "Found a suitable codec on stream = %d\n",
- top->id);
-
- /* we have found a suitable codec, but we will not start the stream
- just yet, wait for transport negotiation to complete... */
- purple_media_set_send_codec(
- jabber_jingle_session_get_media(session),
- xmlnode_get_attrib(content, "name"),
- codec_intersection->data);
- }
- /* if we also got transport candidates, add them to our streams
- list of known remote candidates */
- if (g_list_length(remote_transports) > 0) {
- purple_media_add_remote_candidates(session->media,
- xmlnode_get_attrib(content, "name"),
- jabber_jingle_session_get_remote_jid(session),
- remote_transports);
- fs_candidate_list_destroy(remote_transports);
- }
- if (g_list_length(codec_intersection) == 0 &&
- g_list_length(remote_transports)) {
- /* we didn't get any candidates and the codec intersection is empty,
- this means this was not a content-accept message and we couldn't
- find any suitable codecs, should return error and hang up */
-
- }
-
- fs_codec_list_destroy(codec_intersection);
-
+ jingle_content_set_pending_transport(content, transport);
}
-
- if (!strcmp(action, "session-accept")) {
- purple_media_got_accept(jabber_jingle_session_get_media(session));
- purple_debug_info("jingle", "Got session-accept\n");
- }
-
- jabber_iq_send(jabber_jingle_session_create_ack(session, jingle));
-
- jabber_jingle_session_set_state(session, ACTIVE);
}
-static void
-jabber_jingle_session_handle_session_info(JingleSession *session, xmlnode *jingle)
-{
- purple_debug_info("jingle", "got session-info\n");
- jabber_iq_send(jabber_jingle_session_create_ack(session, jingle));
-}
-static void
-jabber_jingle_session_handle_session_initiate(JingleSession *session, xmlnode *jingle)
-{
- xmlnode *content = NULL;
- xmlnode *description = NULL;
- xmlnode *transport = NULL;
- const char *initiator = NULL;
- GList *codecs = NULL;
-
- if (!jingle) {
- purple_debug_error("jingle", "Malformed request\n");
- return;
- }
-
- initiator = xmlnode_get_attrib(jingle, "initiator");
-
- for (content = xmlnode_get_child(jingle, "content"); content;
- content = xmlnode_get_next_twin(content)) {
- /* init media */
- if (!content) {
- purple_debug_error("jingle", "jingle tag must contain content tag\n");
- /* should send error here */
- return;
- }
-
- description = xmlnode_get_child(content, "description");
-
- if (!description) {
- purple_debug_error("jingle", "content tag must contain description tag\n");
- /* we should create an error iq here */
- return;
- }
-
- transport = xmlnode_get_child(content, "transport");
-
- if (!transport) {
- purple_debug_error("jingle", "content tag must contain transport tag\n");
- /* we should create an error iq here */
- return;
- }
-
- jabber_jingle_session_content_create_parse(session, content);
- }
-
- if (!jabber_jingle_session_initiate_media_internal(session, initiator, initiator)) {
- purple_debug_error("jingle", "Couldn't start media session with %s\n", initiator);
- jabber_jingle_session_send_session_reject(session);
- return;
- }
-
- for (content = xmlnode_get_child(jingle, "content"); content;
- content = xmlnode_get_next_twin(content)) {
- GList *codec_intersection = NULL;
-
- /* init media */
- if (!content) {
- purple_debug_error("jingle", "jingle tag must contain content tag\n");
- /* should send error here */
- return;
- }
-
- description = xmlnode_get_child(content, "description");
-
- if (!description) {
- purple_debug_error("jingle", "content tag must contain description tag\n");
- /* we should create an error iq here */
- return;
- }
- codecs = jabber_jingle_get_codecs(description);
-
- purple_media_set_remote_codecs(session->media,
- xmlnode_get_attrib(content, "name"),
- initiator, codecs);
-
- codec_intersection = purple_media_get_negotiated_codecs(session->media,
- xmlnode_get_attrib(content, "name"));
- purple_debug_info("jingle", "codec intersection: %i\n",
- g_list_length(codec_intersection));
-
- if (g_list_length(codec_intersection) > 0) {
- purple_media_set_send_codec(
- jabber_jingle_session_get_media(session),
- xmlnode_get_attrib(content, "name"),
- codec_intersection->data);
- }
- }
- jabber_iq_send(jabber_jingle_session_create_ack(session, jingle));
- jabber_iq_send(jabber_jingle_session_create_session_info(session, "ringing"));
-
- purple_media_got_request(jabber_jingle_session_get_media(session));
-}
-
-static void
-jabber_jingle_session_handle_session_terminate(JingleSession *session, xmlnode *jingle)
-{
- if (!session) {
- purple_debug_error("jingle", "jabber_handle_session_terminate couldn't find session\n");
- return;
- }
-
- /* maybe we should look at the reasoncode to determine if it was
- a hangup or a reject, and call different callbacks to purple_media */
- purple_media_got_hangup(jabber_jingle_session_get_media(session));
- jabber_iq_send(jabber_jingle_session_create_ack(session, jingle));
- jabber_jingle_session_destroy(session);
-}
-
-static void
-jabber_jingle_session_handle_transport_info(JingleSession *session, xmlnode *jingle)
-{
- xmlnode *content = xmlnode_get_child(jingle, "content");
- xmlnode *transport = xmlnode_get_child(content, "transport");
- GList *remote_candidates = jabber_jingle_get_candidates(transport);
-
- if (!session)
- purple_debug_error("jingle", "jabber_handle_session_candidates couldn't find session\n");
-
- /* send acknowledement */
- jabber_iq_send(jabber_jingle_session_create_ack(session, jingle));
-
- /* add candidates to our list of remote candidates */
- if (g_list_length(remote_candidates) > 0) {
- purple_media_add_remote_candidates(session->media,
- xmlnode_get_attrib(content, "name"),
- xmlnode_get_attrib(xmlnode_get_parent(jingle), "from"),
- remote_candidates);
- fs_candidate_list_destroy(remote_candidates);
- }
-}
-
void
-jabber_jingle_session_parse(JabberStream *js, xmlnode *packet)
+jingle_parse(JabberStream *js, xmlnode *packet)
{
const gchar *type = xmlnode_get_attrib(packet, "type");
xmlnode *jingle;
const gchar *action;
- const char *sid;
+ const gchar *sid;
JingleSession *session;
if (!type || strcmp(type, "set")) {
@@ -1478,7 +365,7 @@ jabber_jingle_session_parse(JabberStream
return;
}
- if (!(session = jabber_jingle_session_find_by_id(js, sid))
+ if (!(session = jingle_session_find_by_sid(js, sid))
&& strcmp(action, "session-initiate")) {
purple_debug_error("jingle", "jabber_jingle_session_parse couldn't find session\n");
/* send iq error here */
@@ -1491,7 +378,7 @@ jabber_jingle_session_parse(JabberStream
purple_debug_error("jingle", "Jingle session with "
"id={%s} already exists\n", sid);
/* send iq error */
- } else if ((session = jabber_jingle_session_find_by_jid(js,
+ } else if ((session = jingle_session_find_by_jid(js,
xmlnode_get_attrib(packet, "from")))) {
purple_debug_fatal("jingle", "Jingle session with "
"jid={%s} already exists\n",
@@ -1499,22 +386,47 @@ jabber_jingle_session_parse(JabberStream
/* send jingle redirect packet */
return;
} else {
- session = jabber_jingle_session_create_by_id(js, sid);
- jabber_jingle_session_handle_session_initiate(session, jingle);
+ session = jingle_session_create(js, sid,
+ xmlnode_get_attrib(packet, "to"),
+ xmlnode_get_attrib(packet, "from"), FALSE);
+ jingle_handle_session_initiate(session, jingle);
}
- } else if (!strcmp(action, "session-accept")
- || !strcmp(action, "content-accept")) {
- jabber_jingle_session_handle_session_accept(session, jingle);
+ } else if (!strcmp(action, "content-accept")) {
+ jingle_handle_content_accept(session, jingle);
+ } else if (!strcmp(action, "content-add")) {
+ jingle_handle_content_add(session, jingle);
+ } else if (!strcmp(action, "content-modify")) {
+ jingle_handle_content_modify(session, jingle);
+ } else if (!strcmp(action, "content-reject")) {
+ jingle_handle_content_reject(session, jingle);
+ } else if (!strcmp(action, "content-remove")) {
+ jingle_handle_content_remove(session, jingle);
+ } else if (!strcmp(action, "session-accept")) {
+ jingle_handle_session_accept(session, jingle);
} else if (!strcmp(action, "session-info")) {
- jabber_jingle_session_handle_session_info(session, jingle);
+ jingle_handle_session_info(session, jingle);
} else if (!strcmp(action, "session-terminate")) {
- jabber_jingle_session_handle_session_terminate(session, jingle);
+ jingle_handle_session_terminate(session, jingle);
+ } else if (!strcmp(action, "transport-accept")) {
+ jingle_handle_transport_accept(session, jingle);
} else if (!strcmp(action, "transport-info")) {
- jabber_jingle_session_handle_transport_info(session, jingle);
- } else if (!strcmp(action, "content-replace")) {
- jabber_jingle_session_handle_content_replace(session, jingle);
+ jingle_handle_transport_info(session, jingle);
+ } else if (!strcmp(action, "transport-reject")) {
+ jingle_handle_transport_reject(session, jingle);
+ } else if (!strcmp(action, "transport-replace")) {
+ jingle_handle_transport_replace(session, jingle);
}
}
-#endif /* USE_VV */
+void
+jingle_terminate_sessions(JabberStream *js)
+{
+ GList *values = js->sessions ?
+ g_hash_table_get_values(js->sessions) : NULL;
+ for (; values; values = g_list_delete_link(values, values)) {
+ JingleSession *session = (JingleSession *)values->data;
+ g_object_unref(session);
+ }
+}
+
============================================================
--- libpurple/protocols/jabber/jingle.h e068bce654e60495dee1841107f40cd9a48ba6b6
+++ libpurple/protocols/jabber/jingle/jingle.h 9e27c85dda189559bffeeb670f8213ed4ef61d83
@@ -1,4 +1,6 @@
/*
+ * @file jingle.h
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -17,33 +19,63 @@
#ifndef JINGLE_H
#define JINGLE_H
-#include "config.h"
#include "jabber.h"
-#include "media.h"
#include <glib.h>
#include <glib-object.h>
-/*
- * When Jingle content types other than voice and video are implemented,
- * this #ifdef others surrounding Jingle code should be changed to just
- * be around the voice and video specific parts.
- */
-#ifdef USE_VV
+G_BEGIN_DECLS
-G_BEGIN_DECLS
+#ifdef __cplusplus
+extern "C" {
+#endif
-void jabber_jingle_session_parse(JabberStream *js, xmlnode *packet);
+#define JINGLE "urn:xmpp:jingle:0"
+#define JINGLE_ERROR "urn:xmpp:jingle:errors:0"
+#define JINGLE_APP_FT "urn:xmpp:jingle:apps:file-transfer:0"
+#define JINGLE_APP_RTP "urn:xmpp:jingle:apps:rtp:0"
+#define JINGLE_APP_RTP_ERROR "urn:xmpp:jingle:apps:rtp:errors:0"
+#define JINGLE_APP_RTP_INFO "urn:xmpp:jingle:apps:rtp:info:0"
+#define JINGLE_APP_RTP_SUPPORT_AUDIO "urn:xmpp:jingle:apps:rtp:audio"
+#define JINGLE_APP_RTP_SUPPORT_VIDEO "urn:xmpp:jingle:apps:rtp:video"
+#define JINGLE_APP_XML "urn:xmpp:tmp:jingle:apps:xmlstream"
+#define JINGLE_DTMF "urn:xmpp:jingle:dtmf:0"
+#define JINGLE_TRANSPORT_SOCKS "urn:xmpp:jingle:transports:bytestreams:0"
+#define JINGLE_TRANSPORT_IBB "urn:xmpp:jingle:transports:ibb:0"
+#define JINGLE_TRANSPORT_ICEUDP "urn:xmpp:jingle:transports:ice-udp:0"
+#define JINGLE_TRANSPORT_RAWUDP "urn:xmpp:jingle:transports:raw-udp:0"
+#define JINGLE_TRANSPORT_RAWUDP_INFO "urn:xmpp:jingle:transports:raw-udp:info:0"
-PurpleMedia *jabber_jingle_session_initiate_media(JabberStream *js,
- const char *who,
- PurpleMediaSessionType type);
+typedef enum {
+ JINGLE_UNKNOWN_TYPE,
+ JINGLE_CONTENT_ACCEPT,
+ JINGLE_CONTENT_ADD,
+ JINGLE_CONTENT_MODIFY,
+ JINGLE_CONTENT_REJECT,
+ JINGLE_CONTENT_REMOVE,
+ JINGLE_SESSION_ACCEPT,
+ JINGLE_SESSION_INFO,
+ JINGLE_SESSION_INITIATE,
+ JINGLE_SESSION_TERMINATE,
+ JINGLE_TRANSPORT_ACCEPT,
+ JINGLE_TRANSPORT_INFO,
+ JINGLE_TRANSPORT_REJECT,
+ JINGLE_TRANSPORT_REPLACE,
+} JingleActionType;
-void jabber_jingle_session_terminate_session_media(JabberStream *js, const gchar *who);
-void jabber_jingle_session_terminate_sessions(JabberStream *js);
+const gchar *jingle_get_action_name(JingleActionType action);
+JingleActionType jingle_get_action_type(const gchar *action);
-G_END_DECLS
+GType jingle_get_type(const gchar *type);
-#endif /* USE_VV */
+void jingle_parse(JabberStream *js, xmlnode *packet);
+void jingle_terminate_sessions(JabberStream *js);
+
+#ifdef __cplusplus
+}
+#endif
+
+G_END_DECLS
+
#endif /* JINGLE_H */
============================================================
--- pidgin/gtkconv.c f5b79b930aa900917da4cdfe3aa0d0a969a4cb17
+++ pidgin/gtkconv.c 2221a967dd3ef977e7847dcb40f4034722388c8d
@@ -7770,6 +7770,8 @@ pidgin_conv_new_media_cb(PurpleMediaMana
}
gtkmedia = pidgin_media_new(media);
+ g_object_unref(media);
+
gtk_box_pack_start(GTK_BOX(gtkconv->topvbox), gtkmedia, FALSE, FALSE, 0);
gtk_widget_show(gtkmedia);
g_signal_connect(G_OBJECT(gtkmedia), "message", G_CALLBACK(pidgin_gtkmedia_message_cb), conv);
============================================================
--- pidgin/gtkmedia.c e6bdc85a826b2957d8bffc0e428f9e3f20b442a6
+++ pidgin/gtkmedia.c 4c8c2f03b4fcc94490112810c3abd9af613759ab
@@ -249,6 +249,7 @@ pidgin_media_finalize (GObject *media)
pidgin_media_finalize (GObject *media)
{
PidginMedia *gtkmedia = PIDGIN_MEDIA(media);
+ purple_debug_info("gtkmedia", "pidgin_media_finalize\n");
if (gtkmedia->priv->media) {
pidgin_media_disconnect_levels(gtkmedia->priv->media, gtkmedia);
g_object_unref(gtkmedia->priv->media);
More information about the Commits
mailing list