1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-xmlrpc.c: XML-RPC parser/generator
5 * Copyright (C) 2007 Red Hat, Inc.
14 #include <libxml/tree.h>
16 #include "soup-xmlrpc.h"
21 * @short_description: XML-RPC support
25 static xmlNode *find_real_node (xmlNode *node);
27 static gboolean insert_value (xmlNode *parent, GValue *value);
30 insert_value (xmlNode *parent, GValue *value)
32 GType type = G_VALUE_TYPE (value);
36 xvalue = xmlNewChild (parent, NULL, (const xmlChar *)"value", NULL);
38 if (type == G_TYPE_INT) {
39 snprintf (buf, sizeof (buf), "%d", g_value_get_int (value));
40 xmlNewChild (xvalue, NULL,
41 (const xmlChar *)"int",
42 (const xmlChar *)buf);
43 } else if (type == G_TYPE_BOOLEAN) {
44 snprintf (buf, sizeof (buf), "%d", g_value_get_boolean (value));
45 xmlNewChild (xvalue, NULL,
46 (const xmlChar *)"boolean",
47 (const xmlChar *)buf);
48 } else if (type == G_TYPE_STRING) {
49 xmlNewTextChild (xvalue, NULL,
50 (const xmlChar *)"string",
51 (const xmlChar *)g_value_get_string (value));
52 } else if (type == G_TYPE_DOUBLE) {
53 g_ascii_dtostr (buf, sizeof (buf), g_value_get_double (value));
54 xmlNewChild (xvalue, NULL,
55 (const xmlChar *)"double",
56 (const xmlChar *)buf);
57 } else if (type == SOUP_TYPE_DATE) {
58 SoupDate *date = g_value_get_boxed (value);
59 char *timestamp = soup_date_to_string (date, SOUP_DATE_ISO8601_XMLRPC);
60 xmlNewChild (xvalue, NULL,
61 (const xmlChar *)"dateTime.iso8601",
62 (const xmlChar *)timestamp);
64 } else if (type == SOUP_TYPE_BYTE_ARRAY) {
65 GByteArray *ba = g_value_get_boxed (value);
68 encoded = g_base64_encode (ba->data, ba->len);
69 xmlNewChild (xvalue, NULL,
70 (const xmlChar *)"base64",
71 (const xmlChar *)encoded);
73 } else if (type == G_TYPE_HASH_TABLE) {
74 GHashTable *hash = g_value_get_boxed (value);
76 gpointer mname, mvalue;
77 xmlNode *struct_node, *member;
79 struct_node = xmlNewChild (xvalue, NULL,
80 (const xmlChar *)"struct", NULL);
82 g_hash_table_iter_init (&iter, hash);
84 while (g_hash_table_iter_next (&iter, &mname, &mvalue)) {
85 member = xmlNewChild (struct_node, NULL,
86 (const xmlChar *)"member", NULL);
87 xmlNewTextChild (member, NULL,
88 (const xmlChar *)"name",
89 (const xmlChar *)mname);
90 if (!insert_value (member, mvalue)) {
91 xmlFreeNode (struct_node);
99 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
100 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
102 } else if (type == G_TYPE_VALUE_ARRAY) {
103 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
104 G_GNUC_END_IGNORE_DEPRECATIONS
106 GValueArray *va = g_value_get_boxed (value);
110 node = xmlNewChild (xvalue, NULL,
111 (const xmlChar *)"array", NULL);
112 node = xmlNewChild (node, NULL,
113 (const xmlChar *)"data", NULL);
114 for (i = 0; i < va->n_values; i++) {
115 if (!insert_value (node, &va->values[i]))
125 * soup_xmlrpc_build_method_call:
126 * @method_name: the name of the XML-RPC method
127 * @params: (array length=n_params): arguments to @method
128 * @n_params: length of @params
130 * This creates an XML-RPC methodCall and returns it as a string.
131 * This is the low-level method that soup_xmlrpc_request_new() is
134 * @params is an array of #GValue representing the parameters to
135 * @method. (It is *not* a #GValueArray, although if you have a
136 * #GValueArray, you can just pass its <literal>values</literal>f and
137 * <literal>n_values</literal> fields.)
139 * The correspondence between glib types and XML-RPC types is:
141 * int: #int (%G_TYPE_INT)
142 * boolean: #gboolean (%G_TYPE_BOOLEAN)
143 * string: #char* (%G_TYPE_STRING)
144 * double: #double (%G_TYPE_DOUBLE)
145 * datetime.iso8601: #SoupDate (%SOUP_TYPE_DATE)
146 * base64: #GByteArray (%SOUP_TYPE_BYTE_ARRAY)
147 * struct: #GHashTable (%G_TYPE_HASH_TABLE)
148 * array: #GValueArray (%G_TYPE_VALUE_ARRAY)
150 * For structs, use a #GHashTable that maps strings to #GValue;
151 * soup_value_hash_new() and related methods can help with this.
153 * Return value: the text of the methodCall, or %NULL on error
156 soup_xmlrpc_build_method_call (const char *method_name,
157 GValue *params, int n_params)
160 xmlNode *node, *param;
165 doc = xmlNewDoc ((const xmlChar *)"1.0");
166 doc->standalone = FALSE;
167 doc->encoding = xmlCharStrdup ("UTF-8");
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);
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])) {
184 xmlDocDumpMemory (doc, &xmlbody, &len);
185 body = g_strndup ((char *)xmlbody, len);
192 soup_xmlrpc_request_newv (const char *uri, const char *method_name, va_list args)
198 params = soup_value_array_from_args (args);
202 body = soup_xmlrpc_build_method_call (method_name, params->values,
204 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
205 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
207 g_value_array_free (params);
208 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
209 G_GNUC_END_IGNORE_DEPRECATIONS
214 msg = soup_message_new ("POST", uri);
215 soup_message_set_request (msg, "text/xml", SOUP_MEMORY_TAKE,
216 body, strlen (body));
221 * soup_xmlrpc_request_new:
222 * @uri: URI of the XML-RPC service
223 * @method_name: the name of the XML-RPC method to invoke at @uri
224 * @...: parameters for @method
226 * Creates an XML-RPC methodCall and returns a #SoupMessage, ready
227 * to send, for that method call.
229 * The parameters are passed as type/value pairs; ie, first a #GType,
230 * and then a value of the appropriate type, finally terminated by
233 * Return value: (transfer full): a #SoupMessage encoding the
234 * indicated XML-RPC request.
237 soup_xmlrpc_request_new (const char *uri, const char *method_name, ...)
242 va_start (args, method_name);
243 msg = soup_xmlrpc_request_newv (uri, method_name, args);
249 * soup_xmlrpc_build_method_response:
250 * @value: the return value
252 * This creates a (successful) XML-RPC methodResponse and returns it
253 * as a string. To create a fault response, use
254 * soup_xmlrpc_build_fault().
256 * The glib type to XML-RPC type mapping is as with
257 * soup_xmlrpc_build_method_call(), qv.
259 * Return value: the text of the methodResponse, or %NULL on error
262 soup_xmlrpc_build_method_response (GValue *value)
270 doc = xmlNewDoc ((const xmlChar *)"1.0");
271 doc->standalone = FALSE;
272 doc->encoding = xmlCharStrdup ("UTF-8");
274 node = xmlNewDocNode (doc, NULL,
275 (const xmlChar *)"methodResponse", NULL);
276 xmlDocSetRootElement (doc, node);
278 node = xmlNewChild (node, NULL, (const xmlChar *)"params", NULL);
279 node = xmlNewChild (node, NULL, (const xmlChar *)"param", NULL);
280 if (!insert_value (node, value)) {
285 xmlDocDumpMemory (doc, &xmlbody, &len);
286 body = g_strndup ((char *)xmlbody, len);
293 soup_xmlrpc_build_faultv (int fault_code,
294 const char *fault_format,
295 va_list args) G_GNUC_PRINTF (2, 0);
298 soup_xmlrpc_build_faultv (int fault_code, const char *fault_format, va_list args)
301 xmlNode *node, *member;
304 char *fault_string, *body;
307 fault_string = g_strdup_vprintf (fault_format, args);
309 doc = xmlNewDoc ((const xmlChar *)"1.0");
310 doc->standalone = FALSE;
311 doc->encoding = xmlCharStrdup ("UTF-8");
313 node = xmlNewDocNode (doc, NULL,
314 (const xmlChar *)"methodResponse", NULL);
315 xmlDocSetRootElement (doc, node);
316 node = xmlNewChild (node, NULL, (const xmlChar *)"fault", NULL);
317 node = xmlNewChild (node, NULL, (const xmlChar *)"value", NULL);
318 node = xmlNewChild (node, NULL, (const xmlChar *)"struct", NULL);
320 memset (&value, 0, sizeof (value));
322 member = xmlNewChild (node, NULL, (const xmlChar *)"member", NULL);
323 xmlNewChild (member, NULL,
324 (const xmlChar *)"name", (const xmlChar *)"faultCode");
325 g_value_init (&value, G_TYPE_INT);
326 g_value_set_int (&value, fault_code);
327 insert_value (member, &value);
328 g_value_unset (&value);
330 member = xmlNewChild (node, NULL, (const xmlChar *)"member", NULL);
331 xmlNewChild (member, NULL,
332 (const xmlChar *)"name", (const xmlChar *)"faultString");
333 g_value_init (&value, G_TYPE_STRING);
334 g_value_take_string (&value, fault_string);
335 insert_value (member, &value);
336 g_value_unset (&value);
338 xmlDocDumpMemory (doc, &xmlbody, &len);
339 body = g_strndup ((char *)xmlbody, len);
347 * soup_xmlrpc_build_fault:
348 * @fault_code: the fault code
349 * @fault_format: a printf()-style format string
350 * @...: the parameters to @fault_format
352 * This creates an XML-RPC fault response and returns it as a string.
353 * (To create a successful response, use
354 * soup_xmlrpc_build_method_response().)
356 * Return value: the text of the fault
359 soup_xmlrpc_build_fault (int fault_code, const char *fault_format, ...)
364 va_start (args, fault_format);
365 body = soup_xmlrpc_build_faultv (fault_code, fault_format, args);
371 * soup_xmlrpc_set_response:
372 * @msg: an XML-RPC request
373 * @type: the type of the response value
374 * @...: the response value
376 * Sets the status code and response body of @msg to indicate a
377 * successful XML-RPC call, with a return value given by @type and the
378 * following varargs argument, of the type indicated by @type.
381 soup_xmlrpc_set_response (SoupMessage *msg, GType type, ...)
387 va_start (args, type);
388 SOUP_VALUE_SETV (&value, type, args);
391 body = soup_xmlrpc_build_method_response (&value);
392 g_value_unset (&value);
393 soup_message_set_status (msg, SOUP_STATUS_OK);
394 soup_message_set_response (msg, "text/xml", SOUP_MEMORY_TAKE,
395 body, strlen (body));
399 * soup_xmlrpc_set_fault:
400 * @msg: an XML-RPC request
401 * @fault_code: the fault code
402 * @fault_format: a printf()-style format string
403 * @...: the parameters to @fault_format
405 * Sets the status code and response body of @msg to indicate an
406 * unsuccessful XML-RPC call, with the error described by @fault_code
410 soup_xmlrpc_set_fault (SoupMessage *msg, int fault_code,
411 const char *fault_format, ...)
416 va_start (args, fault_format);
417 body = soup_xmlrpc_build_faultv (fault_code, fault_format, args);
420 soup_message_set_status (msg, SOUP_STATUS_OK);
421 soup_message_set_response (msg, "text/xml", SOUP_MEMORY_TAKE,
422 body, strlen (body));
428 parse_value (xmlNode *xmlvalue, GValue *value)
431 const char *typename;
434 memset (value, 0, sizeof (GValue));
436 typenode = find_real_node (xmlvalue->children);
438 /* If no type node, it's a string */
439 content = xmlNodeGetContent (typenode);
440 g_value_init (value, G_TYPE_STRING);
441 g_value_set_string (value, (char *)content);
446 typename = (const char *)typenode->name;
448 if (!strcmp (typename, "i4") || !strcmp (typename, "int")) {
449 content = xmlNodeGetContent (typenode);
450 g_value_init (value, G_TYPE_INT);
451 g_value_set_int (value, atoi ((char *)content));
453 } else if (!strcmp (typename, "boolean")) {
454 content = xmlNodeGetContent (typenode);
455 g_value_init (value, G_TYPE_BOOLEAN);
456 g_value_set_boolean (value, atoi ((char *)content));
458 } else if (!strcmp (typename, "string")) {
459 content = xmlNodeGetContent (typenode);
460 g_value_init (value, G_TYPE_STRING);
461 g_value_set_string (value, (char *)content);
463 } else if (!strcmp (typename, "double")) {
464 content = xmlNodeGetContent (typenode);
465 g_value_init (value, G_TYPE_DOUBLE);
466 g_value_set_double (value, g_ascii_strtod ((char *)content, NULL));
468 } else if (!strcmp (typename, "dateTime.iso8601")) {
469 content = xmlNodeGetContent (typenode);
470 g_value_init (value, SOUP_TYPE_DATE);
471 g_value_take_boxed (value, soup_date_new_from_string ((char *)content));
473 } else if (!strcmp (typename, "base64")) {
478 content = xmlNodeGetContent (typenode);
479 decoded = g_base64_decode ((char *)content, &len);
480 ba = g_byte_array_sized_new (len);
481 g_byte_array_append (ba, decoded, len);
484 g_value_init (value, SOUP_TYPE_BYTE_ARRAY);
485 g_value_take_boxed (value, ba);
486 } else if (!strcmp (typename, "struct")) {
487 xmlNode *member, *child, *mname, *mxval;
491 hash = soup_value_hash_new ();
492 for (member = find_real_node (typenode->children);
494 member = find_real_node (member->next)) {
495 if (strcmp ((const char *)member->name, "member") != 0) {
496 g_hash_table_destroy (hash);
499 mname = mxval = NULL;
500 memset (&mgval, 0, sizeof (mgval));
502 for (child = find_real_node (member->children);
504 child = find_real_node (child->next)) {
505 if (!strcmp ((const char *)child->name, "name"))
507 else if (!strcmp ((const char *)child->name, "value"))
513 if (!mname || !mxval || !parse_value (mxval, &mgval)) {
514 g_hash_table_destroy (hash);
518 content = xmlNodeGetContent (mname);
519 soup_value_hash_insert_value (hash, (char *)content, &mgval);
521 g_value_unset (&mgval);
523 g_value_init (value, G_TYPE_HASH_TABLE);
524 g_value_take_boxed (value, hash);
525 } else if (!strcmp (typename, "array")) {
526 xmlNode *data, *xval;
530 data = find_real_node (typenode->children);
531 if (!data || strcmp ((const char *)data->name, "data") != 0)
534 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
535 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
537 array = g_value_array_new (1);
538 for (xval = find_real_node (data->children);
540 xval = find_real_node (xval->next)) {
541 memset (&gval, 0, sizeof (gval));
542 if (strcmp ((const char *)xval->name, "value") != 0 ||
543 !parse_value (xval, &gval)) {
544 g_value_array_free (array);
548 g_value_array_append (array, &gval);
549 g_value_unset (&gval);
551 g_value_init (value, G_TYPE_VALUE_ARRAY);
552 g_value_take_boxed (value, array);
553 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
554 G_GNUC_END_IGNORE_DEPRECATIONS
563 * soup_xmlrpc_parse_method_call:
564 * @method_call: the XML-RPC methodCall string
565 * @length: the length of @method_call, or -1 if it is NUL-terminated
566 * @method_name: (out): on return, the methodName from @method_call
567 * @params: (out): on return, the parameters from @method_call
569 * Parses @method_call to get the name and parameters, and returns the
570 * parameter values in a #GValueArray; see also
571 * soup_xmlrpc_extract_method_call(), which is more convenient if you
572 * know in advance what the types of the parameters will be.
574 * Return value: success or failure.
577 soup_xmlrpc_parse_method_call (const char *method_call, int length,
578 char **method_name, GValueArray **params)
581 xmlNode *node, *param, *xval;
582 xmlChar *xmlMethodName = NULL;
583 gboolean success = FALSE;
586 doc = xmlParseMemory (method_call,
587 length == -1 ? strlen (method_call) : length);
591 node = xmlDocGetRootElement (doc);
592 if (!node || strcmp ((const char *)node->name, "methodCall") != 0)
595 node = find_real_node (node->children);
596 if (!node || strcmp ((const char *)node->name, "methodName") != 0)
598 xmlMethodName = xmlNodeGetContent (node);
600 node = find_real_node (node->next);
602 if (strcmp ((const char *)node->name, "params") != 0)
605 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
606 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
608 *params = soup_value_array_new ();
609 param = find_real_node (node->children);
610 while (param && !strcmp ((const char *)param->name, "param")) {
611 xval = find_real_node (param->children);
612 if (!xval || strcmp ((const char *)xval->name, "value") != 0 ||
613 !parse_value (xval, &value)) {
614 g_value_array_free (*params);
617 g_value_array_append (*params, &value);
618 g_value_unset (&value);
620 param = find_real_node (param->next);
622 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
623 G_GNUC_END_IGNORE_DEPRECATIONS
626 *params = soup_value_array_new ();
629 *method_name = g_strdup ((char *)xmlMethodName);
634 xmlFree (xmlMethodName);
639 * soup_xmlrpc_extract_method_call:
640 * @method_call: the XML-RPC methodCall string
641 * @length: the length of @method_call, or -1 if it is NUL-terminated
642 * @method_name: (out): on return, the methodName from @method_call
643 * @...: return types and locations for parameters
645 * Parses @method_call to get the name and parameters, and puts
646 * the parameters into variables of the appropriate types.
648 * The parameters are handled similarly to
649 * @soup_xmlrpc_build_method_call, with pairs of types and values,
650 * terminated by %G_TYPE_INVALID, except that values are pointers to
651 * variables of the indicated type, rather than values of the type.
653 * See also soup_xmlrpc_parse_method_call(), which can be used if
654 * you don't know the types of the parameters.
656 * Return value: success or failure.
659 soup_xmlrpc_extract_method_call (const char *method_call, int length,
660 char **method_name, ...)
666 if (!soup_xmlrpc_parse_method_call (method_call, length,
667 method_name, ¶ms))
670 va_start (args, method_name);
671 success = soup_value_array_to_args (params, args);
674 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
675 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
677 g_value_array_free (params);
678 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
679 G_GNUC_END_IGNORE_DEPRECATIONS
685 * soup_xmlrpc_parse_method_response:
686 * @method_response: the XML-RPC methodResponse string
687 * @length: the length of @method_response, or -1 if it is NUL-terminated
688 * @value: (out): on return, the return value from @method_call
689 * @error: error return value
691 * Parses @method_response and returns the return value in @value. If
692 * @method_response is a fault, @value will be unchanged, and @error
693 * will be set to an error of type %SOUP_XMLRPC_FAULT, with the error
694 * #code containing the fault code, and the error #message containing
695 * the fault string. (If @method_response cannot be parsed at all,
696 * soup_xmlrpc_parse_method_response() will return %FALSE, but @error
699 * Return value: %TRUE if a return value was parsed, %FALSE if the
700 * response could not be parsed, or contained a fault.
703 soup_xmlrpc_parse_method_response (const char *method_response, int length,
704 GValue *value, GError **error)
708 gboolean success = FALSE;
710 doc = xmlParseMemory (method_response,
711 length == -1 ? strlen (method_response) : length);
715 node = xmlDocGetRootElement (doc);
716 if (!node || strcmp ((const char *)node->name, "methodResponse") != 0)
719 node = find_real_node (node->children);
723 if (!strcmp ((const char *)node->name, "fault") && error) {
727 GHashTable *fault_hash;
729 node = find_real_node (node->children);
730 if (!node || strcmp ((const char *)node->name, "value") != 0)
732 if (!parse_value (node, &fault_val))
734 if (!G_VALUE_HOLDS (&fault_val, G_TYPE_HASH_TABLE)) {
735 g_value_unset (&fault_val);
738 fault_hash = g_value_get_boxed (&fault_val);
739 if (!soup_value_hash_lookup (fault_hash, "faultCode",
740 G_TYPE_INT, &fault_code) ||
741 !soup_value_hash_lookup (fault_hash, "faultString",
742 G_TYPE_STRING, &fault_string)) {
743 g_value_unset (&fault_val);
747 g_set_error (error, SOUP_XMLRPC_FAULT,
748 fault_code, "%s", fault_string);
749 g_value_unset (&fault_val);
750 } else if (!strcmp ((const char *)node->name, "params")) {
751 node = find_real_node (node->children);
752 if (!node || strcmp ((const char *)node->name, "param") != 0)
754 node = find_real_node (node->children);
755 if (!node || strcmp ((const char *)node->name, "value") != 0)
757 if (!parse_value (node, value))
768 * soup_xmlrpc_extract_method_response:
769 * @method_response: the XML-RPC methodResponse string
770 * @length: the length of @method_response, or -1 if it is NUL-terminated
771 * @error: error return value
772 * @type: the expected type of the return value
773 * @...: location for return value
775 * Parses @method_response and extracts the return value into
776 * a variable of the correct type.
778 * If @method_response is a fault, the return value will be unset,
779 * and @error will be set to an error of type %SOUP_XMLRPC_FAULT, with
780 * the error #code containing the fault code, and the error #message
781 * containing the fault string. (If @method_response cannot be parsed
782 * at all, soup_xmlrpc_extract_method_response() will return %FALSE,
783 * but @error will be unset.)
785 * Return value: %TRUE if a return value was parsed, %FALSE if the
786 * response was of the wrong type, or contained a fault.
789 soup_xmlrpc_extract_method_response (const char *method_response, int length,
790 GError **error, GType type, ...)
795 if (!soup_xmlrpc_parse_method_response (method_response, length,
798 if (!G_VALUE_HOLDS (&value, type))
801 va_start (args, type);
802 SOUP_VALUE_GETV (&value, type, args);
810 soup_xmlrpc_error_quark (void)
814 error = g_quark_from_static_string ("soup_xmlrpc_error_quark");
821 * A #GError domain representing an XML-RPC fault code. Used with
822 * #SoupXMLRPCFault (although servers may also return fault codes not
823 * in that enumeration).
828 * @SOUP_XMLRPC_FAULT_PARSE_ERROR_NOT_WELL_FORMED: request was not
830 * @SOUP_XMLRPC_FAULT_PARSE_ERROR_UNSUPPORTED_ENCODING: request was in
831 * an unsupported encoding
832 * @SOUP_XMLRPC_FAULT_PARSE_ERROR_INVALID_CHARACTER_FOR_ENCODING:
833 * request contained an invalid character
834 * @SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_XML_RPC: request was not
836 * @SOUP_XMLRPC_FAULT_SERVER_ERROR_REQUESTED_METHOD_NOT_FOUND: method
838 * @SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_METHOD_PARAMETERS: invalid
840 * @SOUP_XMLRPC_FAULT_SERVER_ERROR_INTERNAL_XML_RPC_ERROR: internal
842 * @SOUP_XMLRPC_FAULT_APPLICATION_ERROR: start of reserved range for
843 * application error codes
844 * @SOUP_XMLRPC_FAULT_SYSTEM_ERROR: start of reserved range for
846 * @SOUP_XMLRPC_FAULT_TRANSPORT_ERROR: start of reserved range for
847 * transport error codes
849 * Pre-defined XML-RPC fault codes from <ulink
850 * url="http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php">http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php</ulink>.
851 * These are an extension, not part of the XML-RPC spec; you can't
852 * assume servers will use them.
856 soup_xmlrpc_fault_quark (void)
860 error = g_quark_from_static_string ("soup_xmlrpc_fault_quark");
865 find_real_node (xmlNode *node)
867 while (node && (node->type == XML_COMMENT_NODE ||
868 xmlIsBlankNode (node)))