Wed, 13 May 2009 20:29:03 +0000
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); }