]> www.infradead.org Git - users/dwmw2/ews-sync.git/commitdiff
Import soup-soap-message
authorDavid Woodhouse <dwmw2@infradead.org>
Wed, 21 Jul 2010 09:50:27 +0000 (10:50 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Wed, 21 Jul 2010 09:50:27 +0000 (10:50 +0100)
Makefile
soup-soap-message.c [new file with mode: 0644]
soup-soap-message.h [new file with mode: 0644]
soup-soap-response.c [new file with mode: 0644]
soup-soap-response.h [new file with mode: 0644]

index 3b384d3057c3434ac8f937b9d366400b76eaf8cb..087c560d7e71ae9c32dc760f879ad8ceb4ee062a 100644 (file)
--- 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 (file)
index 0000000..2f26bc9
--- /dev/null
@@ -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 <string.h>
+#include <libsoup/soup.h>
+#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 (file)
index 0000000..30caf29
--- /dev/null
@@ -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 <time.h>
+#include <libxml/tree.h>
+#include <libsoup/soup-message.h>
+#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 (file)
index 0000000..9c0f048
--- /dev/null
@@ -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 <stdlib.h>
+#include <string.h>
+#include <libxml/tree.h>
+#include <libsoup/soup.h>
+#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 (file)
index 0000000..8490571
--- /dev/null
@@ -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 <glib-object.h>
+#include <libxml/tree.h>
+
+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