libpurple/protocols/jabber/jingle/content.c

Wed, 13 May 2009 20:29:03 +0000

author
Marcus Lundblad <malu@pidgin.im>
date
Wed, 13 May 2009 20:29:03 +0000
changeset 27110
05ca719b901b
parent 26823
1bb25f5e90ef
child 28322
ac8fec1d2234
permissions
-rw-r--r--

Support custom smileys in MUCs (when all participants support BoB and a maximum
of 10 participants are in the chat).
Always announce support for BoB, since disable custom smileys will still turn
off fetching them, and BoB can be used for other purposes further on.

/**
 * @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 "internal.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);
			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);
			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"));
	GType jingle_type = jingle_get_type(type);

	if (jingle_type != G_TYPE_NONE) {
		return JINGLE_CONTENT_CLASS(g_type_class_ref(jingle_type))->parse(content);
	} else {
		return NULL;
	}
}

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);
		g_object_unref(transport);
	}

	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 *xmlcontent, JingleActionType action)
{
	g_return_if_fail(JINGLE_IS_CONTENT(content));
	JINGLE_CONTENT_GET_CLASS(content)->handle_action(content, xmlcontent, action);
}

mercurial