From: David Woodhouse Date: Wed, 21 Jul 2010 09:50:27 +0000 (+0100) Subject: Import soup-soap-message X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=ad126322424822eda156d8783fed4608257ffa50;p=users%2Fdwmw2%2Fews-sync.git Import soup-soap-message --- diff --git a/Makefile b/Makefile index 3b384d3..087c560 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,8 @@ CFLAGS_ews_syncfolder.o := $(SOUP_CFLAGS) CFLAGS_ews_autodiscover.o := $(SOUP_CFLAGS) CFLAGS_ews2ical.o := $(ICAL_CFLAGS) CFLAGS_calitem_to_ical.o := $(ICAL_CFLAGS) +CFLAGS_soup-soap-message.o := $(SOUP_CFLAGS) +CFLAGS_soup-soap-response.o := $(SOUP_CFLAGS) %.o: %.c $(CC) -c -o $@ $(CFLAGS) $(CFLAGS_$@) $< -MD -MF .$@.dep @@ -51,6 +53,8 @@ PROGS := ews_syncfolder ews_autodiscover ews2ical all: $(PROGS) +-include $(wildcard .*o.dep) /dev/null + clean: rm -f $(PROGS) *.o .*.o.dep @@ -60,5 +64,5 @@ ews2ical: ews2ical.o calitem_to_ical.o ews_autodiscover: ews_autodiscover.o $(CC) -o $@ $^ $(LDFLAGS) $(XML2_LDFLAGS) $(SOUP_LDFLAGS) $(GLIB_LDFLAGS) -ews_syncfolder: ews_syncfolder.o calitem_to_ical.o +ews_syncfolder: ews_syncfolder.o calitem_to_ical.o soup-soap-message.o soup-soap-response.o $(CC) -o $@ $^ $(LDFLAGS) $(XML2_LDFLAGS) $(SOUP_LDFLAGS) $(GLIB_LDFLAGS) $(ICAL_LDFLAGS) diff --git a/soup-soap-message.c b/soup-soap-message.c new file mode 100644 index 0000000..2f26bc9 --- /dev/null +++ b/soup-soap-message.c @@ -0,0 +1,816 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#include +#include +#include "soup-soap-message.h" + +G_DEFINE_TYPE (SoupSoapMessage, soup_soap_message, SOUP_TYPE_MESSAGE) + +typedef struct { + /* Serialization fields */ + xmlDocPtr doc; + xmlNodePtr last_node; + xmlNsPtr soap_ns; + xmlNsPtr xsi_ns; + xmlChar *env_prefix; + xmlChar *env_uri; + gboolean body_started; + gchar *action; +} SoupSoapMessagePrivate; +#define SOUP_SOAP_MESSAGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SOAP_MESSAGE, SoupSoapMessagePrivate)) + +static void +finalize (GObject *object) +{ + SoupSoapMessagePrivate *priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (object); + + if (priv->doc) + xmlFreeDoc (priv->doc); + if (priv->action) + g_free (priv->action); + if (priv->env_uri) + xmlFree (priv->env_uri); + if (priv->env_prefix) + xmlFree (priv->env_prefix); + + G_OBJECT_CLASS (soup_soap_message_parent_class)->finalize (object); +} + +static void +soup_soap_message_class_init (SoupSoapMessageClass *soup_soap_message_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (soup_soap_message_class); + + g_type_class_add_private (soup_soap_message_class, sizeof (SoupSoapMessagePrivate)); + + object_class->finalize = finalize; +} + +static void +soup_soap_message_init (SoupSoapMessage *msg) +{ + SoupSoapMessagePrivate *priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + /* initialize XML structures */ + priv->doc = xmlNewDoc ((const xmlChar *)"1.0"); + priv->doc->standalone = FALSE; + priv->doc->encoding = xmlCharStrdup ("UTF-8"); +} + +static xmlNsPtr +fetch_ns (SoupSoapMessage *msg, const gchar *prefix, const gchar *ns_uri) +{ + SoupSoapMessagePrivate *priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + xmlNsPtr ns = NULL; + + if (prefix && ns_uri) + ns = xmlNewNs (priv->last_node, (const xmlChar *)ns_uri, (const xmlChar *)prefix); + else if (prefix && !ns_uri) { + ns = xmlSearchNs (priv->doc, priv->last_node, (const xmlChar *)prefix); + if (!ns) + ns = xmlNewNs (priv->last_node, (const xmlChar *)"", (const xmlChar *)prefix); + } + + return ns; +} + +/** + * soup_soap_message_new: + * @method: the HTTP method for the created request. + * @uri_string: the destination endpoint (as a string). + * @standalone: ??? FIXME + * @xml_encoding: ??? FIXME + * @env_prefix: ??? FIXME + * @env_uri: ??? FIXME + * + * Creates a new empty #SoupSoapMessage, which will connect to @uri_string. + * + * Returns: the new #SoupSoapMessage (or %NULL if @uri_string could not be + * parsed). + */ +SoupSoapMessage * +soup_soap_message_new (const gchar *method, const gchar *uri_string, + gboolean standalone, const gchar *xml_encoding, + const gchar *env_prefix, const gchar *env_uri) +{ + SoupSoapMessage *msg; + SoupURI *uri; + + uri = soup_uri_new (uri_string); + if (!uri) + return NULL; + + msg = soup_soap_message_new_from_uri (method, uri, standalone, + xml_encoding, env_prefix, env_uri); + + soup_uri_free (uri); + + return msg; +} + +/** + * soup_soap_message_new_from_uri: + * @method: the HTTP method for the created request. + * @uri: the destination endpoint (as a #SoupURI). + * @standalone: ??? FIXME + * @xml_encoding: ??? FIXME + * @env_prefix: ??? FIXME + * @env_uri: ??? FIXME + * + * Creates a new empty #SoupSoapMessage, which will connect to @uri + * + * Returns: the new #SoupSoapMessage + */ +SoupSoapMessage * +soup_soap_message_new_from_uri (const gchar *method, SoupURI *uri, + gboolean standalone, const gchar *xml_encoding, + const gchar *env_prefix, const gchar *env_uri) +{ + SoupSoapMessage *msg; + SoupSoapMessagePrivate *priv; + + msg = g_object_new (SOUP_TYPE_SOAP_MESSAGE, + SOUP_MESSAGE_METHOD, method, + SOUP_MESSAGE_URI, uri, + NULL); + + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + priv->doc->standalone = standalone; + + if (xml_encoding) { + xmlFree ((xmlChar *)priv->doc->encoding); + priv->doc->encoding = xmlCharStrdup (xml_encoding); + } + + if (env_prefix) + priv->env_prefix = xmlCharStrdup (env_prefix); + if (env_uri) + priv->env_uri = xmlCharStrdup (env_uri); + + return msg; +} + +/** + * soup_soap_message_start_envelope: + * @msg: the %SoupSoapMessage. + * + * Starts the top level SOAP Envelope element. + */ +void +soup_soap_message_start_envelope (SoupSoapMessage *msg) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + priv->last_node = priv->doc->xmlRootNode = + xmlNewDocNode (priv->doc, NULL, (const xmlChar *)"Envelope", NULL); + + priv->soap_ns = xmlNewNs (priv->doc->xmlRootNode, + priv->env_uri ? priv->env_uri : + (const xmlChar *)"http://schemas.xmlsoap.org/soap/envelope/", + priv->env_prefix ? priv->env_prefix : (const xmlChar *)"SOAP-ENV"); + if (priv->env_uri) { + xmlFree (priv->env_uri); + priv->env_uri = NULL; + } + if (priv->env_prefix) { + xmlFree (priv->env_prefix); + priv->env_prefix = NULL; + } + + xmlSetNs (priv->doc->xmlRootNode, priv->soap_ns); + + xmlNewNs (priv->doc->xmlRootNode, + (const xmlChar *)"http://schemas.xmlsoap.org/soap/encoding/", + (const xmlChar *)"SOAP-ENC"); + xmlNewNs (priv->doc->xmlRootNode, + (const xmlChar *)"http://www.w3.org/1999/XMLSchema", + (const xmlChar *)"xsd"); + xmlNewNs (priv->doc->xmlRootNode, + (const xmlChar *)"http://schemas.xmlsoap.org/soap/envelope/", + (const xmlChar *)"SOAP-ENV"); + priv->xsi_ns = xmlNewNs (priv->doc->xmlRootNode, + (const xmlChar *)"http://www.w3.org/1999/XMLSchema-instance", + (const xmlChar *)"xsi"); +} + +/** + * soup_soap_message_end_envelope: + * @msg: the %SoupSoapMessage. + * + * Closes the top level SOAP Envelope element. + */ +void +soup_soap_message_end_envelope (SoupSoapMessage *msg) +{ + soup_soap_message_end_element (msg); +} + +/** + * soup_soap_message_start_body: + * @msg: the %SoupSoapMessage. + * + * Starts the SOAP Body element. + */ +void +soup_soap_message_start_body (SoupSoapMessage *msg) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + if (priv->body_started) + return; + + priv->last_node = xmlNewChild (priv->last_node, + priv->soap_ns, + (const xmlChar *)"Body", NULL); + + priv->body_started = TRUE; +} + +/** + * soup_soap_message_end_body: + * @msg: the %SoupSoapMessage. + * + * Closes the SOAP Body element. + */ +void +soup_soap_message_end_body (SoupSoapMessage *msg) +{ + soup_soap_message_end_element (msg); +} + +/** + * soup_soap_message_start_element: + * @msg: the #SoupSoapMessage. + * @name: the element name. + * @prefix: the namespace prefix + * @ns_uri: the namespace URI + * + * Starts a new arbitrary message element, with @name as the element + * name, @prefix as the XML Namespace prefix, and @ns_uri as the XML + * Namespace uri for * the created element. + * + * Passing @prefix with no @ns_uri will cause a recursive search for + * an existing namespace with the same prefix. Failing that a new ns + * will be created with an empty uri. + * + * Passing both @prefix and @ns_uri always causes new namespace + * attribute creation. + * + * Passing NULL for both @prefix and @ns_uri causes no prefix to be + * used, and the element will be in the default namespace. + */ +void +soup_soap_message_start_element (SoupSoapMessage *msg, + const gchar *name, + const gchar *prefix, + const gchar *ns_uri) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + priv->last_node = xmlNewChild (priv->last_node, NULL, (const xmlChar *)name, NULL); + + xmlSetNs (priv->last_node, fetch_ns (msg, prefix, ns_uri)); + + if (priv->body_started && !priv->action) + priv->action = g_strconcat (ns_uri ? ns_uri : "", + "#", name, NULL); +} + +/** + * soup_soap_message_end_element: + * @msg: the #SoupSoapMessage. + * + * Closes the current message element. + */ +void +soup_soap_message_end_element (SoupSoapMessage *msg) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + priv->last_node = priv->last_node->parent; +} + +/** + * soup_soap_message_start_fault: + * @msg: the #SoupSoapMessage. + * @faultcode: faultcode element value + * @faultstring: faultstring element value + * @faultfactor: faultfactor element value + * + * Starts a new SOAP Fault element, creating faultcode, faultstring, + * and faultfactor child elements. + * + * If you wish to add the faultdetail element, use + * soup_soap_message_start_fault_detail(), and then + * soup_soap_message_start_element() to add arbitrary sub-elements. + */ +void +soup_soap_message_start_fault (SoupSoapMessage *msg, + const gchar *faultcode, + const gchar *faultstring, + const gchar *faultfactor) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + priv->last_node = xmlNewChild (priv->last_node, + priv->soap_ns, + (const xmlChar *)"Fault", NULL); + xmlNewChild (priv->last_node, priv->soap_ns, (const xmlChar *)"faultcode", (const xmlChar *)faultcode); + xmlNewChild (priv->last_node, priv->soap_ns, (const xmlChar *)"faultstring", (const xmlChar *)faultstring); + + priv->last_node = xmlNewChild (priv->last_node, priv->soap_ns, + (const xmlChar *)"faultfactor", (const xmlChar *)faultfactor); + if (!faultfactor) + soup_soap_message_set_null (msg); + + soup_soap_message_end_element (msg); +} + +/** + * soup_soap_message_end_fault: + * @msg: the #SoupSoapMessage. + * + * Closes the current SOAP Fault element. + */ +void +soup_soap_message_end_fault (SoupSoapMessage *msg) +{ + soup_soap_message_end_element (msg); +} + +/** + * soup_soap_message_start_fault_detail: + * @msg: the #SoupSoapMessage. + * + * Start the faultdetail child element of the current SOAP Fault + * element. The faultdetail element allows arbitrary data to be sent + * in a returned fault. + **/ +void +soup_soap_message_start_fault_detail (SoupSoapMessage *msg) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + priv->last_node = xmlNewChild (priv->last_node, + priv->soap_ns, + (const xmlChar *)"detail", + NULL); +} + +/** + * soup_soap_message_end_fault_detail: + * @msg: the #SoupSoapMessage. + * + * Closes the current SOAP faultdetail element. + */ +void +soup_soap_message_end_fault_detail (SoupSoapMessage *msg) +{ + soup_soap_message_end_element (msg); +} + +/** + * soup_soap_message_start_header: + * @msg: the #SoupSoapMessage. + * + * Creates a new SOAP Header element. You can call + * soup_soap_message_start_header_element() after this to add a new + * header child element. SOAP Header elements allow out-of-band data + * to be transferred while not interfering with the message body. + * + * This should be called after soup_soap_message_start_envelope() and + * before soup_soap_message_start_body(). + */ +void +soup_soap_message_start_header (SoupSoapMessage *msg) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + priv->last_node = xmlNewChild (priv->last_node, priv->soap_ns, + (const xmlChar *)"Header", NULL); +} + +/** + * soup_soap_message_end_header: + * @msg: the #SoupSoapMessage. + * + * Closes the current SOAP Header element. + */ +void +soup_soap_message_end_header (SoupSoapMessage *msg) +{ + soup_soap_message_end_element (msg); +} + +/** + * soup_soap_message_start_header_element: + * @msg: the #SoupSoapMessage. + * @name: name of the header element + * @must_understand: whether the recipient must understand the header in order + * to proceed with processing the message + * @actor_uri: the URI which represents the destination actor for this header. + * @prefix: the namespace prefix + * @ns_uri: the namespace URI + * + * Starts a new SOAP arbitrary header element. + */ +void +soup_soap_message_start_header_element (SoupSoapMessage *msg, + const gchar *name, + gboolean must_understand, + const gchar *actor_uri, + const gchar *prefix, + const gchar *ns_uri) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + soup_soap_message_start_element (msg, name, prefix, ns_uri); + if (actor_uri) + xmlNewNsProp (priv->last_node, priv->soap_ns, (const xmlChar *)"actorUri", (const xmlChar *)actor_uri); + if (must_understand) + xmlNewNsProp (priv->last_node, priv->soap_ns, (const xmlChar *)"mustUnderstand", (const xmlChar *)"1"); +} + +/** + * soup_soap_message_end_header_element: + * @msg: the #SoupSoapMessage. + * + * Closes the current SOAP header element. + */ +void +soup_soap_message_end_header_element (SoupSoapMessage *msg) +{ + soup_soap_message_end_element (msg); +} + +/** + * soup_soap_message_write_int: + * @msg: the #SoupSoapMessage. + * @i: the integer value to write. + * + * Writes the stringified value of @i as the current element's content. + */ +void +soup_soap_message_write_int (SoupSoapMessage *msg, glong i) +{ + gchar *str = g_strdup_printf ("%ld", i); + soup_soap_message_write_string (msg, str); + g_free (str); +} + +/** + * soup_soap_message_write_double: + * @msg: the #SoupSoapMessage. + * @d: the double value to write. + * + * Writes the stringified value of @d as the current element's content. + */ +void +soup_soap_message_write_double (SoupSoapMessage *msg, gdouble d) +{ + gchar *str = g_strdup_printf ("%f", d); + soup_soap_message_write_string (msg, str); + g_free (str); +} + +/** + * soup_soap_message_write_base64: + * @msg: the #SoupSoapMessage + * @string: the binary data buffer to encode + * @len: the length of data to encode + * + * Writes the Base-64 encoded value of @string as the current + * element's content. + **/ +void +soup_soap_message_write_base64 (SoupSoapMessage *msg, const gchar *string, gint len) +{ + gchar *str = g_base64_encode ((const guchar *)string, len); + soup_soap_message_write_string (msg, str); + g_free (str); +} + +/** + * soup_soap_message_write_time: + * @msg: the #SoupSoapMessage. + * @timeval: pointer to a time_t to encode + * + * Writes the stringified value of @timeval as the current element's + * content. + **/ +void +soup_soap_message_write_time (SoupSoapMessage *msg, const time_t *timeval) +{ + gchar *str = g_strchomp (ctime (timeval)); + soup_soap_message_write_string (msg, str); +} + +/** + * soup_soap_message_write_string: + * @msg: the #SoupSoapMessage. + * @string: string to write. + * + * Writes the @string as the current element's content. + */ +void +soup_soap_message_write_string (SoupSoapMessage *msg, const gchar *string) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + xmlNodeAddContent (priv->last_node, (const xmlChar *)string); +} + +/** + * soup_soap_message_write_buffer: + * @msg: the #SoupSoapMessage. + * @buffer: the string data buffer to write. + * @len: length of @buffer. + * + * Writes the string buffer pointed to by @buffer as the current + * element's content. + */ +void +soup_soap_message_write_buffer (SoupSoapMessage *msg, const gchar *buffer, gint len) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + xmlNodeAddContentLen (priv->last_node, (const xmlChar *)buffer, len); +} + +/** + * soup_soap_message_set_element_type: + * @msg: the #SoupSoapMessage. + * @xsi_type: the type name for the element. + * + * Sets the current element's XML schema xsi:type attribute, which + * specifies the element's type name. + */ +void +soup_soap_message_set_element_type (SoupSoapMessage *msg, const gchar *xsi_type) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + xmlNewNsProp (priv->last_node, priv->xsi_ns, (const xmlChar *)"type", (const xmlChar *)xsi_type); +} + +/** + * soup_soap_message_set_null: + * @msg: the #SoupSoapMessage. + * + * Sets the current element's XML Schema xsi:null attribute. + */ +void +soup_soap_message_set_null (SoupSoapMessage *msg) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + xmlNewNsProp (priv->last_node, priv->xsi_ns, (const xmlChar *)"null", (const xmlChar *)"1"); +} + +/** + * soup_soap_message_add_attribute: + * @msg: the #SoupSoapMessage. + * @name: name of the attribute + * @value: value of the attribute + * @prefix: the namespace prefix + * @ns_uri: the namespace URI + * + * Adds an XML attribute to the current element. + */ +void +soup_soap_message_add_attribute (SoupSoapMessage *msg, + const gchar *name, + const gchar *value, + const gchar *prefix, + const gchar *ns_uri) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + xmlNewNsProp (priv->last_node, + fetch_ns (msg, prefix, ns_uri), + (const xmlChar *)name, (const xmlChar *)value); +} + +/** + * soup_soap_message_add_namespace: + * @msg: the #SoupSoapMessage. + * @prefix: the namespace prefix + * @ns_uri: the namespace URI, or NULL for empty namespace + * + * Adds a new XML namespace to the current element. + */ +void +soup_soap_message_add_namespace (SoupSoapMessage *msg, const gchar *prefix, const gchar *ns_uri) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + xmlNewNs (priv->last_node, (const xmlChar *)(ns_uri ? ns_uri : ""), (const xmlChar *)prefix); +} + +/** + * soup_soap_message_set_default_namespace: + * @msg: the #SoupSoapMessage. + * @ns_uri: the namespace URI. + * + * Sets the default namespace to the URI specified in @ns_uri. The + * default namespace becomes the namespace all non-explicitly + * namespaced child elements fall into. + */ +void +soup_soap_message_set_default_namespace (SoupSoapMessage *msg, const gchar *ns_uri) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + soup_soap_message_add_namespace (msg, NULL, ns_uri); +} + +/** + * soup_soap_message_set_encoding_style: + * @msg: the #SoupSoapMessage. + * @enc_style: the new encodingStyle value + * + * Sets the encodingStyle attribute on the current element to the + * value of @enc_style. + */ +void +soup_soap_message_set_encoding_style (SoupSoapMessage *msg, const gchar *enc_style) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + xmlNewNsProp (priv->last_node, priv->soap_ns, (const xmlChar *)"encodingStyle", (const xmlChar *)enc_style); +} + +/** + * soup_soap_message_reset: + * @msg: the #SoupSoapMessage. + * + * Resets the internal XML representation of the SOAP message. + */ +void +soup_soap_message_reset (SoupSoapMessage *msg) +{ + SoupSoapMessagePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + xmlFreeDoc (priv->doc); + priv->doc = xmlNewDoc ((const xmlChar *)"1.0"); + priv->last_node = NULL; + + g_free (priv->action); + priv->action = NULL; + priv->body_started = FALSE; + + if (priv->env_uri) + xmlFree (priv->env_uri); + priv->env_uri = NULL; + + if (priv->env_prefix) + xmlFree (priv->env_prefix); + priv->env_prefix = NULL; +} + +/** + * soup_soap_message_persist: + * @msg: the #SoupSoapMessage. + * + * Writes the serialized XML tree to the #SoupMessage's buffer. + */ +void +soup_soap_message_persist (SoupSoapMessage *msg) +{ + SoupSoapMessagePrivate *priv; + xmlChar *body; + gint len; + + g_return_if_fail (SOUP_IS_SOAP_MESSAGE (msg)); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + xmlDocDumpMemory (priv->doc, &body, &len); + + /* serialize to SoupMessage class */ + soup_message_set_request (SOUP_MESSAGE (msg), "text/xml", + SOUP_MEMORY_TAKE, (gchar *)body, len); +} + +/** + * soup_soap_message_get_namespace_prefix: + * @msg: the #SoupSoapMessage. + * @ns_uri: the namespace URI. + * + * Returns the namespace prefix for @ns_uri (or an empty string if + * @ns_uri is set to the default namespace) + * + * Returns: The namespace prefix, or %NULL if no namespace exists + * for the URI given. + */ +const gchar * +soup_soap_message_get_namespace_prefix (SoupSoapMessage *msg, const gchar *ns_uri) +{ + SoupSoapMessagePrivate *priv; + xmlNsPtr ns = NULL; + + g_return_val_if_fail (SOUP_IS_SOAP_MESSAGE (msg), NULL); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + g_return_val_if_fail (ns_uri != NULL, NULL); + + ns = xmlSearchNsByHref (priv->doc, priv->last_node, (const xmlChar *)ns_uri); + if (ns) { + if (ns->prefix) + return (const gchar *)ns->prefix; + else + return ""; + } + + return NULL; +} + +/** + * soup_soap_message_get_xml_doc: + * @msg: the #SoupSoapMessage. + * + * Returns the internal XML representation tree of the + * #SoupSoapMessage pointed to by @msg. + * + * Returns: the #xmlDocPtr representing the SOAP message. + */ +xmlDocPtr +soup_soap_message_get_xml_doc (SoupSoapMessage *msg) +{ + SoupSoapMessagePrivate *priv; + + g_return_val_if_fail (SOUP_IS_SOAP_MESSAGE (msg), NULL); + priv = SOUP_SOAP_MESSAGE_GET_PRIVATE (msg); + + return priv->doc; +} + +/** + * soup_soap_message_parse_response: + * @msg: the #SoupSoapMessage. + * + * Parses the response returned by the server. + * + * Returns: a #SoupSoapResponse representing the response from + * the server, or %NULL if there was an error. + */ +SoupSoapResponse * +soup_soap_message_parse_response (SoupSoapMessage *msg) +{ + g_return_val_if_fail (SOUP_IS_SOAP_MESSAGE (msg), NULL); + + return soup_soap_response_new_from_string (SOUP_MESSAGE (msg)->response_body->data); +} diff --git a/soup-soap-message.h b/soup-soap-message.h new file mode 100644 index 0000000..30caf29 --- /dev/null +++ b/soup-soap-message.h @@ -0,0 +1,96 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#ifndef SOUP_SOAP_MESSAGE_H +#define SOUP_SOAP_MESSAGE_H 1 + +#include +#include +#include +#include "soup-soap-response.h" + +G_BEGIN_DECLS + +#define SOUP_TYPE_SOAP_MESSAGE (soup_soap_message_get_type ()) +#define SOUP_SOAP_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_SOAP_MESSAGE, SoupSoapMessage)) +#define SOUP_SOAP_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_SOAP_MESSAGE, SoupSoapMessageClass)) +#define SOUP_IS_SOAP_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUP_TYPE_SOAP_MESSAGE)) +#define SOUP_IS_SOAP_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SOUP_TYPE_SOAP_MESSAGE)) +#define SOUP_SOAP_MESSAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_SOAP_MESSAGE, SoupSoapMessageClass)) + +typedef struct { + SoupMessage parent; + +} SoupSoapMessage; + +typedef struct { + SoupMessageClass parent_class; +} SoupSoapMessageClass; + +GType soup_soap_message_get_type (void); + +SoupSoapMessage *soup_soap_message_new (const gchar *method, const gchar *uri_string, + gboolean standalone, const gchar *xml_encoding, + const gchar *env_prefix, const gchar *env_uri); +SoupSoapMessage *soup_soap_message_new_from_uri (const gchar *method, SoupURI *uri, + gboolean standalone, const gchar *xml_encoding, + const gchar *env_prefix, const gchar *env_uri); + +void soup_soap_message_start_envelope (SoupSoapMessage *msg); +void soup_soap_message_end_envelope (SoupSoapMessage *msg); +void soup_soap_message_start_body (SoupSoapMessage *msg); +void soup_soap_message_end_body (SoupSoapMessage *msg); +void soup_soap_message_start_element (SoupSoapMessage *msg, + const gchar *name, + const gchar *prefix, + const gchar *ns_uri); +void soup_soap_message_end_element (SoupSoapMessage *msg); +void soup_soap_message_start_fault (SoupSoapMessage *msg, + const gchar *faultcode, + const gchar *faultstring, + const gchar *faultfactor); +void soup_soap_message_end_fault (SoupSoapMessage *msg); +void soup_soap_message_start_fault_detail (SoupSoapMessage *msg); +void soup_soap_message_end_fault_detail (SoupSoapMessage *msg); +void soup_soap_message_start_header (SoupSoapMessage *msg); +void soup_soap_message_end_header (SoupSoapMessage *msg); +void soup_soap_message_start_header_element (SoupSoapMessage *msg, + const gchar *name, + gboolean must_understand, + const gchar *actor_uri, + const gchar *prefix, + const gchar *ns_uri); +void soup_soap_message_end_header_element (SoupSoapMessage *msg); +void soup_soap_message_write_int (SoupSoapMessage *msg, glong i); +void soup_soap_message_write_double (SoupSoapMessage *msg, gdouble d); +void soup_soap_message_write_base64 (SoupSoapMessage *msg, const gchar *string, gint len); +void soup_soap_message_write_time (SoupSoapMessage *msg, const time_t *timeval); +void soup_soap_message_write_string (SoupSoapMessage *msg, const gchar *string); +void soup_soap_message_write_buffer (SoupSoapMessage *msg, const gchar *buffer, gint len); +void soup_soap_message_set_element_type (SoupSoapMessage *msg, const gchar *xsi_type); +void soup_soap_message_set_null (SoupSoapMessage *msg); +void soup_soap_message_add_attribute (SoupSoapMessage *msg, + const gchar *name, + const gchar *value, + const gchar *prefix, + const gchar *ns_uri); +void soup_soap_message_add_namespace (SoupSoapMessage *msg, + const gchar *prefix, + const gchar *ns_uri); +void soup_soap_message_set_default_namespace (SoupSoapMessage *msg, + const gchar *ns_uri); +void soup_soap_message_set_encoding_style (SoupSoapMessage *msg, const gchar *enc_style); +void soup_soap_message_reset (SoupSoapMessage *msg); +void soup_soap_message_persist (SoupSoapMessage *msg); + +const gchar *soup_soap_message_get_namespace_prefix (SoupSoapMessage *msg, const gchar *ns_uri); + +xmlDocPtr soup_soap_message_get_xml_doc (SoupSoapMessage *msg); + +SoupSoapResponse *soup_soap_message_parse_response (SoupSoapMessage *msg); + +G_END_DECLS + +#endif diff --git a/soup-soap-response.c b/soup-soap-response.c new file mode 100644 index 0000000..9c0f048 --- /dev/null +++ b/soup-soap-response.c @@ -0,0 +1,578 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#include +#include +#include +#include +#include "soup-soap-response.h" + +G_DEFINE_TYPE (SoupSoapResponse, soup_soap_response, G_TYPE_OBJECT) + +typedef struct { + /* the XML document */ + xmlDocPtr xmldoc; + xmlNodePtr xml_root; + xmlNodePtr xml_body; + xmlNodePtr xml_method; + xmlNodePtr soap_fault; + GList *parameters; +} SoupSoapResponsePrivate; +#define SOUP_SOAP_RESPONSE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SOAP_RESPONSE, SoupSoapResponsePrivate)) + +static xmlNode *soup_xml_real_node (xmlNode *node); + +static void +finalize (GObject *object) +{ + SoupSoapResponsePrivate *priv = SOUP_SOAP_RESPONSE_GET_PRIVATE (object); + + if (priv->xmldoc) + xmlFreeDoc (priv->xmldoc); + if (priv->parameters != NULL) + g_list_free (priv->parameters); + + G_OBJECT_CLASS (soup_soap_response_parent_class)->finalize (object); +} + +static void +soup_soap_response_class_init (SoupSoapResponseClass *soup_soap_response_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (soup_soap_response_class); + + g_type_class_add_private (soup_soap_response_class, sizeof (SoupSoapResponsePrivate)); + + object_class->finalize = finalize; +} + +static void +soup_soap_response_init (SoupSoapResponse *response) +{ + SoupSoapResponsePrivate *priv = SOUP_SOAP_RESPONSE_GET_PRIVATE (response); + + priv->xmldoc = xmlNewDoc ((const xmlChar *)"1.0"); +} + +/** + * soup_soap_response_new: + * + * Create a new empty #SoupSoapResponse object, which can be modified + * with the accessor functions provided with this class. + * + * Returns: the new #SoupSoapResponse (or %NULL if there was an + * error). + */ +SoupSoapResponse * +soup_soap_response_new (void) +{ + SoupSoapResponse *response; + + response = g_object_new (SOUP_TYPE_SOAP_RESPONSE, NULL); + return response; +} + +/** + * soup_soap_response_new_from_string: + * @xmlstr: the XML string to parse. + * + * Create a new #SoupSoapResponse object from the XML string contained + * in @xmlstr. + * + * Returns: the new #SoupSoapResponse (or %NULL if there was an + * error). + */ +SoupSoapResponse * +soup_soap_response_new_from_string (const gchar *xmlstr) +{ + SoupSoapResponse *response; + + g_return_val_if_fail (xmlstr != NULL, NULL); + + response = g_object_new (SOUP_TYPE_SOAP_RESPONSE, NULL); + if (!soup_soap_response_from_string (response, xmlstr)) { + g_object_unref (response); + return NULL; + } + + return response; +} + +static void +parse_parameters (SoupSoapResponsePrivate *priv, xmlNodePtr xml_method) +{ + xmlNodePtr tmp; + + for (tmp = soup_xml_real_node (xml_method->children); + tmp != NULL; + tmp = soup_xml_real_node (tmp->next)) { + if (!strcmp ((const gchar *)tmp->name, "Fault")) { + priv->soap_fault = tmp; + continue; + } else { + /* regular parameters */ + priv->parameters = g_list_append (priv->parameters, tmp); + } + } +} + +/** + * soup_soap_response_from_string: + * @response: the #SoupSoapResponse object. + * @xmlstr: XML string to parse. + * + * Parses the string contained in @xmlstr and sets all properties from + * it in the @response object. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +soup_soap_response_from_string (SoupSoapResponse *response, const gchar *xmlstr) +{ + SoupSoapResponsePrivate *priv; + xmlDocPtr old_doc = NULL; + xmlNodePtr xml_root, xml_body, xml_method = NULL; + + g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), FALSE); + priv = SOUP_SOAP_RESPONSE_GET_PRIVATE (response); + g_return_val_if_fail (xmlstr != NULL, FALSE); + + /* clear the previous contents */ + if (priv->xmldoc) + old_doc = priv->xmldoc; + + /* parse the string */ + priv->xmldoc = xmlParseMemory (xmlstr, strlen (xmlstr)); + if (!priv->xmldoc) { + priv->xmldoc = old_doc; + return FALSE; + } + + xml_root = xmlDocGetRootElement (priv->xmldoc); + if (!xml_root) { + xmlFreeDoc (priv->xmldoc); + priv->xmldoc = old_doc; + return FALSE; + } + + if (strcmp ((const gchar *)xml_root->name, "Envelope") != 0) { + xmlFreeDoc (priv->xmldoc); + priv->xmldoc = old_doc; + return FALSE; + } + + xml_body = soup_xml_real_node (xml_root->children); + if (xml_body != NULL) { + if (strcmp ((const gchar *)xml_body->name, "Header") == 0) + xml_body = soup_xml_real_node (xml_body->next); + if (strcmp ((const gchar *)xml_body->name, "Body") != 0) { + xmlFreeDoc (priv->xmldoc); + priv->xmldoc = old_doc; + return FALSE; + } + + xml_method = soup_xml_real_node (xml_body->children); + + /* read all parameters */ + if (xml_method) + parse_parameters (priv, xml_method); + } + + xmlFreeDoc (old_doc); + + priv->xml_root = xml_root; + priv->xml_body = xml_body; + priv->xml_method = xml_method; + + return TRUE; +} + +/** + * soup_soap_response_get_method_name: + * @response: the #SoupSoapResponse object. + * + * Gets the method name from the SOAP response. + * + * Returns: the method name. + */ +const gchar * +soup_soap_response_get_method_name (SoupSoapResponse *response) +{ + SoupSoapResponsePrivate *priv; + + g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), NULL); + priv = SOUP_SOAP_RESPONSE_GET_PRIVATE (response); + g_return_val_if_fail (priv->xml_method != NULL, NULL); + + return (const gchar *) priv->xml_method->name; +} + +/** + * soup_soap_response_set_method_name: + * @response: the #SoupSoapResponse object. + * @method_name: the method name to set. + * + * Sets the method name on the given #SoupSoapResponse. + */ +void +soup_soap_response_set_method_name (SoupSoapResponse *response, const gchar *method_name) +{ + SoupSoapResponsePrivate *priv; + + g_return_if_fail (SOUP_IS_SOAP_RESPONSE (response)); + priv = SOUP_SOAP_RESPONSE_GET_PRIVATE (response); + g_return_if_fail (priv->xml_method != NULL); + g_return_if_fail (method_name != NULL); + + xmlNodeSetName (priv->xml_method, (const xmlChar *)method_name); +} + +/** + * soup_soap_parameter_get_name: + * @param: the parameter + * + * Returns the parameter name. + * + * Returns: the parameter name. + */ +const gchar * +soup_soap_parameter_get_name (SoupSoapParameter *param) +{ + g_return_val_if_fail (param != NULL, NULL); + + return (const gchar *) param->name; +} + +/** + * soup_soap_parameter_get_int_value: + * @param: the parameter + * + * Returns the parameter's (integer) value. + * + * Returns: the parameter value as an integer + */ +gint +soup_soap_parameter_get_int_value (SoupSoapParameter *param) +{ + gint i; + xmlChar *s; + g_return_val_if_fail (param != NULL, -1); + + s = xmlNodeGetContent (param); + if (s) { + i = atoi ((gchar *)s); + xmlFree (s); + + return i; + } + + return -1; +} + +/** + * soup_soap_parameter_get_string_value: + * @param: the parameter + * + * Returns the parameter's value. + * + * Returns: the parameter value as a string, which must be freed + * by the caller. + */ +gchar * +soup_soap_parameter_get_string_value (SoupSoapParameter *param) +{ + xmlChar *xml_s; + gchar *s; + g_return_val_if_fail (param != NULL, NULL); + + xml_s = xmlNodeGetContent (param); + s = g_strdup ((gchar *)xml_s); + xmlFree (xml_s); + + return s; +} + +/** + * soup_soap_parameter_get_first_child: + * @param: A #SoupSoapParameter. + * + * Gets the first child of the given #SoupSoapParameter. This is used + * for compound data types, which can contain several parameters + * themselves. + * + * Returns: the first child or %NULL if there are no children. + */ +SoupSoapParameter * +soup_soap_parameter_get_first_child (SoupSoapParameter *param) +{ + g_return_val_if_fail (param != NULL, NULL); + + return soup_xml_real_node (param->children); +} + +/** + * soup_soap_parameter_get_first_child_by_name: + * @param: A #SoupSoapParameter. + * @name: The name of the child parameter to look for. + * + * Gets the first child of the given #SoupSoapParameter whose name is + * @name. + * + * Returns: the first child with the given name or %NULL if there + * are no children. + */ +SoupSoapParameter * +soup_soap_parameter_get_first_child_by_name (SoupSoapParameter *param, const gchar *name) +{ + SoupSoapParameter *tmp; + + g_return_val_if_fail (param != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + + for (tmp = soup_soap_parameter_get_first_child (param); + tmp != NULL; + tmp = soup_soap_parameter_get_next_child (tmp)) { + if (!strcmp (name, (const gchar *)tmp->name)) + return tmp; + } + + return NULL; +} + +/** + * soup_soap_parameter_get_next_child: + * @param: A #SoupSoapParameter. + * + * Gets the next sibling of the given #SoupSoapParameter. This is used + * for compound data types, which can contain several parameters + * themselves. + * + * FIXME: the name of this method is wrong + * + * Returns: the next sibling, or %NULL if there are no more + * siblings. + */ +SoupSoapParameter * +soup_soap_parameter_get_next_child (SoupSoapParameter *param) +{ + g_return_val_if_fail (param != NULL, NULL); + + return soup_xml_real_node (param->next); +} + +/** + * soup_soap_parameter_get_next_child_by_name: + * @param: A #SoupSoapParameter. + * @name: The name of the sibling parameter to look for. + * + * Gets the next sibling of the given #SoupSoapParameter whose name is + * @name. + * + * FIXME: the name of this method is wrong + * + * Returns: the next sibling with the given name, or %NULL + */ +SoupSoapParameter * +soup_soap_parameter_get_next_child_by_name (SoupSoapParameter *param, + const gchar *name) +{ + SoupSoapParameter *tmp; + + g_return_val_if_fail (param != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + + for (tmp = soup_soap_parameter_get_next_child (param); + tmp != NULL; + tmp = soup_soap_parameter_get_next_child (tmp)) { + if (!strcmp (name, (const gchar *)tmp->name)) + return tmp; + } + + return NULL; +} + +/** + * soup_soap_parameter_get_property: + * @param: the parameter + * @prop_name: Name of the property to retrieve. + * + * Returns the named property of @param. + * + * Returns: the property, which must be freed by the caller. + */ +gchar * +soup_soap_parameter_get_property (SoupSoapParameter *param, const gchar *prop_name) +{ + xmlChar *xml_s; + gchar *s; + + g_return_val_if_fail (param != NULL, NULL); + g_return_val_if_fail (prop_name != NULL, NULL); + + xml_s = xmlGetProp (param, (const xmlChar *)prop_name); + s = g_strdup ((gchar *)xml_s); + xmlFree (xml_s); + + return s; +} + +/** + * soup_soap_response_get_parameters: + * @response: the #SoupSoapResponse object. + * + * Returns the list of parameters received in the SOAP response. + * + * Returns: a list of #SoupSoapParameter + */ +const GList * +soup_soap_response_get_parameters (SoupSoapResponse *response) +{ + SoupSoapResponsePrivate *priv; + + g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), NULL); + priv = SOUP_SOAP_RESPONSE_GET_PRIVATE (response); + + return (const GList *) priv->parameters; +} + +/** + * soup_soap_response_get_first_parameter: + * @response: the #SoupSoapResponse object. + * + * Retrieves the first parameter contained in the SOAP response. + * + * Returns: a #SoupSoapParameter representing the first + * parameter, or %NULL if there are no parameters. + */ +SoupSoapParameter * +soup_soap_response_get_first_parameter (SoupSoapResponse *response) +{ + SoupSoapResponsePrivate *priv; + + g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), NULL); + priv = SOUP_SOAP_RESPONSE_GET_PRIVATE (response); + + return priv->parameters ? priv->parameters->data : NULL; +} + +/** + * soup_soap_response_get_first_parameter_by_name: + * @response: the #SoupSoapResponse object. + * @name: the name of the parameter to look for. + * + * Retrieves the first parameter contained in the SOAP response whose + * name is @name. + * + * Returns: a #SoupSoapParameter representing the first parameter + * with the given name, or %NULL. + */ +SoupSoapParameter * +soup_soap_response_get_first_parameter_by_name (SoupSoapResponse *response, + const gchar *name) +{ + SoupSoapResponsePrivate *priv; + GList *l; + + g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), NULL); + priv = SOUP_SOAP_RESPONSE_GET_PRIVATE (response); + g_return_val_if_fail (name != NULL, NULL); + + for (l = priv->parameters; l != NULL; l = l->next) { + SoupSoapParameter *param = (SoupSoapParameter *) l->data; + + if (!strcmp (name, (const gchar *)param->name)) + return param; + } + + return NULL; +} + +/** + * soup_soap_response_get_next_parameter: + * @response: the #SoupSoapResponse object. + * @from: the parameter to start from. + * + * Retrieves the parameter following @from in the #SoupSoapResponse + * object. + * + * Returns: a #SoupSoapParameter representing the parameter. + */ +SoupSoapParameter * +soup_soap_response_get_next_parameter (SoupSoapResponse *response, + SoupSoapParameter *from) +{ + SoupSoapResponsePrivate *priv; + GList *l; + + g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), NULL); + priv = SOUP_SOAP_RESPONSE_GET_PRIVATE (response); + g_return_val_if_fail (from != NULL, NULL); + + l = g_list_find (priv->parameters, (gconstpointer) from); + if (!l) + return NULL; + + return l->next ? (SoupSoapParameter *) l->next->data : NULL; +} + +/** + * soup_soap_response_get_next_parameter_by_name: + * @response: the #SoupSoapResponse object. + * @from: the parameter to start from. + * @name: the name of the parameter to look for. + * + * Retrieves the first parameter following @from in the + * #SoupSoapResponse object whose name matches @name. + * + * Returns: a #SoupSoapParameter representing the parameter. + */ +SoupSoapParameter * +soup_soap_response_get_next_parameter_by_name (SoupSoapResponse *response, + SoupSoapParameter *from, + const gchar *name) +{ + SoupSoapParameter *param; + + g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), NULL); + g_return_val_if_fail (from != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + + param = soup_soap_response_get_next_parameter (response, from); + while (param) { + const gchar *param_name = soup_soap_parameter_get_name (param); + + if (param_name) { + if (!strcmp (name, param_name)) + return param; + } + + param = soup_soap_response_get_next_parameter (response, param); + } + + return NULL; +} + +static xmlNode * +soup_xml_real_node (xmlNode *node) +{ + while (node && (node->type == XML_COMMENT_NODE || + xmlIsBlankNode (node))) + node = node->next; + return node; +} + +gint +soup_soap_response_dump_response (SoupSoapResponse *response, FILE *buffer) +{ + xmlChar *xmlbuff; + gint buffersize, ret; + + SoupSoapResponsePrivate *priv = SOUP_SOAP_RESPONSE_GET_PRIVATE (response); + xmlDocDumpFormatMemory(priv->xmldoc, &xmlbuff, &buffersize, 1); + + ret = fputs ((gchar *) xmlbuff, buffer); + xmlFree (xmlbuff); + + return ret; +} diff --git a/soup-soap-response.h b/soup-soap-response.h new file mode 100644 index 0000000..8490571 --- /dev/null +++ b/soup-soap-response.h @@ -0,0 +1,68 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#ifndef SOUP_SOAP_RESPONSE_H +#define SOUP_SOAP_RESPONSE_H + +#include +#include + +G_BEGIN_DECLS + +#define SOUP_TYPE_SOAP_RESPONSE (soup_soap_response_get_type ()) +#define SOUP_SOAP_RESPONSE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_SOAP_RESPONSE, SoupSoapResponse)) +#define SOUP_SOAP_RESPONSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_SOAP_RESPONSE, SoupSoapResponseClass)) +#define SOUP_IS_SOAP_RESPONSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUP_TYPE_SOAP_RESPONSE)) +#define SOUP_IS_SOAP_RESPONSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SOUP_TYPE_SOAP_RESPONSE)) +#define SOUP_SOAP_RESPONSE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_SOAP_RESPONSE, SoupSoapResponseClass)) + +typedef struct { + GObject parent; + +} SoupSoapResponse; + +typedef struct { + GObjectClass parent_class; +} SoupSoapResponseClass; + +GType soup_soap_response_get_type (void); + +SoupSoapResponse *soup_soap_response_new (void); +SoupSoapResponse *soup_soap_response_new_from_string (const gchar *xmlstr); + +gboolean soup_soap_response_from_string (SoupSoapResponse *response, const gchar *xmlstr); + +const gchar *soup_soap_response_get_method_name (SoupSoapResponse *response); +void soup_soap_response_set_method_name (SoupSoapResponse *response, + const gchar *method_name); + +typedef xmlNode SoupSoapParameter; + +const gchar *soup_soap_parameter_get_name (SoupSoapParameter *param); +gint soup_soap_parameter_get_int_value (SoupSoapParameter *param); +gchar *soup_soap_parameter_get_string_value (SoupSoapParameter *param); +SoupSoapParameter *soup_soap_parameter_get_first_child (SoupSoapParameter *param); +SoupSoapParameter *soup_soap_parameter_get_first_child_by_name (SoupSoapParameter *param, + const gchar *name); +SoupSoapParameter *soup_soap_parameter_get_next_child (SoupSoapParameter *param); +SoupSoapParameter *soup_soap_parameter_get_next_child_by_name (SoupSoapParameter *param, + const gchar *name); +gchar *soup_soap_parameter_get_property (SoupSoapParameter *param, const gchar *prop_name); + +const GList *soup_soap_response_get_parameters (SoupSoapResponse *response); +SoupSoapParameter *soup_soap_response_get_first_parameter (SoupSoapResponse *response); +SoupSoapParameter *soup_soap_response_get_first_parameter_by_name (SoupSoapResponse *response, + const gchar *name); +SoupSoapParameter *soup_soap_response_get_next_parameter (SoupSoapResponse *response, + SoupSoapParameter *from); +SoupSoapParameter *soup_soap_response_get_next_parameter_by_name (SoupSoapResponse *response, + SoupSoapParameter *from, + const gchar *name); + +gint soup_soap_response_dump_response (SoupSoapResponse *response, FILE *buffer); + +G_END_DECLS + +#endif