X-Git-Url: http://git.datanom.net/caldav.git/blobdiff_plain/7f587903cb1680dc6d9a70603a9db396dc645627..e1b22e2b5b944589477889b759029f8fe104a731:/src/xml.c diff --git a/src/xml.c b/src/xml.c new file mode 100644 index 0000000..fe7928b --- /dev/null +++ b/src/xml.c @@ -0,0 +1,242 @@ +/* + * xml.c + * + * Copyright 2017 Michael Rasmussen + * + * 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 +#include +#include +#include +#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; +}