]> git.datanom.net - caldav.git/blobdiff - src/xml.c
First complete version
[caldav.git] / src / xml.c
diff --git a/src/xml.c b/src/xml.c
new file mode 100644 (file)
index 0000000..fe7928b
--- /dev/null
+++ b/src/xml.c
@@ -0,0 +1,242 @@
+/*
+ * xml.c
+ *
+ * Copyright 2017 Michael Rasmussen <mir@datanom.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <string.h>
+#include "xml.h"
+
+static gboolean debug = FALSE;
+
+static xmlDocPtr getdoc(const gchar* xml) {
+       xmlDocPtr doc;
+       doc = xmlParseMemory(xml, strlen(xml));
+
+       if (doc == NULL ) {
+               g_warning("Document not parsed successfully.");
+               return NULL;
+       }
+
+       return doc;
+}
+
+static xmlXPathObjectPtr getnodeset(xmlDocPtr doc, xmlChar *xpath, const gchar* prefix, const gchar* ns_url) {
+
+       xmlXPathContextPtr context;
+       xmlXPathObjectPtr result = NULL;
+
+       context = xmlXPathNewContext(doc);
+       if (context == NULL) {
+               g_warning("Error in xmlXPathNewContext");
+               return NULL;
+       }
+
+       if (prefix && ns_url) {
+               xmlXPathRegisterNs(context, (xmlChar *)prefix, (xmlChar *)ns_url);
+       }
+
+       result = xmlXPathEvalExpression(xpath, context);
+       xmlXPathFreeContext(context);
+       xmlFree(xpath);
+       if (result == NULL) {
+               g_warning("Error in xmlXPathEvalExpression");
+               return NULL;
+       }
+
+       if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
+               xmlXPathFreeObject(result);
+               result = NULL;
+       }
+
+       return result;
+}
+
+xmlNodePtr find_node_by_name(xmlNodePtr rootnode, const xmlChar* nodename, GSList** nodes) {
+       xmlNodePtr node = rootnode;
+
+    if (!node) {
+        return NULL;
+    }
+
+    while (node != NULL) {
+
+        if (!xmlStrcmp(node->name, nodename)) {
+                       if (nodes) {
+                               *nodes = g_slist_append(*nodes, (gpointer) node);
+                       } else {
+                               return node;
+                       }
+        } else if (node->children != NULL) {
+            xmlNodePtr intNode = find_node_by_name(node->children, nodename, nodes);
+            if (intNode != NULL) {
+                               if (nodes) {
+                                       *nodes = g_slist_append(*nodes, (gpointer) node);
+                               } else {
+                                       return intNode;
+                               }
+            }
+        }
+        node = node->next;
+    }
+
+    return NULL;
+}
+
+static GSList* find_all_nodes_by_name(xmlDocPtr doc, const gchar* nodename) {
+       GSList* nodes = NULL;
+
+       find_node_by_name(doc->children, (const xmlChar *) nodename, &nodes);
+
+       return nodes;
+}
+
+void dump_node(FILE* f, xmlDocPtr doc, xmlNodePtr node) {
+       g_return_if_fail(f && doc && node);
+
+       xmlElemDump(f, doc, node);
+       fprintf(f, "\n");
+}
+
+void dump_nodes(gpointer data, gpointer user_data) {
+       g_return_if_fail(data && user_data);
+
+       xmlNodePtr node = (xmlNodePtr) data;
+       xmlDocPtr doc = (xmlDocPtr) user_data;
+
+       dump_node(stderr, doc, node);
+}
+
+void get_props(gpointer data, gpointer user_data) {
+       g_return_if_fail(data && user_data);
+
+       xmlNodePtr node = (xmlNodePtr) data;
+       Calendar* cal = (Calendar *) user_data;
+
+       xmlChar* comp = xmlGetProp(node, (const xmlChar *)"name");
+       if (comp) {
+               Component c = string_to_component((const gchar *) comp);
+               cal->components = g_slist_append(cal->components, GUINT_TO_POINTER(c));
+               xmlFree(comp);
+       }
+}
+
+GSList* find_element(const gchar* element, const gchar* xml, const gchar* prefix, const gchar* ns_url) {
+       GSList* elements = NULL;
+       xmlChar* keyword = NULL;
+
+       g_return_val_if_fail(element && xml, NULL);
+
+       xmlDocPtr doc = getdoc(xml);
+               if (doc) {
+               xmlXPathObjectPtr result = getnodeset(doc, xmlCharStrdup(element), prefix, ns_url);
+
+               if (result) {
+                       xmlNodeSetPtr nodeset = result->nodesetval;
+                       for (int i = 0; i < nodeset->nodeNr; i++) {
+                               keyword = xmlNodeListGetString(doc, nodeset->nodeTab[i]->xmlChildrenNode, 1);
+                               elements = g_slist_append(elements, (gpointer) g_strdup((gchar *) keyword));
+                               xmlFree(keyword);
+                       }
+                       xmlXPathFreeObject(result);
+               }
+
+               xmlFreeDoc(doc);
+       }
+       xmlCleanupParser();
+
+       return elements;
+}
+
+GSList* find_node(const gchar* node, const gchar* xml) {
+       GSList* nodes = NULL;
+       xmlDocPtr doc = getdoc(xml);
+
+       if (doc) {
+               GSList* n = find_all_nodes_by_name(doc, node);
+
+               for (GSList* l = n; l; l = g_slist_next(l)) {
+                       xmlNodePtr p = (xmlNodePtr) l->data;
+                       nodes = g_slist_append(nodes, g_strdup((gchar *) p->name));
+               }
+
+               g_slist_free(n);
+               xmlFreeDoc(doc);
+       }
+       xmlCleanupParser();
+
+       return nodes;
+}
+
+GSList* find_calendars(const gchar* host_part, const gchar* xml) {
+       GSList* list = NULL;
+       xmlNodePtr ptr;
+       xmlNodePtr found;
+       xmlDocPtr doc = getdoc(xml);
+
+       if (doc) {
+               GSList* n = find_all_nodes_by_name(doc, "response");
+               for (GSList* l = n; l; l = g_slist_next(l)) {
+                       xmlNodePtr p = (xmlNodePtr) l->data;
+                       if (debug)
+                               dump_node(stderr, doc, p);
+                       found = find_node_by_name(p, (const xmlChar*)"resourcetype", NULL);
+                       if (found) {
+                               found = find_node_by_name(found, (const xmlChar*)"calendar", NULL);
+                               if (found) {
+                                       if (debug)
+                                               dump_node(stderr, doc, p);
+                                       Calendar* cal = g_new0(Calendar, 1);
+                                       ptr = find_node_by_name(p, (const xmlChar*)"href", NULL);
+                                       if (ptr)
+                                               cal->url = g_strconcat(host_part, ptr->children->content, NULL);
+                                       ptr = find_node_by_name(p, (const xmlChar*)"displayname", NULL);
+                                       if (ptr)
+                                               cal->displayname = g_strdup((gchar *)ptr->children->content);
+                                       ptr = find_node_by_name(p, (const xmlChar*)"getctag", NULL);
+                                       if (ptr)
+                                               cal->ctag = g_strdup((gchar *)ptr->children->content);
+                                       ptr = find_node_by_name(p, (const xmlChar*)"supported-calendar-component-set", NULL);
+                                       if (ptr) {
+                                               GSList* comps = NULL;
+                                               find_node_by_name(ptr, (const xmlChar *)"comp", &comps);
+                                               g_slist_foreach(comps, (GFunc)get_props, (gpointer) cal);
+                                               g_slist_free(comps);
+                                       }
+                                       list = g_slist_append(list, (gpointer) cal);
+                                       if (debug)
+                                               calendar_dump(stderr, cal);
+                               }
+                       }
+               }
+               g_slist_free(n);
+       }
+
+       return list;
+}
+
+void set_debug_mode(gboolean mode) {
+       debug = mode;
+}
This page took 0.036647 seconds and 5 git commands to generate.