/* * 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; }