all: updated FSF address in GPL text
[sip-router] / lib / xcap / parse_common_rules.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 <xcap/parse_common_rules.h>
27 #include <xcap/xcap_result_codes.h>
28
29 #include <cds/dstring.h>
30 #include <cds/memory.h>
31 #include <cds/logger.h>
32 #include <cds/list.h>
33 #include <string.h>
34
35 #include <xcap/xml_utils.h>
36
37 char *common_policy_ns = NULL;
38
39 static int read_sphere(xmlNode *n, cp_sphere_t **dst)
40 {
41         *dst = (cp_sphere_t*)cds_malloc(sizeof(cp_sphere_t));
42         if (!(*dst)) return RES_MEMORY_ERR;
43         memset(*dst, 0, sizeof(**dst));
44         (*dst)->next = NULL;
45         
46         str_dup_zt(&(*dst)->value, get_node_value(n));
47         return RES_OK;
48 }
49
50 static int read_validity(xmlNode *n, cp_validity_t **dst)
51 {
52         const char *from, *to;
53         *dst = (cp_validity_t*)cds_malloc(sizeof(cp_validity_t));
54         if (!(*dst)) return RES_MEMORY_ERR;
55         memset(*dst, 0, sizeof(**dst));
56         
57         from = get_node_value(find_node(n, "from", common_policy_ns));
58         to = get_node_value(find_node(n, "to", common_policy_ns));
59         
60         (*dst)->from = xmltime2time(from);
61         (*dst)->to = xmltime2time(to);
62         return RES_OK;
63 }
64
65 static int read_id(xmlNode *n, cp_id_t **dst)
66 {
67         *dst = (cp_id_t*)cds_malloc(sizeof(cp_id_t));
68         if (!(*dst)) return RES_MEMORY_ERR;
69         memset(*dst, 0, sizeof(**dst));
70         (*dst)->next = NULL;
71         
72         get_str_attr(n, "entity", &(*dst)->entity);
73         if ((*dst)->entity.len == 0) {
74                 /* hack - eyeBeams format differs from draft ! */
75                 str_dup_zt(&(*dst)->entity, get_node_value(n));
76         }
77
78         return RES_OK;
79 }
80
81 static int read_domain(xmlNode *n, cp_domain_t **dst)
82 {
83         *dst = (cp_domain_t*)cds_malloc(sizeof(cp_domain_t));
84         if (!(*dst)) return RES_MEMORY_ERR;
85         memset(*dst, 0, sizeof(**dst));
86         (*dst)->next = NULL;
87         
88         get_str_attr(n, "domain", &(*dst)->domain);
89         return RES_OK;
90 }
91
92 static int read_except(xmlNode *n, cp_except_t **dst)
93 {
94         *dst = (cp_except_t*)cds_malloc(sizeof(cp_except_t));
95         if (!(*dst)) return RES_MEMORY_ERR;
96         memset(*dst, 0, sizeof(**dst));
97         (*dst)->next = NULL;
98         
99         get_str_attr(n, "entity", &(*dst)->entity);
100         return RES_OK;
101 }
102
103 static int read_except_domain(xmlNode *n, cp_except_domain_t **dst)
104 {
105         *dst = (cp_except_domain_t*)cds_malloc(sizeof(cp_except_domain_t));
106         if (!*dst) return RES_MEMORY_ERR;
107         memset(*dst, 0, sizeof(**dst));
108         (*dst)->next = NULL;
109         
110         get_str_attr(n, "domain", &(*dst)->domain);
111         return RES_OK;
112 }
113
114 static int read_any_identity(xmlNode *an, cp_any_identity_t **dst)
115 {
116         cp_domain_t *domain, *last_domain = NULL;
117         cp_except_domain_t *except, *last_except = NULL;
118         xmlNode *n;
119         int res = RES_OK;
120         
121         *dst = (cp_any_identity_t*)cds_malloc(sizeof(cp_any_identity_t));
122         if (!*dst) return RES_MEMORY_ERR;
123         memset(*dst, 0, sizeof(**dst));
124         
125         n = an->children;
126         while (n) {
127                 if (n->type == XML_ELEMENT_NODE) {
128                         if (cmp_node(n, "domain", common_policy_ns) >= 0) {
129                                 res = read_domain(n, &domain);
130                                 if (res != 0) break;
131                                 LINKED_LIST_ADD((*dst)->domains, last_domain, domain);
132                         }
133                         else if (cmp_node(n, "except-domain", common_policy_ns) >= 0) {
134                                 res = read_except_domain(n, &except);
135                                 if (res != 0) break;
136                                 LINKED_LIST_ADD((*dst)->except_domains, last_except, except);
137                         }
138                 }
139                 
140                 n = n->next;
141         }
142         return res;
143 }
144
145 static int read_identity(xmlNode *idn, cp_identity_t **dst)
146 {
147         cp_id_t *id, *last_id = NULL;
148         cp_domain_t *domain, *last_domain = NULL;
149         cp_except_t *except, *last_except = NULL;
150         xmlNode *n;
151         int res = RES_OK;
152         
153         *dst = (cp_identity_t*)cds_malloc(sizeof(cp_identity_t));
154         if (!*dst) return RES_MEMORY_ERR;
155         memset(*dst, 0, sizeof(**dst));
156
157         n = idn->children;
158         while (n) {
159                 if (n->type == XML_ELEMENT_NODE) {
160                         if (cmp_node(n, "id", common_policy_ns) >= 0) {
161                                 res = read_id(n, &id);
162                                 if (res != 0) break;
163                                 LINKED_LIST_ADD((*dst)->ids, last_id, id);
164                         }
165                         else if (cmp_node(n, "domain", common_policy_ns) >= 0) {
166                                 res = read_domain(n, &domain);
167                                 if (res != 0) break;
168                                 LINKED_LIST_ADD((*dst)->domains, last_domain, domain);
169                         }
170                         else if (cmp_node(n, "except", common_policy_ns) >= 0) {
171                                 res = read_except(n, &except);
172                                 if (res != 0) break;
173                                 LINKED_LIST_ADD((*dst)->excepts, last_except, except);
174                         }
175                         else if (cmp_node(n, "any-identity", common_policy_ns) >= 0) {
176                                 res = read_any_identity(n, &(*dst)->any_identity);
177                                 if (res != 0) break;
178                         }
179                 }
180                 
181                 n = n->next;
182         }
183         
184         return res;
185 }
186
187 static int read_conditions(xmlNode *cn, cp_conditions_t **dst)
188 {
189         xmlNode *n;
190         int res = RES_OK;
191         cp_sphere_t *sphere, * last_sphere = NULL;
192         if ((!cn) || (!dst)) return RES_INTERNAL_ERR;
193         
194         *dst = (cp_conditions_t*)cds_malloc(sizeof(cp_conditions_t));
195         if (!(*dst)) return RES_MEMORY_ERR;
196         memset(*dst, 0, sizeof(cp_conditions_t));
197         
198         n = cn->children;
199         while (n) {
200                 if (n->type == XML_ELEMENT_NODE) {
201                         if (cmp_node(n, "validity", common_policy_ns) >= 0) {
202                                 /* FIXME: free existing validity */
203                                 res = read_validity(n, &(*dst)->validity);
204                                 if (res != 0) break;
205                         }
206                         else {
207                                 if (cmp_node(n, "identity", common_policy_ns) >= 0) {
208                                         /* FIXME: free existing identity */
209                                         res = read_identity(n, &(*dst)->identity);
210                                         if (res != 0) break;
211                                 }
212                                 else {
213                                         if (cmp_node(n, "sphere", common_policy_ns) >= 0) {
214                                                 res = read_sphere(n, &sphere);
215                                                 if (res != 0) break;
216                                                 LINKED_LIST_ADD((*dst)->spheres, last_sphere, sphere);
217                                         }
218                                         /* else process other elements ? */
219                                 }
220                                 
221                         }
222                 }
223                 n = n->next;
224         }
225
226         return res;
227 }
228
229 static int read_transformations(xmlNode *tn, cp_transformations_t **dst)
230 {
231         int res = RES_OK;
232         if ((!tn) || (!dst)) return RES_INTERNAL_ERR;
233         
234         *dst = (cp_transformations_t*)cds_malloc(sizeof(cp_transformations_t));
235         if (!*dst) return RES_MEMORY_ERR;
236         memset(*dst, 0, sizeof(cp_transformations_t));
237
238         DEBUG_LOG("transformations for pres_rules not used\n");
239
240         return res;
241 }
242
243 static int read_rule(xmlNode *rn, cp_rule_t **dst, 
244                 cp_read_actions_func read_actions,
245                 cp_free_actions_func free_actions)
246 {
247         xmlNode *n;
248         int res = RES_OK;
249         if ((!rn) || (!dst)) return RES_INTERNAL_ERR;
250         
251         *dst = (cp_rule_t*)cds_malloc(sizeof(cp_rule_t));
252         if (!*dst) return RES_MEMORY_ERR;
253         memset(*dst, 0, sizeof(cp_rule_t));
254
255         get_str_attr(rn, "id", &(*dst)->id);
256
257         n = find_node(rn, "actions", common_policy_ns);
258         if (n && (res == 0) && read_actions) res = read_actions(n, &(*dst)->actions);
259         
260         n = find_node(rn, "conditions", common_policy_ns);
261         if (n && (res == 0)) res = read_conditions(n, &(*dst)->conditions);
262         
263         n = find_node(rn, "transformations", common_policy_ns);
264         if (n && (res == 0)) res = read_transformations(n, &(*dst)->transformations);
265         
266         if (res != 0) {
267                 free_cp_rule(*dst, free_actions);
268                 *dst = NULL;
269                 return res;
270         }
271
272         return 0;
273 }
274
275 static int read_common_rules(xmlNode *root, cp_ruleset_t **dst, 
276                 cp_read_actions_func read_actions, cp_free_actions_func free_actions)
277 {
278         cp_ruleset_t *rs = NULL;
279         cp_rule_t *r, *last = NULL;
280         xmlNode *n;
281         int res = RES_OK;
282         
283         if (!dst) return RES_INTERNAL_ERR;
284         else *dst = NULL;
285         if (!root) return RES_INTERNAL_ERR;
286         
287         if (cmp_node(root, "ruleset", common_policy_ns) < 0) {
288                 ERROR_LOG("document is not a ruleset \n");
289                 return RES_INTERNAL_ERR;
290         }
291
292         rs = (cp_ruleset_t*)cds_malloc(sizeof(cp_ruleset_t));
293         if (!rs) return RES_MEMORY_ERR;
294         *dst = rs;
295         memset(rs, 0, sizeof(*rs));
296
297         
298         /* read rules in ruleset */
299         n = root->children;
300         while (n) {
301                 if (n->type == XML_ELEMENT_NODE) {
302                         if (cmp_node(n, "rule", common_policy_ns) >= 0) {
303                                 res = read_rule(n, &r, read_actions, free_actions);
304                                 if (res == 0) {
305                                         if (r) LINKED_LIST_ADD(rs->rules, last, r);
306                                 }
307                                 else break;
308                         }
309                 }
310                 n = n->next;
311         }
312
313         return res;
314 }
315
316 int parse_common_rules(const char *data, int dsize, cp_ruleset_t **dst,
317         cp_read_actions_func read_actions, cp_free_actions_func free_actions)
318 {
319         int res = 0;
320         xmlDocPtr doc; /* the resulting document tree */
321
322         if (dst) *dst = NULL;
323         doc = xmlReadMemory(data, dsize, NULL, NULL, xml_parser_flags);
324         if (doc == NULL) {
325                 ERROR_LOG("can't parse document\n");
326                 return RES_INTERNAL_ERR;
327         }
328         
329         res = read_common_rules(xmlDocGetRootElement(doc), dst, 
330                         read_actions, free_actions);
331         if ((res != RES_OK) && (dst)) {
332                 /* may be set => must be freed */
333                 free_common_rules(*dst, free_actions);
334                 *dst = NULL;
335         }
336
337         xmlFreeDoc(doc);
338         return res;
339 }
340