Mercurial > pidgin.yaz
diff libpurple/protocols/jabber/jingle/content.c @ 26014:bd598b606ca4
Restructure Jingle code to more easily support multiple application types.
Actually negotiate a rawudp transport rather than pretending to use iceudp.
author | Mike Ruprecht <maiku@soc.pidgin.im> |
---|---|
date | Sun, 19 Oct 2008 04:37:23 +0000 |
parents | |
children | 1a2d446cb8a0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/jingle/content.c Sun Oct 19 04:37:23 2008 +0000 @@ -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); +} +