]> git.datanom.net - caldav.git/blob - src/xml.c
First complete version
[caldav.git] / src / xml.c
1 /*
2 * xml.c
3 *
4 * Copyright 2017 Michael Rasmussen <mir@datanom.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #include <libxml/parser.h>
27 #include <libxml/xpath.h>
28 #include <libxml/xpathInternals.h>
29 #include <string.h>
30 #include "xml.h"
31
32 static gboolean debug = FALSE;
33
34 static xmlDocPtr getdoc(const gchar* xml) {
35 xmlDocPtr doc;
36 doc = xmlParseMemory(xml, strlen(xml));
37
38 if (doc == NULL ) {
39 g_warning("Document not parsed successfully.");
40 return NULL;
41 }
42
43 return doc;
44 }
45
46 static xmlXPathObjectPtr getnodeset(xmlDocPtr doc, xmlChar *xpath, const gchar* prefix, const gchar* ns_url) {
47
48 xmlXPathContextPtr context;
49 xmlXPathObjectPtr result = NULL;
50
51 context = xmlXPathNewContext(doc);
52 if (context == NULL) {
53 g_warning("Error in xmlXPathNewContext");
54 return NULL;
55 }
56
57 if (prefix && ns_url) {
58 xmlXPathRegisterNs(context, (xmlChar *)prefix, (xmlChar *)ns_url);
59 }
60
61 result = xmlXPathEvalExpression(xpath, context);
62 xmlXPathFreeContext(context);
63 xmlFree(xpath);
64 if (result == NULL) {
65 g_warning("Error in xmlXPathEvalExpression");
66 return NULL;
67 }
68
69 if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
70 xmlXPathFreeObject(result);
71 result = NULL;
72 }
73
74 return result;
75 }
76
77 xmlNodePtr find_node_by_name(xmlNodePtr rootnode, const xmlChar* nodename, GSList** nodes) {
78 xmlNodePtr node = rootnode;
79
80 if (!node) {
81 return NULL;
82 }
83
84 while (node != NULL) {
85
86 if (!xmlStrcmp(node->name, nodename)) {
87 if (nodes) {
88 *nodes = g_slist_append(*nodes, (gpointer) node);
89 } else {
90 return node;
91 }
92 } else if (node->children != NULL) {
93 xmlNodePtr intNode = find_node_by_name(node->children, nodename, nodes);
94 if (intNode != NULL) {
95 if (nodes) {
96 *nodes = g_slist_append(*nodes, (gpointer) node);
97 } else {
98 return intNode;
99 }
100 }
101 }
102 node = node->next;
103 }
104
105 return NULL;
106 }
107
108 static GSList* find_all_nodes_by_name(xmlDocPtr doc, const gchar* nodename) {
109 GSList* nodes = NULL;
110
111 find_node_by_name(doc->children, (const xmlChar *) nodename, &nodes);
112
113 return nodes;
114 }
115
116 void dump_node(FILE* f, xmlDocPtr doc, xmlNodePtr node) {
117 g_return_if_fail(f && doc && node);
118
119 xmlElemDump(f, doc, node);
120 fprintf(f, "\n");
121 }
122
123 void dump_nodes(gpointer data, gpointer user_data) {
124 g_return_if_fail(data && user_data);
125
126 xmlNodePtr node = (xmlNodePtr) data;
127 xmlDocPtr doc = (xmlDocPtr) user_data;
128
129 dump_node(stderr, doc, node);
130 }
131
132 void get_props(gpointer data, gpointer user_data) {
133 g_return_if_fail(data && user_data);
134
135 xmlNodePtr node = (xmlNodePtr) data;
136 Calendar* cal = (Calendar *) user_data;
137
138 xmlChar* comp = xmlGetProp(node, (const xmlChar *)"name");
139 if (comp) {
140 Component c = string_to_component((const gchar *) comp);
141 cal->components = g_slist_append(cal->components, GUINT_TO_POINTER(c));
142 xmlFree(comp);
143 }
144 }
145
146 GSList* find_element(const gchar* element, const gchar* xml, const gchar* prefix, const gchar* ns_url) {
147 GSList* elements = NULL;
148 xmlChar* keyword = NULL;
149
150 g_return_val_if_fail(element && xml, NULL);
151
152 xmlDocPtr doc = getdoc(xml);
153 if (doc) {
154 xmlXPathObjectPtr result = getnodeset(doc, xmlCharStrdup(element), prefix, ns_url);
155
156 if (result) {
157 xmlNodeSetPtr nodeset = result->nodesetval;
158 for (int i = 0; i < nodeset->nodeNr; i++) {
159 keyword = xmlNodeListGetString(doc, nodeset->nodeTab[i]->xmlChildrenNode, 1);
160 elements = g_slist_append(elements, (gpointer) g_strdup((gchar *) keyword));
161 xmlFree(keyword);
162 }
163 xmlXPathFreeObject(result);
164 }
165
166 xmlFreeDoc(doc);
167 }
168 xmlCleanupParser();
169
170 return elements;
171 }
172
173 GSList* find_node(const gchar* node, const gchar* xml) {
174 GSList* nodes = NULL;
175 xmlDocPtr doc = getdoc(xml);
176
177 if (doc) {
178 GSList* n = find_all_nodes_by_name(doc, node);
179
180 for (GSList* l = n; l; l = g_slist_next(l)) {
181 xmlNodePtr p = (xmlNodePtr) l->data;
182 nodes = g_slist_append(nodes, g_strdup((gchar *) p->name));
183 }
184
185 g_slist_free(n);
186 xmlFreeDoc(doc);
187 }
188 xmlCleanupParser();
189
190 return nodes;
191 }
192
193 GSList* find_calendars(const gchar* host_part, const gchar* xml) {
194 GSList* list = NULL;
195 xmlNodePtr ptr;
196 xmlNodePtr found;
197 xmlDocPtr doc = getdoc(xml);
198
199 if (doc) {
200 GSList* n = find_all_nodes_by_name(doc, "response");
201 for (GSList* l = n; l; l = g_slist_next(l)) {
202 xmlNodePtr p = (xmlNodePtr) l->data;
203 if (debug)
204 dump_node(stderr, doc, p);
205 found = find_node_by_name(p, (const xmlChar*)"resourcetype", NULL);
206 if (found) {
207 found = find_node_by_name(found, (const xmlChar*)"calendar", NULL);
208 if (found) {
209 if (debug)
210 dump_node(stderr, doc, p);
211 Calendar* cal = g_new0(Calendar, 1);
212 ptr = find_node_by_name(p, (const xmlChar*)"href", NULL);
213 if (ptr)
214 cal->url = g_strconcat(host_part, ptr->children->content, NULL);
215 ptr = find_node_by_name(p, (const xmlChar*)"displayname", NULL);
216 if (ptr)
217 cal->displayname = g_strdup((gchar *)ptr->children->content);
218 ptr = find_node_by_name(p, (const xmlChar*)"getctag", NULL);
219 if (ptr)
220 cal->ctag = g_strdup((gchar *)ptr->children->content);
221 ptr = find_node_by_name(p, (const xmlChar*)"supported-calendar-component-set", NULL);
222 if (ptr) {
223 GSList* comps = NULL;
224 find_node_by_name(ptr, (const xmlChar *)"comp", &comps);
225 g_slist_foreach(comps, (GFunc)get_props, (gpointer) cal);
226 g_slist_free(comps);
227 }
228 list = g_slist_append(list, (gpointer) cal);
229 if (debug)
230 calendar_dump(stderr, cal);
231 }
232 }
233 }
234 g_slist_free(n);
235 }
236
237 return list;
238 }
239
240 void set_debug_mode(gboolean mode) {
241 debug = mode;
242 }
This page took 0.084507 seconds and 6 git commands to generate.