--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/loudmouth/src/lm-message-node.c Tue Feb 02 01:10:06 2010 +0200
@@ -0,0 +1,506 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003 Imendio AB
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "lm-internals.h"
+#include "lm-message-node.h"
+
+typedef struct {
+ gchar *key;
+ gchar *value;
+} KeyValuePair;
+
+static void message_node_free (LmMessageNode *node);
+static LmMessageNode * message_node_last_child (LmMessageNode *node);
+
+static void
+message_node_free (LmMessageNode *node)
+{
+ LmMessageNode *l;
+ GSList *list;
+
+ g_return_if_fail (node != NULL);
+
+ for (l = node->children; l;) {
+ LmMessageNode *next = l->next;
+
+ lm_message_node_unref (l);
+ l = next;
+ }
+
+ g_free (node->name);
+ g_free (node->value);
+
+ for (list = node->attributes; list; list = list->next) {
+ KeyValuePair *kvp = (KeyValuePair *) list->data;
+
+ g_free (kvp->key);
+ g_free (kvp->value);
+ g_free (kvp);
+ }
+
+ g_slist_free (node->attributes);
+ g_free (node);
+}
+
+static LmMessageNode *
+message_node_last_child (LmMessageNode *node)
+{
+ LmMessageNode *l;
+
+ g_return_val_if_fail (node != NULL, NULL);
+
+ if (!node->children) {
+ return NULL;
+ }
+
+ l = node->children;
+
+ while (l->next) {
+ l = l->next;
+ }
+
+ return l;
+}
+
+LmMessageNode *
+_lm_message_node_new (const gchar *name)
+{
+ LmMessageNode *node;
+
+ node = g_new0 (LmMessageNode, 1);
+
+ node->name = g_strdup (name);
+ node->value = NULL;
+ node->raw_mode = FALSE;
+ node->attributes = NULL;
+ node->next = NULL;
+ node->prev = NULL;
+ node->parent = NULL;
+ node->children = NULL;
+
+ node->ref_count = 1;
+
+ return node;
+}
+void
+_lm_message_node_add_child_node (LmMessageNode *node, LmMessageNode *child)
+{
+ LmMessageNode *prev;
+
+ g_return_if_fail (node != NULL);
+
+ prev = message_node_last_child (node);
+ lm_message_node_ref (child);
+
+ if (prev) {
+ prev->next = child;
+ child->prev = prev;
+ } else {
+ node->children = child;
+ }
+
+ child->parent = node;
+}
+
+/**
+ * lm_message_node_get_value:
+ * @node: an #LmMessageNode
+ *
+ * Retrieves the value of @node.
+ *
+ * Return value:
+ **/
+EXPORT_C const gchar *
+lm_message_node_get_value (LmMessageNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ return node->value;
+}
+
+/**
+ * lm_message_node_set_value:
+ * @node: an #LmMessageNode
+ * @value: the new value.
+ *
+ * Sets the value of @node. If a previous value is set it will be freed.
+ **/
+EXPORT_C void
+lm_message_node_set_value (LmMessageNode *node, const gchar *value)
+{
+ g_return_if_fail (node != NULL);
+
+ g_free (node->value);
+
+ if (!value) {
+ node->value = NULL;
+ return;
+ }
+
+ node->value = g_strdup (value);
+}
+
+/**
+ * lm_message_node_add_child:
+ * @node: an #LmMessageNode
+ * @name: the name of the new child
+ * @value: value of the new child
+ *
+ * Add a child node with @name and value set to @value.
+ *
+ * Return value: the newly created child
+ **/
+EXPORT_C LmMessageNode *
+lm_message_node_add_child (LmMessageNode *node,
+ const gchar *name,
+ const gchar *value)
+{
+ LmMessageNode *child;
+
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ child = _lm_message_node_new (name);
+
+ lm_message_node_set_value (child, value);
+ _lm_message_node_add_child_node (node, child);
+ lm_message_node_unref (child);
+
+ return child;
+}
+
+/**
+ * lm_message_node_set_attributes:
+ * @node: an #LmMessageNode
+ * @name: the first attribute, should be followed by a string with the value
+ * @Varargs: The rest of the name/value pairs
+ *
+ * Sets a list of attributes. The arguments should be names and corresponding
+ * value and needs to be ended with %NULL.
+ **/
+EXPORT_C void
+lm_message_node_set_attributes (LmMessageNode *node,
+ const gchar *name,
+ ...)
+{
+ va_list args;
+
+ g_return_if_fail (node != NULL);
+
+ for (va_start (args, name);
+ name;
+ name = (const gchar *) va_arg (args, gpointer)) {
+ const gchar *value;
+
+ value = (const gchar *) va_arg (args, gpointer);
+
+ lm_message_node_set_attribute (node, name, value);
+
+ }
+
+ va_end (args);
+}
+
+/**
+ * lm_message_node_set_attribute:
+ * @node: an #LmMessageNode
+ * @name: name of attribute
+ * @value: value of attribute.
+ *
+ * Sets the attribute @name to @value.
+ **/
+EXPORT_C void
+lm_message_node_set_attribute (LmMessageNode *node,
+ const gchar *name,
+ const gchar *value)
+{
+ gboolean found = FALSE;
+ GSList *l;
+
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (value != NULL);
+
+ for (l = node->attributes; l; l = l->next) {
+ KeyValuePair *kvp = (KeyValuePair *) l->data;
+
+ if (strcmp (kvp->key, name) == 0) {
+ g_free (kvp->value);
+ kvp->value = g_strdup (value);
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ KeyValuePair *kvp;
+
+ kvp = g_new0 (KeyValuePair, 1);
+ kvp->key = g_strdup (name);
+ kvp->value = g_strdup (value);
+
+ node->attributes = g_slist_prepend (node->attributes, kvp);
+ }
+}
+
+/**
+ * lm_message_node_get_attribute:
+ * @node: an #LmMessageNode
+ * @name: the attribute name
+ *
+ * Fetches the attribute @name from @node.
+ *
+ * Return value: the attribute value or %NULL if not set
+ **/
+EXPORT_C const gchar *
+lm_message_node_get_attribute (LmMessageNode *node, const gchar *name)
+{
+ GSList *l;
+ const gchar *ret_val = NULL;
+
+ //g_return_val_if_fail (node != NULL, NULL);
+ //g_return_val_if_fail (name != NULL, NULL);
+
+ if(!node || !name)
+ return NULL;
+
+ for (l = node->attributes; l; l = l->next) {
+ KeyValuePair *kvp = (KeyValuePair *) l->data;
+
+ if (strcmp (kvp->key, name) == 0) {
+ ret_val = kvp->value;
+ }
+ }
+
+ return ret_val;
+}
+
+/**
+ * lm_message_node_get_child:
+ * @node: an #LmMessageNode
+ * @child_name: the childs name
+ *
+ * Fetches the child @child_name from @node. If child is not found as an
+ * immediate child of @node %NULL is returned.
+ *
+ * Return value: the child node or %NULL if not found
+ **/
+EXPORT_C LmMessageNode *
+lm_message_node_get_child (LmMessageNode *node, const gchar *child_name)
+{
+ LmMessageNode *l;
+
+ // g_return_val_if_fail (node != NULL, NULL);
+ // g_return_val_if_fail (child_name != NULL, NULL);
+
+ if(!node || !child_name)
+ return NULL;
+ for (l = node->children; l; l = l->next) {
+ if (strcmp (l->name, child_name) == 0) {
+ return l;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * lm_message_node_find_child:
+ * @node: A #LmMessageNode
+ * @child_name: The name of the child to find
+ *
+ * Locates a child among all children of @node. The entire tree will be search
+ * until a child with name @child_name is located.
+ *
+ * Return value: the located child or %NULL if not found
+ **/
+EXPORT_C LmMessageNode *
+lm_message_node_find_child (LmMessageNode *node,
+ const gchar *child_name)
+{
+ LmMessageNode *l;
+ LmMessageNode *ret_val = NULL;
+
+ //g_return_val_if_fail (node != NULL, NULL);
+ //g_return_val_if_fail (child_name != NULL, NULL);
+ if(!node || !child_name)
+ return NULL;
+ for (l = node->children; l; l = l->next) {
+ if (strcmp (l->name, child_name) == 0) {
+ return l;
+ }
+ if (l->children) {
+ ret_val = lm_message_node_find_child (l, child_name);
+ if (ret_val) {
+ return ret_val;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * lm_message_node_get_raw_mode:
+ * @node: an #LmMessageNode
+ *
+ * Checks if the nodes value should be sent as raw mode.
+ *
+ * Return value: %TRUE if nodes value should be sent as is and %FALSE if the value will be escaped before sending.
+ **/
+EXPORT_C gboolean
+lm_message_node_get_raw_mode (LmMessageNode *node)
+{
+ //g_return_val_if_fail (node != NULL, FALSE);
+
+ return node? node->raw_mode : 0 ;
+ //return node->raw_mode;
+}
+
+/**
+ * lm_message_node_set_raw_mode:
+ * @node: an #LmMessageNode
+ * @raw_mode: boolean specifying if node value should be escaped or not.
+ *
+ * Set @raw_mode to %TRUE if you don't want to escape the value. You need to make sure the value is valid XML yourself.
+ **/
+EXPORT_C void
+lm_message_node_set_raw_mode (LmMessageNode *node, gboolean raw_mode)
+{
+ //g_return_if_fail (node != NULL);
+ if(!node)
+ return;
+
+ node->raw_mode = raw_mode;
+}
+
+/**
+ * lm_message_node_ref:
+ * @node: an #LmMessageNode
+ *
+ * Adds a reference to @node.
+ *
+ * Return value: the node
+ **/
+EXPORT_C LmMessageNode *
+lm_message_node_ref (LmMessageNode *node)
+{
+ //g_return_val_if_fail (node != NULL, NULL);
+ if(!node)
+ return NULL;
+ node->ref_count++;
+
+ return node;
+}
+
+/**
+ * lm_message_node_unref:
+ * @node: an #LmMessageNode
+ *
+ * Removes a reference from @node. When no more references are present the
+ * node is freed. When freed lm_message_node_unref() will be called on all
+ * children. If caller needs to keep references to the children a call to
+ * lm_message_node_ref() needs to be done before the call to
+ *lm_message_unref().
+ **/
+EXPORT_C void
+lm_message_node_unref (LmMessageNode *node)
+{
+ //g_return_if_fail (node != NULL);
+ if(!node)
+ return;
+ node->ref_count--;
+
+ if (node->ref_count == 0) {
+ message_node_free (node);
+ }
+}
+
+/**
+ * lm_message_node_to_string:
+ * @node: an #LmMessageNode
+ *
+ * Returns an XML string representing the node. This is what is sent over the
+ * wire. This is used internally Loudmouth and is external for debugging
+ * purposes.
+ *
+ * Return value: an XML string representation of @node
+ **/
+EXPORT_C gchar *
+lm_message_node_to_string (LmMessageNode *node)
+{
+ GString *ret;
+ GSList *l;
+ LmMessageNode *child;
+
+ g_return_val_if_fail (node != NULL, NULL);
+
+ if (node->name == NULL) {
+ return g_strdup ("");
+ }
+
+ ret = g_string_new ("<");
+ g_string_append (ret, node->name);
+
+ for (l = node->attributes; l; l = l->next) {
+ KeyValuePair *kvp = (KeyValuePair *) l->data;
+
+ if (node->raw_mode == FALSE) {
+ gchar *escaped;
+
+ escaped = g_markup_escape_text (kvp->value, -1);
+ g_string_append_printf (ret, " %s=\"%s\"",
+ kvp->key, escaped);
+ g_free (escaped);
+ } else {
+ g_string_append_printf (ret, " %s=\"%s\"",
+ kvp->key, kvp->value);
+ }
+
+ }
+
+ g_string_append_c (ret, '>');
+
+ if (node->value) {
+ gchar *tmp;
+
+ if (node->raw_mode == FALSE) {
+ tmp = g_markup_escape_text (node->value, -1);
+ g_string_append (ret, tmp);
+ g_free (tmp);
+ } else {
+ g_string_append (ret, node->value);
+ }
+ }
+
+ for (child = node->children; child; child = child->next) {
+ gchar *child_str = lm_message_node_to_string (child);
+ g_string_append_c (ret, ' ');
+ g_string_append (ret, child_str);
+ g_free (child_str);
+ }
+
+ g_string_append_printf (ret, "</%s>\n", node->name);
+
+ return g_string_free (ret, FALSE);
+}