msilo: coherent indentation and whitespacing
[sip-router] / src / lib / xcap / resource_lists_parser.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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