loudmouth/src/lm-message-node.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
equal deleted inserted replaced
0:d0f3a028347a 10:59927b2d3b75
     1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
       
     2 /*
       
     3  * Copyright (C) 2003 Imendio AB
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Lesser General Public License as
       
     7  * published by the Free Software Foundation; either version 2 of the
       
     8  * License, or (at your option) any later version.
       
     9  *
       
    10  * This program is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  * Lesser General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU Lesser General Public
       
    16  * License along with this program; if not, write to the
       
    17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    18  * Boston, MA 02111-1307, USA.
       
    19  */
       
    20 
       
    21 #include <config.h>
       
    22 #include <string.h>
       
    23 
       
    24 #include "lm-internals.h"
       
    25 #include "lm-message-node.h"
       
    26 
       
    27 typedef struct {
       
    28         gchar *key;
       
    29         gchar *value;
       
    30 } KeyValuePair;
       
    31 
       
    32 static void            message_node_free            (LmMessageNode    *node);
       
    33 static LmMessageNode * message_node_last_child      (LmMessageNode    *node);
       
    34 
       
    35 static void
       
    36 message_node_free (LmMessageNode *node)
       
    37 {
       
    38         LmMessageNode *l;
       
    39         GSList        *list;
       
    40         
       
    41         g_return_if_fail (node != NULL);
       
    42 
       
    43 	for (l = node->children; l;) {
       
    44 		LmMessageNode *next = l->next;
       
    45 
       
    46 		lm_message_node_unref (l);
       
    47 		l = next;
       
    48         }
       
    49 
       
    50         g_free (node->name);
       
    51         g_free (node->value);
       
    52         
       
    53         for (list = node->attributes; list; list = list->next) {
       
    54                 KeyValuePair *kvp = (KeyValuePair *) list->data;
       
    55                 
       
    56                 g_free (kvp->key);
       
    57                 g_free (kvp->value);
       
    58                 g_free (kvp);
       
    59         }
       
    60         
       
    61         g_slist_free (node->attributes);
       
    62         g_free (node);
       
    63 }
       
    64 
       
    65 static LmMessageNode *
       
    66 message_node_last_child (LmMessageNode *node)
       
    67 {
       
    68         LmMessageNode *l;
       
    69         
       
    70         g_return_val_if_fail (node != NULL, NULL);
       
    71 
       
    72         if (!node->children) {
       
    73                 return NULL;
       
    74         }
       
    75                 
       
    76         l = node->children;
       
    77 
       
    78         while (l->next) {
       
    79                 l = l->next;
       
    80         }
       
    81 
       
    82         return l;
       
    83 }
       
    84 
       
    85 LmMessageNode *
       
    86 _lm_message_node_new (const gchar *name)
       
    87 {
       
    88         LmMessageNode *node;
       
    89 
       
    90         node = g_new0 (LmMessageNode, 1);
       
    91         
       
    92         node->name       = g_strdup (name);
       
    93         node->value      = NULL;
       
    94 	node->raw_mode   = FALSE;
       
    95         node->attributes = NULL;
       
    96         node->next       = NULL;
       
    97         node->prev       = NULL;
       
    98         node->parent     = NULL;
       
    99         node->children   = NULL;
       
   100 
       
   101 	node->ref_count  = 1;
       
   102 
       
   103         return node;
       
   104 }
       
   105 void
       
   106 _lm_message_node_add_child_node (LmMessageNode *node, LmMessageNode *child)
       
   107 {
       
   108         LmMessageNode *prev;
       
   109 	
       
   110         g_return_if_fail (node != NULL);
       
   111 
       
   112         prev = message_node_last_child (node);
       
   113 	lm_message_node_ref (child);
       
   114 
       
   115         if (prev) {
       
   116                 prev->next    = child;
       
   117                 child->prev   = prev;
       
   118         } else {
       
   119                 node->children = child;
       
   120         }
       
   121         
       
   122         child->parent = node;
       
   123 }
       
   124 
       
   125 /**
       
   126  * lm_message_node_get_value:
       
   127  * @node: an #LmMessageNode
       
   128  * 
       
   129  * Retrieves the value of @node.
       
   130  * 
       
   131  * Return value: 
       
   132  **/
       
   133 EXPORT_C const gchar *
       
   134 lm_message_node_get_value (LmMessageNode *node)
       
   135 {
       
   136 	g_return_val_if_fail (node != NULL, NULL);
       
   137 	
       
   138 	return node->value;
       
   139 }
       
   140 
       
   141 /**
       
   142  * lm_message_node_set_value:
       
   143  * @node: an #LmMessageNode
       
   144  * @value: the new value.
       
   145  * 
       
   146  * Sets the value of @node. If a previous value is set it will be freed.
       
   147  **/
       
   148 EXPORT_C void
       
   149 lm_message_node_set_value (LmMessageNode *node, const gchar *value)
       
   150 {
       
   151         g_return_if_fail (node != NULL);
       
   152        
       
   153         g_free (node->value);
       
   154 	
       
   155         if (!value) {
       
   156                 node->value = NULL;
       
   157                 return;
       
   158         }
       
   159 
       
   160         node->value = g_strdup (value);
       
   161 }
       
   162 
       
   163 /**
       
   164  * lm_message_node_add_child:
       
   165  * @node: an #LmMessageNode
       
   166  * @name: the name of the new child
       
   167  * @value: value of the new child
       
   168  * 
       
   169  * Add a child node with @name and value set to @value. 
       
   170  * 
       
   171  * Return value: the newly created child
       
   172  **/
       
   173 EXPORT_C LmMessageNode *
       
   174 lm_message_node_add_child (LmMessageNode *node, 
       
   175 			   const gchar   *name, 
       
   176 			   const gchar   *value)
       
   177 {
       
   178 	LmMessageNode *child;
       
   179 	
       
   180         g_return_val_if_fail (node != NULL, NULL);
       
   181         g_return_val_if_fail (name != NULL, NULL);
       
   182 
       
   183 	child = _lm_message_node_new (name);
       
   184 
       
   185 	lm_message_node_set_value (child, value);
       
   186 	_lm_message_node_add_child_node (node, child);
       
   187 	lm_message_node_unref (child);
       
   188 
       
   189 	return child;
       
   190 }
       
   191 
       
   192 /**
       
   193  * lm_message_node_set_attributes:
       
   194  * @node: an #LmMessageNode
       
   195  * @name: the first attribute, should be followed by a string with the value
       
   196  * @Varargs: The rest of the name/value pairs
       
   197  * 
       
   198  * Sets a list of attributes. The arguments should be names and corresponding 
       
   199  * value and needs to be ended with %NULL.
       
   200  **/
       
   201 EXPORT_C void
       
   202 lm_message_node_set_attributes  (LmMessageNode *node,
       
   203 				 const gchar   *name,
       
   204 				 ...)
       
   205 {
       
   206 	va_list args;
       
   207 	
       
   208         g_return_if_fail (node != NULL);
       
   209 
       
   210 	for (va_start (args, name); 
       
   211 	     name; 
       
   212 	     name = (const gchar *) va_arg (args, gpointer)) {
       
   213 		const gchar *value;
       
   214 
       
   215 		value = (const gchar *) va_arg (args, gpointer);
       
   216 
       
   217 		lm_message_node_set_attribute (node, name, value);
       
   218 		
       
   219 	}
       
   220 
       
   221 	va_end (args);
       
   222 }
       
   223 
       
   224 /**
       
   225  * lm_message_node_set_attribute:
       
   226  * @node: an #LmMessageNode
       
   227  * @name: name of attribute
       
   228  * @value: value of attribute.
       
   229  * 
       
   230  * Sets the attribute @name to @value.
       
   231  **/
       
   232 EXPORT_C void
       
   233 lm_message_node_set_attribute (LmMessageNode *node,
       
   234 			       const gchar   *name,
       
   235 			       const gchar   *value)
       
   236 {
       
   237 	gboolean  found = FALSE; 
       
   238 	GSList   *l;
       
   239 
       
   240         g_return_if_fail (node != NULL);
       
   241         g_return_if_fail (name != NULL);
       
   242         g_return_if_fail (value != NULL);
       
   243 
       
   244 	for (l = node->attributes; l; l = l->next) {
       
   245 		KeyValuePair *kvp = (KeyValuePair *) l->data;
       
   246                 
       
   247 		if (strcmp (kvp->key, name) == 0) {
       
   248 			g_free (kvp->value);
       
   249 			kvp->value = g_strdup (value);
       
   250 			found = TRUE;
       
   251 			break;
       
   252 		}
       
   253 	}
       
   254 	
       
   255 	if (!found) {
       
   256 		KeyValuePair *kvp;
       
   257 	
       
   258 		kvp = g_new0 (KeyValuePair, 1);                
       
   259 		kvp->key = g_strdup (name);
       
   260 		kvp->value = g_strdup (value);
       
   261 		
       
   262 		node->attributes = g_slist_prepend (node->attributes, kvp);
       
   263 	}
       
   264 }
       
   265 
       
   266 /**
       
   267  * lm_message_node_get_attribute:
       
   268  * @node: an #LmMessageNode
       
   269  * @name: the attribute name
       
   270  * 
       
   271  * Fetches the attribute @name from @node.
       
   272  * 
       
   273  * Return value: the attribute value or %NULL if not set
       
   274  **/
       
   275 EXPORT_C const gchar *
       
   276 lm_message_node_get_attribute (LmMessageNode *node, const gchar *name)
       
   277 {
       
   278         GSList      *l;
       
   279         const gchar *ret_val = NULL;
       
   280 
       
   281         //g_return_val_if_fail (node != NULL, NULL);
       
   282         //g_return_val_if_fail (name != NULL, NULL);
       
   283 
       
   284 		if(!node || !name)
       
   285 			return NULL;
       
   286 		
       
   287         for (l = node->attributes; l; l = l->next) {
       
   288                 KeyValuePair *kvp = (KeyValuePair *) l->data;
       
   289                 
       
   290                 if (strcmp (kvp->key, name) == 0) {
       
   291                         ret_val = kvp->value;
       
   292                 }
       
   293         }
       
   294         
       
   295         return ret_val;
       
   296 }
       
   297 
       
   298 /**
       
   299  * lm_message_node_get_child:
       
   300  * @node: an #LmMessageNode
       
   301  * @child_name: the childs name
       
   302  * 
       
   303  * Fetches the child @child_name from @node. If child is not found as an 
       
   304  * immediate child of @node %NULL is returned.
       
   305  * 
       
   306  * Return value: the child node or %NULL if not found
       
   307  **/
       
   308 EXPORT_C LmMessageNode *
       
   309 lm_message_node_get_child (LmMessageNode *node, const gchar *child_name)
       
   310 {
       
   311 	LmMessageNode *l;
       
   312 
       
   313     //    g_return_val_if_fail (node != NULL, NULL);
       
   314    //     g_return_val_if_fail (child_name != NULL, NULL);
       
   315 	
       
   316 	if(!node || !child_name)
       
   317 		return NULL;
       
   318 	for (l = node->children; l; l = l->next) {
       
   319 		if (strcmp (l->name, child_name) == 0) {
       
   320 			return l;
       
   321 		}
       
   322 	}
       
   323 
       
   324 	return NULL;
       
   325 }
       
   326 
       
   327 /**
       
   328  * lm_message_node_find_child:
       
   329  * @node: A #LmMessageNode
       
   330  * @child_name: The name of the child to find
       
   331  * 
       
   332  * Locates a child among all children of @node. The entire tree will be search 
       
   333  * until a child with name @child_name is located. 
       
   334  * 
       
   335  * Return value: the located child or %NULL if not found
       
   336  **/
       
   337 EXPORT_C LmMessageNode * 
       
   338 lm_message_node_find_child (LmMessageNode *node,
       
   339 			    const gchar   *child_name)
       
   340 {
       
   341         LmMessageNode *l;
       
   342         LmMessageNode *ret_val = NULL;
       
   343 
       
   344         //g_return_val_if_fail (node != NULL, NULL);
       
   345         //g_return_val_if_fail (child_name != NULL, NULL);
       
   346 		if(!node || !child_name)
       
   347 			return NULL;
       
   348         for (l = node->children; l; l = l->next) {
       
   349                 if (strcmp (l->name, child_name) == 0) {
       
   350                         return l;
       
   351                 }
       
   352                 if (l->children) {
       
   353                         ret_val = lm_message_node_find_child (l, child_name);
       
   354                         if (ret_val) {
       
   355                                 return ret_val;
       
   356                         }
       
   357                 }
       
   358         }
       
   359 
       
   360         return NULL;
       
   361 }
       
   362 
       
   363 /**
       
   364  * lm_message_node_get_raw_mode:
       
   365  * @node: an #LmMessageNode
       
   366  * 
       
   367  * Checks if the nodes value should be sent as raw mode. 
       
   368  *
       
   369  * Return value: %TRUE if nodes value should be sent as is and %FALSE if the value will be escaped before sending.
       
   370  **/
       
   371 EXPORT_C gboolean
       
   372 lm_message_node_get_raw_mode (LmMessageNode *node)
       
   373 {
       
   374 	//g_return_val_if_fail (node != NULL, FALSE);
       
   375 	
       
   376 	return node? node->raw_mode : 0 ;
       
   377 	//return node->raw_mode;
       
   378 }
       
   379 
       
   380 /** 
       
   381  * lm_message_node_set_raw_mode:
       
   382  * @node: an #LmMessageNode
       
   383  * @raw_mode: boolean specifying if node value should be escaped or not.
       
   384  *
       
   385  * 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.
       
   386  **/
       
   387 EXPORT_C void
       
   388 lm_message_node_set_raw_mode (LmMessageNode *node, gboolean raw_mode)
       
   389 {
       
   390 	//g_return_if_fail (node != NULL);
       
   391 	if(!node)
       
   392 		return;
       
   393 	
       
   394 	node->raw_mode = raw_mode;	
       
   395 }
       
   396 
       
   397 /**
       
   398  * lm_message_node_ref:
       
   399  * @node: an #LmMessageNode
       
   400  * 
       
   401  * Adds a reference to @node.
       
   402  * 
       
   403  * Return value: the node
       
   404  **/
       
   405 EXPORT_C LmMessageNode *
       
   406 lm_message_node_ref (LmMessageNode *node)
       
   407 {
       
   408 	//g_return_val_if_fail (node != NULL, NULL);
       
   409 	if(!node)
       
   410 		return NULL;
       
   411 	node->ref_count++;
       
   412        
       
   413 	return node;
       
   414 }
       
   415 
       
   416 /**
       
   417  * lm_message_node_unref:
       
   418  * @node: an #LmMessageNode
       
   419  * 
       
   420  * Removes a reference from @node. When no more references are present the
       
   421  * node is freed. When freed lm_message_node_unref() will be called on all
       
   422  * children. If caller needs to keep references to the children a call to 
       
   423  * lm_message_node_ref() needs to be done before the call to 
       
   424  *lm_message_unref().
       
   425  **/
       
   426 EXPORT_C void
       
   427 lm_message_node_unref (LmMessageNode *node)
       
   428 {
       
   429 	//g_return_if_fail (node != NULL);
       
   430 	if(!node)
       
   431 		return;
       
   432 	node->ref_count--;
       
   433 	
       
   434 	if (node->ref_count == 0) {
       
   435 		message_node_free (node);
       
   436 	}
       
   437 }
       
   438 
       
   439 /**
       
   440  * lm_message_node_to_string:
       
   441  * @node: an #LmMessageNode
       
   442  * 
       
   443  * Returns an XML string representing the node. This is what is sent over the
       
   444  * wire. This is used internally Loudmouth and is external for debugging 
       
   445  * purposes.
       
   446  * 
       
   447  * Return value: an XML string representation of @node
       
   448  **/
       
   449 EXPORT_C gchar *
       
   450 lm_message_node_to_string (LmMessageNode *node)
       
   451 {
       
   452 	GString       *ret;
       
   453 	GSList        *l;
       
   454 	LmMessageNode *child;
       
   455 
       
   456 	g_return_val_if_fail (node != NULL, NULL);
       
   457 	
       
   458 	if (node->name == NULL) {
       
   459 		return g_strdup ("");
       
   460 	}
       
   461 	
       
   462 	ret = g_string_new ("<");
       
   463 	g_string_append (ret, node->name);
       
   464 	
       
   465 	for (l = node->attributes; l; l = l->next) {
       
   466 		KeyValuePair *kvp = (KeyValuePair *) l->data;
       
   467 
       
   468 		if (node->raw_mode == FALSE) {
       
   469 			gchar *escaped;
       
   470 
       
   471 			escaped = g_markup_escape_text (kvp->value, -1);
       
   472 			g_string_append_printf (ret, " %s=\"%s\"", 
       
   473 						kvp->key, escaped);
       
   474 			g_free (escaped);
       
   475 		} else {
       
   476 			g_string_append_printf (ret, " %s=\"%s\"", 
       
   477 						kvp->key, kvp->value);
       
   478 		}
       
   479 		
       
   480 	}
       
   481 	
       
   482 	g_string_append_c (ret, '>');
       
   483 	
       
   484 	if (node->value) {
       
   485 		gchar *tmp;
       
   486 
       
   487 		if (node->raw_mode == FALSE) {
       
   488 			tmp = g_markup_escape_text (node->value, -1);
       
   489 			g_string_append (ret,  tmp);
       
   490 			g_free (tmp);
       
   491 		} else {
       
   492 			g_string_append (ret, node->value);
       
   493 		}
       
   494 	} 
       
   495 
       
   496 	for (child = node->children; child; child = child->next) {
       
   497 		gchar *child_str = lm_message_node_to_string (child);
       
   498 		g_string_append_c (ret, ' ');
       
   499 		g_string_append (ret, child_str);
       
   500 		g_free (child_str);
       
   501 	}
       
   502 
       
   503 	g_string_append_printf (ret, "</%s>\n", node->name);
       
   504 	
       
   505 	return g_string_free (ret, FALSE);
       
   506 }