/* gcc `pkg-config --cflags --libs glib-2.0 gio-2.0 libxml-2.0` test.c -g -o test && ./test */

#include <glib.h>
#include <stdio.h>
#include <string.h>

#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>

#define XC(string) ((xmlChar *) string)

#define NS_WEBDAV  "DAV:"
#define NS_CALDAV  "urn:ietf:params:xml:ns:caldav"

static gchar *
caldav_chooser_get_xpath_string (xmlXPathContextPtr xp_ctx,
                                 const gchar *path_format,
                                 ...)
{
	xmlXPathObjectPtr xp_obj;
	va_list va;
	gchar *path;
	gchar *expression;
	gchar *string = NULL;

	va_start (va, path_format);
	path = g_strdup_vprintf (path_format, va);
	va_end (va);

	expression = g_strdup_printf ("string(%s)", path);
	xp_obj = xmlXPathEvalExpression (XC (expression), xp_ctx);
	g_free (expression);

	g_free (path);

	if (xp_obj == NULL)
		return NULL;

	if (xp_obj->type == XPATH_STRING)
		string = g_strdup ((gchar *) xp_obj->stringval);

	/* If the string is empty, return NULL. */
	if (string != NULL && *string == '\0') {
		g_free (string);
		string = NULL;
	}

	xmlXPathFreeObject (xp_obj);

	return string;
}

static gchar *
test_xml (const gchar *xml_str)
{
	xmlDocPtr doc;
	xmlXPathContextPtr xp_ctx;
	xmlXPathObjectPtr xp_obj;
	gchar *calendar_home_set;
	
	doc = xmlReadMemory (
		xml_str,
		strlen(xml_str),
		"response.xml", NULL,
		XML_PARSE_NONET |
		XML_PARSE_NOBLANKS |
		XML_PARSE_NSCLEAN |
		XML_PARSE_NOCDATA |
		XML_PARSE_COMPACT);

	xp_ctx = xmlXPathNewContext (doc);
	xmlXPathRegisterNs (xp_ctx, XC ("D"), XC (NS_WEBDAV));
	xmlXPathRegisterNs (xp_ctx, XC ("C"), XC (NS_CALDAV));

	calendar_home_set = caldav_chooser_get_xpath_string (
		xp_ctx,
		"/D:multistatus"
		"/D:response"
		"/D:propstat"
		"/D:prop"
		"/C:calendar-home-set"
		"/D:href");

	xmlXPathFreeContext (xp_ctx);
	xmlFreeDoc (doc);

	return calendar_home_set;
}

int
main (int argc, char **argv)
{
	static const gchar *bad =
		"<?xml version='1.0' encoding='UTF-8'?>\n"
		"<multistatus xmlns='DAV:'>\n"
		"  <response>\n"
		"    <href>/xxx/principal/</href>\n"
		"    <propstat>\n"
		"      <prop>\n"
		"	<calendar-home-set xmlns='urn:ietf:params:xml:ns:caldav'>\n"
		"	  <href xmlns='DAV:'>https://server.com/xxx/calendars/</href>\n"
		"	</calendar-home-set>\n"
		"	<calendar-user-address-set xmlns='urn:ietf:params:xml:ns:caldav'>\n"
		"	  <href xmlns='DAV:'>/xxx/principal/</href>\n"
		"	</calendar-user-address-set>\n"
		"      </prop>\n"
		"      <status>HTTP/1.1 200 OK</status>\n"
		"    </propstat>\n"
		"  </response>\n"
		"</multistatus>\n";

	static const gchar *good =
		"<?xml version='1.0' encoding='UTF-8'?>\n"
		"<D:multistatus xmlns:D='DAV:' xmlns:C='urn:ietf:params:xml:ns:caldav'>\n"
		"  <D:response>\n"
		"    <D:href>/xxx/principal/</D:href>\n"
		"    <D:propstat>\n"
		"      <D:prop>\n"
		"        <C:calendar-home-set>\n"
		"          <D:href>https://server.com/xxx/calendars/</D:href>\n"
		"        </C:calendar-home-set>\n"
		"        <C:calendar-user-address-set>\n"
		"          <D:href>/xxx/principal/</D:href>\n"
		"        </C:calendar-user-address-set>\n"
		"      </D:prop>\n"
		"      <D:status>HTTP/1.1 200 OK</D:status>\n"
		"    </D:propstat>\n"
		"  </D:response>\n"
		"</D:multistatus>\n";
	gchar *calendar_home_set;

	g_type_init ();

	calendar_home_set = test_xml(bad);
	printf ("Bad XML result:'%s'\n", calendar_home_set ? calendar_home_set : "[null]");
	g_free (calendar_home_set);
	calendar_home_set = test_xml(good);
	printf ("Good XML result:'%s'\n", calendar_home_set ? calendar_home_set : "[null]");
	g_free (calendar_home_set);

	return 0;
}
