1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-xmlrpc-response.c: XMLRPC response message
5 * Copyright (C) 2003, Novell, Inc.
6 * Copyright (C) 2004, Mariano Suarez-Alvarez <mariano@gnome.org>
7 * Copyright (C) 2004, Fernando Herrera <fherrera@onirica.com>
8 * Copyright (C) 2005, Jeff Bailey <jbailey@ubuntu.com>
21 #include <libxml/tree.h>
23 #include "soup-date.h"
24 #include "soup-misc.h"
25 #include "soup-xmlrpc-response.h"
28 G_DEFINE_TYPE (SoupXmlrpcResponse, soup_xmlrpc_response, G_TYPE_OBJECT)
34 } SoupXmlrpcResponsePrivate;
35 #define SOUP_XMLRPC_RESPONSE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_XMLRPC_RESPONSE, SoupXmlrpcResponsePrivate))
38 finalize (GObject *object)
40 SoupXmlrpcResponsePrivate *priv = SOUP_XMLRPC_RESPONSE_GET_PRIVATE (object);
43 xmlFreeDoc (priv->doc);
45 G_OBJECT_CLASS (soup_xmlrpc_response_parent_class)->finalize (object);
49 soup_xmlrpc_response_class_init (SoupXmlrpcResponseClass *soup_xmlrpc_response_class)
51 GObjectClass *object_class = G_OBJECT_CLASS (soup_xmlrpc_response_class);
53 g_type_class_add_private (soup_xmlrpc_response_class, sizeof (SoupXmlrpcResponsePrivate));
55 object_class->finalize = finalize;
59 soup_xmlrpc_response_init (SoupXmlrpcResponse *response)
61 SoupXmlrpcResponsePrivate *priv = SOUP_XMLRPC_RESPONSE_GET_PRIVATE (response);
63 priv->doc = xmlNewDoc ((const xmlChar *)"1.0");
69 soup_xmlrpc_response_new (void)
71 SoupXmlrpcResponse *response;
73 response = g_object_new (SOUP_TYPE_XMLRPC_RESPONSE, NULL);
78 soup_xmlrpc_response_new_from_string (const char *xmlstr)
80 SoupXmlrpcResponse *response;
82 g_return_val_if_fail (xmlstr != NULL, NULL);
84 response = g_object_new (SOUP_TYPE_XMLRPC_RESPONSE, NULL);
86 if (!soup_xmlrpc_response_from_string (response, xmlstr)) {
87 g_object_unref (response);
95 exactly_one_child (xmlNode *node)
100 while (tmp && xmlIsBlankNode (tmp))
104 if (tmp && tmp->next) {
106 while (tmp && xmlIsBlankNode (tmp))
116 soup_xmlrpc_response_from_string (SoupXmlrpcResponse *response, const char *xmlstr)
118 SoupXmlrpcResponsePrivate *priv;
121 gboolean fault = TRUE;
123 g_return_val_if_fail (SOUP_IS_XMLRPC_RESPONSE (response), FALSE);
124 priv = SOUP_XMLRPC_RESPONSE_GET_PRIVATE (response);
125 g_return_val_if_fail (xmlstr != NULL, FALSE);
127 xmlKeepBlanksDefault (0);
128 newdoc = xmlParseMemory (xmlstr, strlen (xmlstr));
132 body = xmlDocGetRootElement (newdoc);
133 if (!body || strcmp ((const char *)body->name, "methodResponse"))
136 body = exactly_one_child (body);
140 if (strcmp ((const char *)body->name, "params") == 0) {
142 body = exactly_one_child (body);
143 if (!body || strcmp ((const char *)body->name, "param"))
145 } else if (strcmp ((const char *)body->name, "fault") != 0)
148 body = exactly_one_child (body);
149 if (!body || strcmp ((const char *)body->name, "value"))
152 /* body should be pointing by now to the struct of a fault, or the value of a
156 xmlFreeDoc (priv->doc);
170 soup_xmlrpc_response_to_string (SoupXmlrpcResponse *response)
172 SoupXmlrpcResponsePrivate *priv;
176 g_return_val_if_fail (SOUP_IS_XMLRPC_RESPONSE (response), FALSE);
177 priv = SOUP_XMLRPC_RESPONSE_GET_PRIVATE (response);
179 xmlDocDumpMemoryEnc (priv->doc, &str, &size, "UTF-8");
185 soup_xmlrpc_response_is_fault (SoupXmlrpcResponse *response)
187 SoupXmlrpcResponsePrivate *priv = SOUP_XMLRPC_RESPONSE_GET_PRIVATE (response);
193 soup_xmlrpc_response_get_value (SoupXmlrpcResponse *response)
195 SoupXmlrpcResponsePrivate *priv;
196 g_return_val_if_fail (SOUP_IS_XMLRPC_RESPONSE (response), FALSE);
197 priv = SOUP_XMLRPC_RESPONSE_GET_PRIVATE (response);
199 return (SoupXmlrpcValue*) priv->value;
203 soup_xmlrpc_value_get_type (SoupXmlrpcValue *value)
207 xml = (xmlNode *) value;
209 if (strcmp ((const char *)xml->name, "value"))
210 return SOUP_XMLRPC_VALUE_TYPE_BAD;
212 xml = exactly_one_child (xml);
214 return SOUP_XMLRPC_VALUE_TYPE_BAD;
216 if (strcmp ((const char *)xml->name, "i4") == 0 || strcmp ((const char *)xml->name, "int") == 0)
217 return SOUP_XMLRPC_VALUE_TYPE_INT;
218 else if (strcmp ((const char *)xml->name, "boolean") == 0)
219 return SOUP_XMLRPC_VALUE_TYPE_BOOLEAN;
220 else if (strcmp ((const char *)xml->name, "string") == 0)
221 return SOUP_XMLRPC_VALUE_TYPE_STRING;
222 else if (strcmp ((const char *)xml->name, "double") == 0)
223 return SOUP_XMLRPC_VALUE_TYPE_DOUBLE;
224 else if (strcmp ((const char *)xml->name, "dateTime.iso8601") == 0)
225 return SOUP_XMLRPC_VALUE_TYPE_DATETIME;
226 else if (strcmp ((const char *)xml->name, "base64") == 0)
227 return SOUP_XMLRPC_VALUE_TYPE_BASE64;
228 else if (strcmp ((const char *)xml->name, "struct") == 0)
229 return SOUP_XMLRPC_VALUE_TYPE_STRUCT;
230 else if (strcmp ((const char *)xml->name, "array") == 0)
231 return SOUP_XMLRPC_VALUE_TYPE_ARRAY;
233 return SOUP_XMLRPC_VALUE_TYPE_BAD;
237 soup_xmlrpc_value_get_int (SoupXmlrpcValue *value, long *i)
244 xml = (xmlNode *) value;
246 if (strcmp ((const char *)xml->name, "value"))
248 xml = exactly_one_child (xml);
249 if (!xml || (strcmp ((const char *)xml->name, "int") && strcmp ((const char *)xml->name, "i4")))
252 /* FIXME this should be exactly one text node */
253 content = xmlNodeGetContent (xml);
254 *i = strtol ((char *)content, &tail, 10);
255 ok = (*tail == '\0');
262 soup_xmlrpc_value_get_double (SoupXmlrpcValue *value, double *d)
269 xml = (xmlNode *) value;
271 if (strcmp ((const char *)xml->name, "value"))
273 xml = exactly_one_child (xml);
274 if (!xml || (strcmp ((const char *)xml->name, "double")))
277 /* FIXME this should be exactly one text node */
278 content = xmlNodeGetContent (xml);
279 *d = g_ascii_strtod ((char *)content, &tail);
280 ok = (*tail == '\0');
287 soup_xmlrpc_value_get_boolean (SoupXmlrpcValue *value, gboolean *b)
295 xml = (xmlNode *) value;
297 if (strcmp ((const char *)xml->name, "value"))
299 xml = exactly_one_child (xml);
300 if (!xml || strcmp ((const char *)xml->name, "boolean"))
303 content = xmlNodeGetContent (xml);
304 i = strtol ((char *)content, &tail, 10);
306 ok = (*tail == '\0');
313 soup_xmlrpc_value_get_string (SoupXmlrpcValue *value, char **str)
318 xml = (xmlNode *) value;
320 if (strcmp ((const char *)xml->name, "value"))
322 xml = exactly_one_child (xml);
323 if (!xml || strcmp ((const char *)xml->name, "string"))
326 content = xmlNodeGetContent (xml);
327 *str = content ? g_strdup ((char *)content) : g_strdup ("");
334 soup_xmlrpc_value_get_datetime (SoupXmlrpcValue *value, time_t *timeval)
339 xml = (xmlNode *) value;
341 if (strcmp ((const char *)xml->name, "value"))
343 xml = exactly_one_child (xml);
344 if (!xml || (strcmp ((const char *)xml->name, "dateTime.iso8601")))
347 /* FIXME this should be exactly one text node */
348 content = xmlNodeGetContent (xml);
349 if (xmlStrlen (content) != 17) {
354 *timeval = soup_date_iso8601_parse ((char *)content);
360 soup_xmlrpc_value_get_base64 (SoupXmlrpcValue *value, GByteArray **data)
367 xml = (xmlNode *) value;
368 if (strcmp ((const char *)xml->name, "value"))
370 xml = exactly_one_child (xml);
371 if (!xml || strcmp ((const char *)xml->name, "base64"))
374 content = xmlNodeGetContent (xml);
375 decoded = soup_base64_decode ((const char *)content, &len);
378 *data = g_byte_array_new ();
379 g_byte_array_append (*data, (guchar *)decoded, len);
387 soup_xmlrpc_value_get_struct (SoupXmlrpcValue *value, GHashTable **table)
392 xml = (xmlNode *) value;
394 if (strcmp ((const char *)xml->name, "value"))
396 xml = exactly_one_child (xml);
398 if (!xml || strcmp ((const char *)xml->name, "struct"))
401 t = g_hash_table_new_full (g_str_hash, g_str_equal, xmlFree, NULL);
403 for (xml = xml->children; xml; xml = xml->next) {
407 if (strcmp ((const char *)xml->name, "member") || !xml->children)
413 for (cur = xml->children; cur; cur = cur->next) {
414 if (strcmp((const char *)cur->name, "name") == 0) {
417 name = xmlNodeGetContent (cur);
419 else if (strcmp ((const char *)cur->name, "value") == 0)
425 if (name) xmlFree (name);
430 if (name) xmlFree (name);
433 g_hash_table_insert (t, name, val);
440 g_hash_table_destroy (t);
445 soup_xmlrpc_value_array_get_iterator (SoupXmlrpcValue *value, SoupXmlrpcValueArrayIterator **iter)
449 xml = (xmlNode *) value;
451 if (!xml->children || strcmp((const char *)xml->children->name, "array") != 0 ||
452 xml->children->next || !xml->children->children ||
453 strcmp((const char *)xml->children->children->name, "data") != 0 ||
454 xml->children->children->next)
457 *iter = (SoupXmlrpcValueArrayIterator *) xml->children->children->children;
462 SoupXmlrpcValueArrayIterator *
463 soup_xmlrpc_value_array_iterator_prev (SoupXmlrpcValueArrayIterator *iter)
467 xml = (xmlNode *) iter;
469 return (SoupXmlrpcValueArrayIterator *) xml->prev;
472 SoupXmlrpcValueArrayIterator *
473 soup_xmlrpc_value_array_iterator_next (SoupXmlrpcValueArrayIterator *iter)
477 xml = (xmlNode *) iter;
479 return (SoupXmlrpcValueArrayIterator *) xml->next;
483 soup_xmlrpc_value_array_iterator_get_value (SoupXmlrpcValueArrayIterator *iter,
484 SoupXmlrpcValue **value)
486 *value = (SoupXmlrpcValue *) iter;
499 soup_xmlrpc_value_dump_internal (SoupXmlrpcValue *value, int d);
502 soup_xmlrpc_value_dump_struct_member (const char *name, SoupXmlrpcValue *value, gpointer d)
504 indent (GPOINTER_TO_INT (d));
505 g_printerr ("MEMBER: %s\n", name);
506 soup_xmlrpc_value_dump_internal (value, GPOINTER_TO_INT (d));
510 soup_xmlrpc_value_dump_array_element (const int i, SoupXmlrpcValue *value, gpointer d)
512 indent (GPOINTER_TO_INT (d));
513 g_printerr ("ELEMENT: %d\n", i);
514 soup_xmlrpc_value_dump_internal (value, GPOINTER_TO_INT (d));
518 soup_xmlrpc_value_dump_internal (SoupXmlrpcValue *value, int d)
527 SoupXmlrpcValueArrayIterator *iter;
529 g_printerr ("\n\n[%s]\n", ((xmlNode*)value)->name);
530 switch (soup_xmlrpc_value_get_type (value)) {
532 case SOUP_XMLRPC_VALUE_TYPE_BAD:
534 g_printerr ("BAD\n");
537 case SOUP_XMLRPC_VALUE_TYPE_INT:
539 if (!soup_xmlrpc_value_get_int (value, &i))
540 g_printerr ("BAD INT\n");
542 g_printerr ("INT: %ld\n", i);
545 case SOUP_XMLRPC_VALUE_TYPE_BOOLEAN:
547 if (!soup_xmlrpc_value_get_boolean (value, &b))
548 g_printerr ("BAD BOOLEAN\n");
550 g_printerr ("BOOLEAN: %s\n", b ? "true" : "false");
553 case SOUP_XMLRPC_VALUE_TYPE_STRING:
555 if (!soup_xmlrpc_value_get_string (value, &str))
556 g_printerr ("BAD STRING\n");
558 g_printerr ("STRING: \"%s\"\n", str);
563 case SOUP_XMLRPC_VALUE_TYPE_DOUBLE:
565 if (!soup_xmlrpc_value_get_double (value, &f))
566 g_printerr ("BAD DOUBLE\n");
568 g_printerr ("DOUBLE: %f\n", f);
571 case SOUP_XMLRPC_VALUE_TYPE_DATETIME:
573 if (!soup_xmlrpc_value_get_datetime (value, &timeval))
574 g_printerr ("BAD DATETIME\n");
576 g_printerr ("DATETIME: %s\n", asctime (gmtime (&timeval)));
579 case SOUP_XMLRPC_VALUE_TYPE_BASE64:
581 if (!soup_xmlrpc_value_get_base64 (value, &base64))
582 g_printerr ("BAD BASE64\n");
584 GString *hex = g_string_new (NULL);
587 for (i = 0; i < base64->len; i++)
588 g_string_append_printf (hex, "%02x", base64->data[i]);
590 g_printerr ("BASE64: %s\n", hex->str);
591 g_string_free (hex, TRUE);
592 g_byte_array_free (base64, TRUE);
597 case SOUP_XMLRPC_VALUE_TYPE_STRUCT:
599 if (!soup_xmlrpc_value_get_struct (value, &hash))
600 g_printerr ("BAD STRUCT\n");
602 g_printerr ("STRUCT\n");
603 g_hash_table_foreach (hash, (GHFunc) soup_xmlrpc_value_dump_struct_member,
604 GINT_TO_POINTER (d+1));
605 g_hash_table_destroy (hash);
609 case SOUP_XMLRPC_VALUE_TYPE_ARRAY:
611 if (!soup_xmlrpc_value_array_get_iterator (value, &iter))
612 g_printerr ("BAD ARRAY\n");
614 SoupXmlrpcValue *evalue;
616 g_printerr ("ARRAY\n");
617 while (iter != NULL) {
618 soup_xmlrpc_value_array_iterator_get_value (iter, &evalue);
619 soup_xmlrpc_value_dump_array_element (i, evalue, GINT_TO_POINTER (d+1));
620 iter = soup_xmlrpc_value_array_iterator_next (iter);
630 soup_xmlrpc_value_dump (SoupXmlrpcValue *value)
632 soup_xmlrpc_value_dump_internal (value, 0);