]>
Commit | Line | Data |
---|---|---|
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 | } |