1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * soup-xmlrpc.c: XML-RPC parser/generator
4 *
5 * Copyright (C) 2007 Red Hat, Inc.
6 */
7
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <string.h>
13
14 #include <libxml/tree.h>
15
16 #include "soup-xmlrpc-old.h"
17 #include "soup.h"
18
19 /**
20 * SECTION:soup-xmlrpc
21 * @short_description: XML-RPC support
22 *
23 **/
24
25 /* This whole file is deprecated and replaced by soup-xmlrpc.c */
26 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
27
28 static xmlNode *find_real_node (xmlNode *node);
29
30 static gboolean insert_value (xmlNode *parent, GValue *value);
31
32 static gboolean
insert_value(xmlNode * parent,GValue * value)33 insert_value (xmlNode *parent, GValue *value)
34 {
35 GType type = G_VALUE_TYPE (value);
36 xmlNode *xvalue;
37 char buf[128];
38
39 xvalue = xmlNewChild (parent, NULL, (const xmlChar *)"value", NULL);
40
41 if (type == G_TYPE_INT) {
42 g_snprintf (buf, sizeof (buf), "%d", g_value_get_int (value));
43 xmlNewChild (xvalue, NULL,
44 (const xmlChar *)"int",
45 (const xmlChar *)buf);
46 } else if (type == G_TYPE_BOOLEAN) {
47 g_snprintf (buf, sizeof (buf), "%d", g_value_get_boolean (value));
48 xmlNewChild (xvalue, NULL,
49 (const xmlChar *)"boolean",
50 (const xmlChar *)buf);
51 } else if (type == G_TYPE_STRING) {
52 xmlNewTextChild (xvalue, NULL,
53 (const xmlChar *)"string",
54 (const xmlChar *)g_value_get_string (value));
55 } else if (type == G_TYPE_DOUBLE) {
56 g_ascii_dtostr (buf, sizeof (buf), g_value_get_double (value));
57 xmlNewChild (xvalue, NULL,
58 (const xmlChar *)"double",
59 (const xmlChar *)buf);
60 } else if (type == SOUP_TYPE_DATE) {
61 SoupDate *date = g_value_get_boxed (value);
62 char *timestamp = soup_date_to_string (date, SOUP_DATE_ISO8601_XMLRPC);
63 xmlNewChild (xvalue, NULL,
64 (const xmlChar *)"dateTime.iso8601",
65 (const xmlChar *)timestamp);
66 g_free (timestamp);
67 } else if (type == SOUP_TYPE_BYTE_ARRAY) {
68 GByteArray *ba = g_value_get_boxed (value);
69 char *encoded;
70
71 encoded = g_base64_encode (ba->data, ba->len);
72 xmlNewChild (xvalue, NULL,
73 (const xmlChar *)"base64",
74 (const xmlChar *)encoded);
75 g_free (encoded);
76 } else if (type == G_TYPE_HASH_TABLE) {
77 GHashTable *hash = g_value_get_boxed (value);
78 GHashTableIter iter;
79 gpointer mname, mvalue;
80 xmlNode *struct_node, *member;
81
82 struct_node = xmlNewChild (xvalue, NULL,
83 (const xmlChar *)"struct", NULL);
84
85 g_hash_table_iter_init (&iter, hash);
86
87 while (g_hash_table_iter_next (&iter, &mname, &mvalue)) {
88 member = xmlNewChild (struct_node, NULL,
89 (const xmlChar *)"member", NULL);
90 xmlNewTextChild (member, NULL,
91 (const xmlChar *)"name",
92 (const xmlChar *)mname);
93 if (!insert_value (member, mvalue)) {
94 xmlFreeNode (struct_node);
95 struct_node = NULL;
96 break;
97 }
98 }
99
100 if (!struct_node)
101 return FALSE;
102 } else if (type == G_TYPE_VALUE_ARRAY) {
103 GValueArray *va = g_value_get_boxed (value);
104 xmlNode *node;
105 guint i;
106
107 node = xmlNewChild (xvalue, NULL,
108 (const xmlChar *)"array", NULL);
109 node = xmlNewChild (node, NULL,
110 (const xmlChar *)"data", NULL);
111 for (i = 0; i < va->n_values; i++) {
112 if (!insert_value (node, &va->values[i]))
113 return FALSE;
114 }
115 } else
116 return FALSE;
117
118 return TRUE;
119 }
120
121 /**
122 * soup_xmlrpc_build_method_call:
123 * @method_name: the name of the XML-RPC method
124 * @params: (array length=n_params): arguments to @method
125 * @n_params: length of @params
126 *
127 * This creates an XML-RPC methodCall and returns it as a string.
128 * This is the low-level method that soup_xmlrpc_request_new() is
129 * built on.
130 *
131 * @params is an array of #GValue representing the parameters to
132 * @method. (It is *not* a #GValueArray, although if you have a
133 * #GValueArray, you can just pass its <literal>values</literal>f and
134 * <literal>n_values</literal> fields.)
135 *
136 * The correspondence between glib types and XML-RPC types is:
137 *
138 * int: #int (%G_TYPE_INT)
139 * boolean: #gboolean (%G_TYPE_BOOLEAN)
140 * string: #char* (%G_TYPE_STRING)
141 * double: #double (%G_TYPE_DOUBLE)
142 * datetime.iso8601: #SoupDate (%SOUP_TYPE_DATE)
143 * base64: #GByteArray (%SOUP_TYPE_BYTE_ARRAY)
144 * struct: #GHashTable (%G_TYPE_HASH_TABLE)
145 * array: #GValueArray (%G_TYPE_VALUE_ARRAY)
146 *
147 * For structs, use a #GHashTable that maps strings to #GValue;
148 * soup_value_hash_new() and related methods can help with this.
149 *
150 * Return value: (nullable): the text of the methodCall, or %NULL on
151 * error
152 *
153 * Deprecated: Use soup_xmlrpc_build_request() instead.
154 **/
155 char *
soup_xmlrpc_build_method_call(const char * method_name,GValue * params,int n_params)156 soup_xmlrpc_build_method_call (const char *method_name,
157 GValue *params, int n_params)
158 {
159 xmlDoc *doc;
160 xmlNode *node, *param;
161 xmlChar *xmlbody;
162 int i, len;
163 char *body;
164
165 doc = xmlNewDoc ((const xmlChar *)"1.0");
166 doc->standalone = FALSE;
167 doc->encoding = xmlCharStrdup ("UTF-8");
168
169 node = xmlNewDocNode (doc, NULL, (const xmlChar *)"methodCall", NULL);
170 xmlDocSetRootElement (doc, node);
171 xmlNewChild (node, NULL, (const xmlChar *)"methodName",
172 (const xmlChar *)method_name);
173
174 node = xmlNewChild (node, NULL, (const xmlChar *)"params", NULL);
175 for (i = 0; i < n_params; i++) {
176 param = xmlNewChild (node, NULL,
177 (const xmlChar *)"param", NULL);
178 if (!insert_value (param, ¶ms[i])) {
179 xmlFreeDoc (doc);
180 return NULL;
181 }
182 }
183
184 xmlDocDumpMemory (doc, &xmlbody, &len);
185 body = g_strndup ((char *)xmlbody, len);
186 xmlFree (xmlbody);
187 xmlFreeDoc (doc);
188 return body;
189 }
190
191 static SoupMessage *
soup_xmlrpc_request_newv(const char * uri,const char * method_name,va_list args)192 soup_xmlrpc_request_newv (const char *uri, const char *method_name, va_list args)
193 {
194 SoupMessage *msg;
195 GValueArray *params;
196 char *body;
197
198 params = soup_value_array_from_args (args);
199 if (!params)
200 return NULL;
201
202 body = soup_xmlrpc_build_method_call (method_name, params->values,
203 params->n_values);
204 g_value_array_free (params);
205
206 if (!body)
207 return NULL;
208
209 msg = soup_message_new ("POST", uri);
210 soup_message_set_request (msg, "text/xml", SOUP_MEMORY_TAKE,
211 body, strlen (body));
212 return msg;
213 }
214
215 /**
216 * soup_xmlrpc_request_new:
217 * @uri: URI of the XML-RPC service
218 * @method_name: the name of the XML-RPC method to invoke at @uri
219 * @...: parameters for @method
220 *
221 * Creates an XML-RPC methodCall and returns a #SoupMessage, ready
222 * to send, for that method call.
223 *
224 * The parameters are passed as type/value pairs; ie, first a #GType,
225 * and then a value of the appropriate type, finally terminated by
226 * %G_TYPE_INVALID.
227 *
228 * Return value: (transfer full): a #SoupMessage encoding the
229 * indicated XML-RPC request.
230 *
231 * Deprecated: Use soup_xmlrpc_message_new() instead.
232 **/
233 SoupMessage *
soup_xmlrpc_request_new(const char * uri,const char * method_name,...)234 soup_xmlrpc_request_new (const char *uri, const char *method_name, ...)
235 {
236 SoupMessage *msg;
237 va_list args;
238
239 va_start (args, method_name);
240 msg = soup_xmlrpc_request_newv (uri, method_name, args);
241 va_end (args);
242 return msg;
243 }
244
245 /**
246 * soup_xmlrpc_build_method_response:
247 * @value: the return value
248 *
249 * This creates a (successful) XML-RPC methodResponse and returns it
250 * as a string. To create a fault response, use
251 * soup_xmlrpc_build_fault().
252 *
253 * The glib type to XML-RPC type mapping is as with
254 * soup_xmlrpc_build_method_call(), qv.
255 *
256 * Return value: (nullable): the text of the methodResponse, or %NULL
257 * on error
258 *
259 * Deprecated: Use soup_xmlrpc_build_response() instead.
260 **/
261 char *
soup_xmlrpc_build_method_response(GValue * value)262 soup_xmlrpc_build_method_response (GValue *value)
263 {
264 xmlDoc *doc;
265 xmlNode *node;
266 xmlChar *xmlbody;
267 char *body;
268 int len;
269
270 doc = xmlNewDoc ((const xmlChar *)"1.0");
271 doc->standalone = FALSE;
272 doc->encoding = xmlCharStrdup ("UTF-8");
273
274 node = xmlNewDocNode (doc, NULL,
275 (const xmlChar *)"methodResponse", NULL);
276 xmlDocSetRootElement (doc, node);
277
278 node = xmlNewChild (node, NULL, (const xmlChar *)"params", NULL);
279 node = xmlNewChild (node, NULL, (const xmlChar *)"param", NULL);
280 if (!insert_value (node, value)) {
281 xmlFreeDoc (doc);
282 return NULL;
283 }
284
285 xmlDocDumpMemory (doc, &xmlbody, &len);
286 body = g_strndup ((char *)xmlbody, len);
287 xmlFree (xmlbody);
288 xmlFreeDoc (doc);
289 return body;
290 }
291
292 /**
293 * soup_xmlrpc_set_response:
294 * @msg: an XML-RPC request
295 * @type: the type of the response value
296 * @...: the response value
297 *
298 * Sets the status code and response body of @msg to indicate a
299 * successful XML-RPC call, with a return value given by @type and the
300 * following varargs argument, of the type indicated by @type.
301 *
302 * Deprecated: Use soup_xmlrpc_message_set_response() instead.
303 **/
304 void
soup_xmlrpc_set_response(SoupMessage * msg,GType type,...)305 soup_xmlrpc_set_response (SoupMessage *msg, GType type, ...)
306 {
307 va_list args;
308 GValue value;
309 char *body;
310
311 va_start (args, type);
312 SOUP_VALUE_SETV (&value, type, args);
313 va_end (args);
314
315 body = soup_xmlrpc_build_method_response (&value);
316 g_value_unset (&value);
317 soup_message_set_status (msg, SOUP_STATUS_OK);
318 soup_message_set_response (msg, "text/xml", SOUP_MEMORY_TAKE,
319 body, strlen (body));
320 }
321
322 char *soup_xmlrpc_build_faultv (int fault_code,
323 const char *fault_format,
324 va_list args) G_GNUC_PRINTF (2, 0);
325
326 /**
327 * soup_xmlrpc_set_fault:
328 * @msg: an XML-RPC request
329 * @fault_code: the fault code
330 * @fault_format: a printf()-style format string
331 * @...: the parameters to @fault_format
332 *
333 * Sets the status code and response body of @msg to indicate an
334 * unsuccessful XML-RPC call, with the error described by @fault_code
335 * and @fault_format.
336 *
337 * Deprecated: Use soup_xmlrpc_message_set_fault() instead.
338 **/
339 void
soup_xmlrpc_set_fault(SoupMessage * msg,int fault_code,const char * fault_format,...)340 soup_xmlrpc_set_fault (SoupMessage *msg, int fault_code,
341 const char *fault_format, ...)
342 {
343 va_list args;
344 char *body;
345
346 va_start (args, fault_format);
347 body = soup_xmlrpc_build_faultv (fault_code, fault_format, args);
348 va_end (args);
349
350 soup_message_set_status (msg, SOUP_STATUS_OK);
351 soup_message_set_response (msg, "text/xml", SOUP_MEMORY_TAKE,
352 body, strlen (body));
353 }
354
355
356
357 static gboolean
parse_value(xmlNode * xmlvalue,GValue * value)358 parse_value (xmlNode *xmlvalue, GValue *value)
359 {
360 xmlNode *typenode;
361 const char *typename;
362 xmlChar *content;
363
364 memset (value, 0, sizeof (GValue));
365
366 typenode = find_real_node (xmlvalue->children);
367 if (!typenode) {
368 /* If no type node, it's a string */
369 content = xmlNodeGetContent (typenode);
370 g_value_init (value, G_TYPE_STRING);
371 g_value_set_string (value, (char *)content);
372 xmlFree (content);
373 return TRUE;
374 }
375
376 typename = (const char *)typenode->name;
377
378 if (!strcmp (typename, "i4") || !strcmp (typename, "int")) {
379 content = xmlNodeGetContent (typenode);
380 g_value_init (value, G_TYPE_INT);
381 g_value_set_int (value, atoi ((char *)content));
382 xmlFree (content);
383 } else if (!strcmp (typename, "boolean")) {
384 content = xmlNodeGetContent (typenode);
385 g_value_init (value, G_TYPE_BOOLEAN);
386 g_value_set_boolean (value, atoi ((char *)content));
387 xmlFree (content);
388 } else if (!strcmp (typename, "string")) {
389 content = xmlNodeGetContent (typenode);
390 g_value_init (value, G_TYPE_STRING);
391 g_value_set_string (value, (char *)content);
392 xmlFree (content);
393 } else if (!strcmp (typename, "double")) {
394 content = xmlNodeGetContent (typenode);
395 g_value_init (value, G_TYPE_DOUBLE);
396 g_value_set_double (value, g_ascii_strtod ((char *)content, NULL));
397 xmlFree (content);
398 } else if (!strcmp (typename, "dateTime.iso8601")) {
399 content = xmlNodeGetContent (typenode);
400 g_value_init (value, SOUP_TYPE_DATE);
401 g_value_take_boxed (value, soup_date_new_from_string ((char *)content));
402 xmlFree (content);
403 } else if (!strcmp (typename, "base64")) {
404 GByteArray *ba;
405 guchar *decoded;
406 gsize len;
407
408 content = xmlNodeGetContent (typenode);
409 decoded = g_base64_decode ((char *)content, &len);
410 ba = g_byte_array_sized_new (len);
411 g_byte_array_append (ba, decoded, len);
412 g_free (decoded);
413 xmlFree (content);
414 g_value_init (value, SOUP_TYPE_BYTE_ARRAY);
415 g_value_take_boxed (value, ba);
416 } else if (!strcmp (typename, "struct")) {
417 xmlNode *member, *child, *mname, *mxval;
418 GHashTable *hash;
419 GValue mgval;
420
421 hash = soup_value_hash_new ();
422 for (member = find_real_node (typenode->children);
423 member;
424 member = find_real_node (member->next)) {
425 if (strcmp ((const char *)member->name, "member") != 0) {
426 g_hash_table_destroy (hash);
427 return FALSE;
428 }
429 mname = mxval = NULL;
430 memset (&mgval, 0, sizeof (mgval));
431
432 for (child = find_real_node (member->children);
433 child;
434 child = find_real_node (child->next)) {
435 if (!strcmp ((const char *)child->name, "name"))
436 mname = child;
437 else if (!strcmp ((const char *)child->name, "value"))
438 mxval = child;
439 else
440 break;
441 }
442
443 if (!mname || !mxval || !parse_value (mxval, &mgval)) {
444 g_hash_table_destroy (hash);
445 return FALSE;
446 }
447
448 content = xmlNodeGetContent (mname);
449 soup_value_hash_insert_value (hash, (char *)content, &mgval);
450 xmlFree (content);
451 g_value_unset (&mgval);
452 }
453 g_value_init (value, G_TYPE_HASH_TABLE);
454 g_value_take_boxed (value, hash);
455 } else if (!strcmp (typename, "array")) {
456 xmlNode *data, *xval;
457 GValueArray *array;
458 GValue gval;
459
460 data = find_real_node (typenode->children);
461 if (!data || strcmp ((const char *)data->name, "data") != 0)
462 return FALSE;
463
464 array = g_value_array_new (1);
465 for (xval = find_real_node (data->children);
466 xval;
467 xval = find_real_node (xval->next)) {
468 memset (&gval, 0, sizeof (gval));
469 if (strcmp ((const char *)xval->name, "value") != 0 ||
470 !parse_value (xval, &gval)) {
471 g_value_array_free (array);
472 return FALSE;
473 }
474
475 g_value_array_append (array, &gval);
476 g_value_unset (&gval);
477 }
478 g_value_init (value, G_TYPE_VALUE_ARRAY);
479 g_value_take_boxed (value, array);
480 } else
481 return FALSE;
482
483 return TRUE;
484 }
485
486 /**
487 * soup_xmlrpc_parse_method_call:
488 * @method_call: the XML-RPC methodCall string
489 * @length: the length of @method_call, or -1 if it is NUL-terminated
490 * @method_name: (out): on return, the methodName from @method_call
491 * @params: (out): on return, the parameters from @method_call
492 *
493 * Parses @method_call to get the name and parameters, and returns the
494 * parameter values in a #GValueArray; see also
495 * soup_xmlrpc_extract_method_call(), which is more convenient if you
496 * know in advance what the types of the parameters will be.
497 *
498 * Return value: success or failure.
499 *
500 * Deprecated: Use soup_xmlrpc_parse_request_full() instead.
501 **/
502 gboolean
soup_xmlrpc_parse_method_call(const char * method_call,int length,char ** method_name,GValueArray ** params)503 soup_xmlrpc_parse_method_call (const char *method_call, int length,
504 char **method_name, GValueArray **params)
505 {
506 xmlDoc *doc;
507 xmlNode *node, *param, *xval;
508 xmlChar *xmlMethodName = NULL;
509 gboolean success = FALSE;
510 GValue value;
511
512 doc = xmlParseMemory (method_call,
513 length == -1 ? strlen (method_call) : length);
514 if (!doc)
515 return FALSE;
516
517 node = xmlDocGetRootElement (doc);
518 if (!node || strcmp ((const char *)node->name, "methodCall") != 0)
519 goto fail;
520
521 node = find_real_node (node->children);
522 if (!node || strcmp ((const char *)node->name, "methodName") != 0)
523 goto fail;
524 xmlMethodName = xmlNodeGetContent (node);
525
526 node = find_real_node (node->next);
527 if (node) {
528 if (strcmp ((const char *)node->name, "params") != 0)
529 goto fail;
530
531 *params = soup_value_array_new ();
532 param = find_real_node (node->children);
533 while (param && !strcmp ((const char *)param->name, "param")) {
534 xval = find_real_node (param->children);
535 if (!xval || strcmp ((const char *)xval->name, "value") != 0 ||
536 !parse_value (xval, &value)) {
537 g_value_array_free (*params);
538 goto fail;
539 }
540 g_value_array_append (*params, &value);
541 g_value_unset (&value);
542
543 param = find_real_node (param->next);
544 }
545 } else
546 *params = soup_value_array_new ();
547
548 success = TRUE;
549 *method_name = g_strdup ((char *)xmlMethodName);
550
551 fail:
552 xmlFreeDoc (doc);
553 if (xmlMethodName)
554 xmlFree (xmlMethodName);
555 return success;
556 }
557
558 /**
559 * soup_xmlrpc_extract_method_call:
560 * @method_call: the XML-RPC methodCall string
561 * @length: the length of @method_call, or -1 if it is NUL-terminated
562 * @method_name: (out): on return, the methodName from @method_call
563 * @...: return types and locations for parameters
564 *
565 * Parses @method_call to get the name and parameters, and puts
566 * the parameters into variables of the appropriate types.
567 *
568 * The parameters are handled similarly to
569 * @soup_xmlrpc_build_method_call, with pairs of types and values,
570 * terminated by %G_TYPE_INVALID, except that values are pointers to
571 * variables of the indicated type, rather than values of the type.
572 *
573 * See also soup_xmlrpc_parse_method_call(), which can be used if
574 * you don't know the types of the parameters.
575 *
576 * Return value: success or failure.
577 *
578 * Deprecated: Use soup_xmlrpc_parse_request_full() instead.
579 **/
580 gboolean
soup_xmlrpc_extract_method_call(const char * method_call,int length,char ** method_name,...)581 soup_xmlrpc_extract_method_call (const char *method_call, int length,
582 char **method_name, ...)
583 {
584 GValueArray *params;
585 gboolean success;
586 va_list args;
587
588 if (!soup_xmlrpc_parse_method_call (method_call, length,
589 method_name, ¶ms))
590 return FALSE;
591
592 va_start (args, method_name);
593 success = soup_value_array_to_args (params, args);
594 va_end (args);
595
596 g_value_array_free (params);
597
598 return success;
599 }
600
601 /**
602 * soup_xmlrpc_parse_method_response:
603 * @method_response: the XML-RPC methodResponse string
604 * @length: the length of @method_response, or -1 if it is NUL-terminated
605 * @value: (out): on return, the return value from @method_call
606 * @error: error return value
607 *
608 * Parses @method_response and returns the return value in @value. If
609 * @method_response is a fault, @value will be unchanged, and @error
610 * will be set to an error of type %SOUP_XMLRPC_FAULT, with the error
611 * #code containing the fault code, and the error #message containing
612 * the fault string. (If @method_response cannot be parsed at all,
613 * soup_xmlrpc_parse_method_response() will return %FALSE, but @error
614 * will be unset.)
615 *
616 * Return value: %TRUE if a return value was parsed, %FALSE if the
617 * response could not be parsed, or contained a fault.
618 *
619 * Deprecated: Use soup_xmlrpc_parse_response() instead.
620 **/
621 gboolean
soup_xmlrpc_parse_method_response(const char * method_response,int length,GValue * value,GError ** error)622 soup_xmlrpc_parse_method_response (const char *method_response, int length,
623 GValue *value, GError **error)
624 {
625 xmlDoc *doc;
626 xmlNode *node;
627 gboolean success = FALSE;
628
629 doc = xmlParseMemory (method_response,
630 length == -1 ? strlen (method_response) : length);
631 if (!doc)
632 return FALSE;
633
634 node = xmlDocGetRootElement (doc);
635 if (!node || strcmp ((const char *)node->name, "methodResponse") != 0)
636 goto fail;
637
638 node = find_real_node (node->children);
639 if (!node)
640 goto fail;
641
642 if (!strcmp ((const char *)node->name, "fault") && error) {
643 int fault_code;
644 char *fault_string;
645 GValue fault_val;
646 GHashTable *fault_hash;
647
648 node = find_real_node (node->children);
649 if (!node || strcmp ((const char *)node->name, "value") != 0)
650 goto fail;
651 if (!parse_value (node, &fault_val))
652 goto fail;
653 if (!G_VALUE_HOLDS (&fault_val, G_TYPE_HASH_TABLE)) {
654 g_value_unset (&fault_val);
655 goto fail;
656 }
657 fault_hash = g_value_get_boxed (&fault_val);
658 if (!soup_value_hash_lookup (fault_hash, "faultCode",
659 G_TYPE_INT, &fault_code) ||
660 !soup_value_hash_lookup (fault_hash, "faultString",
661 G_TYPE_STRING, &fault_string)) {
662 g_value_unset (&fault_val);
663 goto fail;
664 }
665
666 g_set_error (error, SOUP_XMLRPC_FAULT,
667 fault_code, "%s", fault_string);
668 g_value_unset (&fault_val);
669 } else if (!strcmp ((const char *)node->name, "params")) {
670 node = find_real_node (node->children);
671 if (!node || strcmp ((const char *)node->name, "param") != 0)
672 goto fail;
673 node = find_real_node (node->children);
674 if (!node || strcmp ((const char *)node->name, "value") != 0)
675 goto fail;
676 if (!parse_value (node, value))
677 goto fail;
678 success = TRUE;
679 }
680
681 fail:
682 xmlFreeDoc (doc);
683 return success;
684 }
685
686 /**
687 * soup_xmlrpc_extract_method_response:
688 * @method_response: the XML-RPC methodResponse string
689 * @length: the length of @method_response, or -1 if it is NUL-terminated
690 * @error: error return value
691 * @type: the expected type of the return value
692 * @...: location for return value
693 *
694 * Parses @method_response and extracts the return value into
695 * a variable of the correct type.
696 *
697 * If @method_response is a fault, the return value will be unset,
698 * and @error will be set to an error of type %SOUP_XMLRPC_FAULT, with
699 * the error #code containing the fault code, and the error #message
700 * containing the fault string. (If @method_response cannot be parsed
701 * at all, soup_xmlrpc_extract_method_response() will return %FALSE,
702 * but @error will be unset.)
703 *
704 * Return value: %TRUE if a return value was parsed, %FALSE if the
705 * response was of the wrong type, or contained a fault.
706 *
707 * Deprecated: Use soup_xmlrpc_parse_response() instead.
708 **/
709 gboolean
soup_xmlrpc_extract_method_response(const char * method_response,int length,GError ** error,GType type,...)710 soup_xmlrpc_extract_method_response (const char *method_response, int length,
711 GError **error, GType type, ...)
712 {
713 GValue value;
714 va_list args;
715
716 if (!soup_xmlrpc_parse_method_response (method_response, length,
717 &value, error))
718 return FALSE;
719 if (!G_VALUE_HOLDS (&value, type))
720 return FALSE;
721
722 va_start (args, type);
723 SOUP_VALUE_GETV (&value, type, args);
724 va_end (args);
725
726 return TRUE;
727 }
728
729 static xmlNode *
find_real_node(xmlNode * node)730 find_real_node (xmlNode *node)
731 {
732 while (node && (node->type == XML_COMMENT_NODE ||
733 xmlIsBlankNode (node)))
734 node = node->next;
735 return node;
736 }
737
738 G_GNUC_END_IGNORE_DEPRECATIONS
739