1 /*
2  * Copyright (C) 2005 iptelorg GmbH
3  *
4  * This file is part of ser, a free SIP server.
5  *
6  * ser 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  * For a license to use the ser software under conditions
12  * other than those described here, or to purchase support for this
13  * software, please contact iptel.org by e-mail at the following addresses:
14  *    info@iptel.org
15  *
16  * ser is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
24  */
25 
26 #include <stdio.h>
27 #include <string.h>
28 #include <time.h>
29 
30 #include <xcap/resource_lists_parser.h>
31 #include <xcap/xml_utils.h>
32 #include <cds/logger.h>
33 
34 #include <libxml/parser.h>
35 #include <libxml/tree.h>
36 #include <cds/sstr.h>
37 
38 static char rl_namespace[] = "urn:ietf:params:xml:ns:resource-lists";
39 
read_entry_ref(xmlNode * entry_node,entry_ref_t ** dst)40 static int read_entry_ref(xmlNode *entry_node, entry_ref_t **dst)
41 {
42 	xmlAttr *a;
43 	const char *a_val;
44 
45 	/* allocate memory and prepare empty node */
46 	if (!dst) return -1;
47 	*dst = (entry_ref_t*)cds_malloc(sizeof(entry_ref_t));
48 	if (!(*dst)) return -2;
49 	memset(*dst, 0, sizeof(entry_ref_t));
50 
51 	/* get attributes */
52 	a = find_attr(entry_node->properties, "ref");
53 	if (a) {
54 		a_val = get_attr_value(a);
55 		if (a_val) (*dst)->ref = zt_strdup(a_val);
56 	}
57 	return 0;
58 }
59 
read_name(xmlNode * name_node,display_name_t ** dst)60 static int read_name(xmlNode *name_node, display_name_t **dst)
61 {
62 	xmlAttr *a;
63 	const char *a_val;
64 
65 	/* allocate memory and prepare empty node */
66 	if (!dst) return -1;
67 	*dst = (display_name_t*)cds_malloc(sizeof(display_name_t));
68 	if (!(*dst)) return -2;
69 	memset(*dst, 0, sizeof(display_name_t));
70 
71 	/* get attributes */
72 	a = find_attr(name_node->properties, "lang");
73 	if (a) {
74 		a_val = get_attr_value(a);
75 		if (a_val) (*dst)->lang = zt_strdup(a_val);
76 	}
77 
78 	a_val = get_node_value(name_node);
79 	if (a_val) (*dst)->name = zt_strdup(a_val);
80 
81 	return 0;
82 }
83 
read_names(xmlNode * entry_node,display_name_t ** dst)84 static int read_names(xmlNode *entry_node, display_name_t **dst)
85 {
86 	xmlNode *n;
87 	display_name_t *name, *last;
88 	int res = 0;
89 
90 	last = NULL;
91 	*dst = NULL;
92 	n = entry_node->children;
93 	while (n) {
94 		if (n->type == XML_ELEMENT_NODE) {
95 			if (cmp_node(n, "display-name", rl_namespace) >= 0) {
96 				res = read_name(n, &name);
97 				if (res == 0) {
98 					if (name) {
99 						SEQUENCE_ADD((*dst), last, name);
100 						name = NULL;
101 					}
102 				}
103 				else break;
104 			}
105 		}
106 		n = n->next;
107 	}
108 	return res;
109 }
110 
read_entry(xmlNode * entry_node,entry_t ** dst)111 static int read_entry(xmlNode *entry_node, entry_t **dst)
112 {
113 	xmlAttr *a;
114 	const char *a_val;
115 
116 	/* allocate memory and prepare empty node */
117 	if (!dst) return -1;
118 	*dst = (entry_t*)cds_malloc(sizeof(entry_t));
119 	if (!(*dst)) return -2;
120 	memset(*dst, 0, sizeof(entry_t));
121 
122 	/* get attributes */
123 	a = find_attr(entry_node->properties, "uri");
124 	if (a) {
125 		a_val = get_attr_value(a);
126 		if (a_val) (*dst)->uri = zt_strdup(a_val);
127 	}
128 
129 	return read_names(entry_node, &((*dst)->display_names));
130 }
131 
read_external(xmlNode * entry_node,external_t ** dst)132 static int read_external(xmlNode *entry_node, external_t **dst)
133 {
134 	xmlAttr *a;
135 	const char *a_val;
136 
137 	/* allocate memory and prepare empty node */
138 	if (!dst) return -1;
139 	*dst = (external_t*)cds_malloc(sizeof(external_t));
140 	if (!(*dst)) return -2;
141 	memset(*dst, 0, sizeof(external_t));
142 
143 	/* get attributes */
144 	a = find_attr(entry_node->properties, "anchor");
145 	if (a) {
146 		a_val = get_attr_value(a);
147 		if (a_val) (*dst)->anchor = zt_strdup(a_val);
148 	}
149 	return 0;
150 }
151 
read_list(xmlNode * list_node,list_t ** dst,int read_content_only)152 int read_list(xmlNode *list_node, list_t **dst, int read_content_only)
153 {
154 	int res = 0;
155 	xmlAttr *a;
156 	const char *a_val;
157 	xmlNode *n;
158 	list_content_t *l, *last_l;
159 
160 	/* allocate memory and prepare empty node */
161 	if (!dst) return -1;
162 	*dst = (list_t*)cds_malloc(sizeof(list_t));
163 	if (!(*dst)) return -2;
164 	memset(*dst, 0, sizeof(list_t));
165 
166 	/* get attributes */
167 	if (!read_content_only) {
168 		a = find_attr(list_node->properties, "name");
169 		if (a) {
170 			a_val = get_attr_value(a);
171 			if (a_val) (*dst)->name = zt_strdup(a_val);
172 		}
173 	}
174 
175 	/* read entries */
176 	last_l = NULL;
177 	n = list_node->children;
178 	while (n) {
179 		if (n->type == XML_ELEMENT_NODE) {
180 			l = (list_content_t*) cds_malloc(sizeof(list_content_t));
181 			if (!l) return -1;
182 			memset(l, 0, sizeof(*l));
183 
184 			if (cmp_node(n, "list", rl_namespace) >= 0) {
185 				res = read_list(n, &l->u.list, 0);
186 				if (res == 0) {
187 					if (l->u.list) {
188 						l->type = lct_list;
189 						SEQUENCE_ADD((*dst)->content, last_l, l);
190 						l = NULL;
191 					}
192 				}
193 				else break;
194 			}
195 
196 			if (cmp_node(n, "entry", rl_namespace) >= 0) {
197 				res = read_entry(n, &l->u.entry);
198 				if (res == 0) {
199 					if (l->u.entry) {
200 						l->type = lct_entry;
201 						SEQUENCE_ADD((*dst)->content, last_l, l);
202 						l = NULL;
203 					}
204 				}
205 				else break;
206 			}
207 
208 			if (cmp_node(n, "entry-ref", rl_namespace) >= 0) {
209 				res = read_entry_ref(n, &l->u.entry_ref);
210 				if (res == 0) {
211 					if (l->u.entry_ref) {
212 						l->type = lct_entry_ref;
213 						SEQUENCE_ADD((*dst)->content, last_l, l);
214 						l = NULL;
215 					}
216 				}
217 				else break;
218 			}
219 
220 			if (cmp_node(n, "external", rl_namespace) >= 0) {
221 				res = read_external(n, &l->u.external);
222 				if (res == 0) {
223 					if (l->u.external) {
224 						l->type = lct_external;
225 						SEQUENCE_ADD((*dst)->content, last_l, l);
226 						l = NULL;
227 					}
228 				}
229 				else break;
230 			}
231 
232 			if (l) {
233 				cds_free(l);
234 				l = NULL;
235 			}
236 
237 		}
238 		n = n->next;
239 	}
240 
241 	return 0;
242 }
243 
read_resource_lists(xmlNode * root,resource_lists_t ** dst)244 static int read_resource_lists(xmlNode *root, resource_lists_t **dst)
245 {
246 	resource_lists_t *rl;
247 	/* xmlAttr *a; */
248 	xmlNode *n;
249 	list_t *l, *last_l;
250 	int res = 0;
251 
252 	if (!dst) return -1;
253 	else *dst = NULL;
254 	if (!root) return -1;
255 
256 	if (cmp_node(root, "resource-lists", rl_namespace) < 0) {
257 		ERROR_LOG("document is not a resource-lists\n");
258 		return -1;
259 	}
260 
261 	rl = (resource_lists_t*)cds_malloc(sizeof(resource_lists_t));
262 	if (!rl) return -2;
263 	*dst = rl;
264 	rl->lists = NULL;
265 
266 	last_l = NULL;
267 	n = root->children;
268 	while (n) {
269 		if (n->type == XML_ELEMENT_NODE) {
270 			if (cmp_node(n, "list", rl_namespace) >= 0) {
271 				res = read_list(n, &l, 0);
272 				if (res == 0) {
273 					if (l) SEQUENCE_ADD(rl->lists, last_l, l);
274 				}
275 				else break;
276 			}
277 		}
278 		n = n->next;
279 	}
280 
281 	return res;
282 }
283 
parse_resource_lists_xml(const char * data,int data_len,resource_lists_t ** dst)284 int parse_resource_lists_xml(const char *data, int data_len, resource_lists_t **dst)
285 {
286 	int res = 0;
287 	xmlDocPtr doc; /* the resulting document tree */
288 
289 	if (dst) *dst = NULL;
290 	doc = xmlReadMemory(data, data_len, NULL, NULL, xml_parser_flags);
291 	if (doc == NULL) {
292 		ERROR_LOG("can't parse document\n");
293 		return -1;
294 	}
295 
296 	res = read_resource_lists(xmlDocGetRootElement(doc), dst);
297 
298 	xmlFreeDoc(doc);
299 	return res;
300 }
301 
parse_list_xml(const char * data,int data_len,list_t ** dst)302 int parse_list_xml(const char *data, int data_len, list_t **dst)
303 {
304 	int res = 0;
305 	xmlDocPtr doc; /* the resulting document tree */
306 
307 	if (dst) *dst = NULL;
308 	doc = xmlReadMemory(data, data_len, NULL, NULL, xml_parser_flags);
309 	if (doc == NULL) {
310 		ERROR_LOG("can't parse document\n");
311 		return -1;
312 	}
313 
314 	res = read_list(xmlDocGetRootElement(doc), dst, 0);
315 
316 	xmlFreeDoc(doc);
317 	return res;
318 }
319 
parse_as_list_content_xml(const char * data,int data_len,list_t ** dst)320 int parse_as_list_content_xml(const char *data, int data_len, list_t **dst)
321 {
322 	int res = 0;
323 	xmlDocPtr doc; /* the resulting document tree */
324 
325 	if (dst) *dst = NULL;
326 	doc = xmlReadMemory(data, data_len, NULL, NULL, xml_parser_flags);
327 	if (doc == NULL) {
328 		ERROR_LOG("can't parse document\n");
329 		return -1;
330 	}
331 
332 	res = read_list(xmlDocGetRootElement(doc), dst, 1);
333 
334 	xmlFreeDoc(doc);
335 	return res;
336 }
337 
parse_entry_xml(const char * data,int data_len,entry_t ** dst)338 int parse_entry_xml(const char *data, int data_len, entry_t **dst)
339 {
340 	int res = 0;
341 	xmlDocPtr doc; /* the resulting document tree */
342 
343 	if (dst) *dst = NULL;
344 	doc = xmlReadMemory(data, data_len, NULL, NULL, xml_parser_flags);
345 	if (doc == NULL) {
346 		ERROR_LOG("can't parse document\n");
347 		return -1;
348 	}
349 
350 	res = read_entry(xmlDocGetRootElement(doc), dst);
351 
352 	xmlFreeDoc(doc);
353 	return res;
354 }
355 
free_display_name(display_name_t * n)356 void free_display_name(display_name_t *n)
357 {
358 	if (!n) return;
359 	if (n->name) cds_free(n->name);
360 	if (n->lang) cds_free(n->lang);
361 	cds_free(n);
362 }
363 
free_display_names(display_name_t * sequence_first)364 void free_display_names(display_name_t *sequence_first)
365 {
366 	display_name_t *d, *n;
367 
368 	if (!sequence_first) return;
369 
370 	d = SEQUENCE_FIRST(sequence_first);
371 	while (d) {
372 		n = SEQUENCE_NEXT(d);
373 		free_display_name(d);
374 		d = n;
375 	}
376 
377 }
378 
free_entry(entry_t * e)379 void free_entry(entry_t *e)
380 {
381 	if (!e) return;
382 
383 	if (e->uri) cds_free(e->uri);
384 	free_display_names(e->display_names);
385 
386 	cds_free(e);
387 }
388 
free_entry_ref(entry_ref_t * e)389 void free_entry_ref(entry_ref_t *e)
390 {
391 	if (!e) return;
392 	if (e->ref) cds_free(e->ref);
393 	cds_free(e);
394 }
395 
free_external(external_t * e)396 void free_external(external_t *e)
397 {
398 	if (!e) return;
399 	if (e->anchor) cds_free(e->anchor);
400 	cds_free(e);
401 }
402 
free_list(list_t * l)403 void free_list(list_t *l)
404 {
405 	list_content_t *e, *f;
406 
407 	if (!l) return;
408 
409 	if (l->name) cds_free(l->name);
410 
411 	e = SEQUENCE_FIRST(l->content);
412 	while (e) {
413 		switch (e->type) {
414 			case lct_list: free_list(e->u.list); break;
415 			case lct_entry: free_entry(e->u.entry); break;
416 			case lct_entry_ref: free_entry_ref(e->u.entry_ref); break;
417 			case lct_external: free_external(e->u.external); break;
418 		}
419 		f = e;
420 		e = SEQUENCE_NEXT(e);
421 		/* TRACE_LOG("freeing %p\n", f); */
422 		cds_free(f);
423 	}
424 	cds_free(l);
425 }
426 
427 
free_resource_lists(resource_lists_t * rl)428 void free_resource_lists(resource_lists_t *rl)
429 {
430 	list_t *e, *f;
431 	if (!rl) return;
432 
433 	e = SEQUENCE_FIRST(rl->lists);
434 	while (e) {
435 		f = SEQUENCE_NEXT(e);
436 		free_list(e);
437 		e = f;
438 	}
439 	cds_free(rl);
440 }
441 
442