e9cb1d13ce7e5c2abefd1ac8b046ed17779bc638
[sip-router] / parser / contact / cparam.c
1 /* 
2  * $Id$
3  *
4  */
5
6 #include "cparam.h"
7 #include "../../mem/mem.h"
8 #include <stdio.h>         /* printf */
9 #include "../../ut.h"      /* q_memchr */
10 #include <string.h>        /* memset */
11 #include "../../trim.h"
12
13
14 /*
15  * Parse quoted string in a parameter body
16  * return the string without quotes in _r
17  * parameter and update _s to point behind the
18  * closing quote
19  */
20 static inline int parse_quoted(str* _s, str* _r)
21 {
22         char* end_quote;
23
24              /* The string must have at least
25               * surrounding quotes
26               */
27         if (_s->len < 2) {
28                 return -1;
29         }
30
31              /* Skip opening quote */
32         _s->s++;
33         _s->len--;
34
35
36              /* Find closing quote */
37         end_quote = q_memchr(_s->s, '\"', _s->len);
38
39              /* Not found, return error */
40         if (!end_quote) {
41                 return -2;
42         }
43
44              /* Let _r point to the string without
45               * surrounding quotes
46               */
47         _r->s = _s->s;
48         _r->len = end_quote - _s->s;
49
50              /* Update _s parameter to point
51               * behind the closing quote
52               */
53         _s->len -= (end_quote - _s->s + 1);
54         _s->s = end_quote + 1;
55
56              /* Everything went OK */
57         return 0;
58 }
59
60
61 /*
62  * Parse unquoted token in a parameter body
63  * let _r point to the token and update _s
64  * to point right behind the token
65  */
66 static inline int parse_token(str* _s, str* _r)
67 {
68         int i;
69
70              /* There is nothing to parse,
71               * return error
72               */
73         if (_s->len == 0) {
74                 return -1;
75         }
76
77              /* Save the begining of the
78               * token in _r->s
79               */
80         _r->s = _s->s;
81
82              /* Iterate throught the
83               * token body
84               */
85         for(i = 0; i < _s->len; i++) {
86
87                      /* All these characters
88                       * mark end of the token
89                       */
90                 switch(_s->s[i]) {
91                 case ' ':
92                 case '\t':
93                 case '\r':
94                 case '\n':
95                 case ',':
96                 case ';':
97                              /* So if you find
98                               * any of them
99                               * stop iterating
100                               */
101                         goto out;
102                 }
103         }
104  out:
105         if (i == 0) {
106                 return -1;
107         }
108
109              /* Save length of the token */
110         _r->len = i;
111
112              /* Update _s parameter so it points
113               * right behind the end of the token
114               */
115         _s->s = _s->s + i;
116         _s->len -= i;
117
118              /* Everything went OK */
119         return 0;
120 }
121
122
123 /*
124  * Parse type of a parameter
125  */
126 static inline int parse_param_type(cparam_t* _c)
127 {
128         switch(_c->name.s[0]) {
129         case 'q':
130         case 'Q':
131                 if (_c->name.len == 1) {
132                         _c->type = CP_Q;
133                 }
134                 return 0;
135                 
136         case 'e':
137         case 'E':
138                 if ((_c->name.len == 7) &&
139                     (!strncasecmp(_c->name.s + 1, "xpires", 6))) {
140                         _c->type = CP_EXPIRES;
141                 }
142                 return 0;
143                 
144         case 'm':
145         case 'M':
146                 if ((_c->name.len == 6) &&
147                     (!strncasecmp(_c->name.s + 1, "ethod", 5))) {
148                         _c->type = CP_METHOD;
149                 }
150                 return 0;
151         }
152         return 0;
153 }
154
155
156 /*
157  * Parse body of a parameter. It can be quoted string or
158  * a single token.
159  */
160 static inline int parse_body(str* _s, cparam_t* _c)
161 {
162         if (_s->s[0] == '\"') {
163                 if (parse_quoted(_s, &(_c->body)) < 0) {
164                         LOG(L_ERR, "parse_body(): Error while parsing quoted string\n");
165                         return -2;
166                 }
167         } else {
168                 if (parse_token(_s, &(_c->body)) < 0) {
169                         LOG(L_ERR, "parse_body(): Error while parsing token\n");
170                         return -3;
171                 }
172         }
173
174         return 0;
175 }
176
177
178 /*
179  * Parse a parameter name
180  */
181 static inline int parse_param_name(str* _s, cparam_t* _p)
182 {
183         _p->name.s = _s->s;
184
185         while(_s->len) {
186                 switch(_s->s[0]) {
187                 case ' ':
188                 case '\t':
189                 case '\r':
190                 case '\n':
191                 case ';':
192                 case ',':
193                 case '=':
194                         goto out;
195                 }
196                 _s->s++;
197                 _s->len--;
198         }
199
200  out:
201         _p->name.len = _s->s - _p->name.s;
202         
203         if (parse_param_type(_p) < 0) {
204                 LOG(L_ERR, "parse_param_name(): Error while parsing type\n");
205                 return -2;
206         }
207         
208         return 0;
209 }
210
211
212 /*
213  * Parse contact parameters
214  */
215 int parse_cparams(str* _s, cparam_t** _p, cparam_t** _q, cparam_t** _e, cparam_t** _m)
216 {
217         cparam_t* c;
218
219         while(1) {
220                 c = (cparam_t*)pkg_malloc(sizeof(cparam_t));
221                 if (c == 0) {
222                         LOG(L_ERR, "parse_cparams(): No memory left\n");
223                         goto error;
224                 }
225                 memset(c, 0, sizeof(cparam_t));
226
227                 if (parse_param_name(_s, c) < 0) {
228                         LOG(L_ERR, "parse_cparams(): Error while parsing param name\n");
229                         goto error;
230                 }
231
232                 trim_leading(_s);
233                 
234                 if (_s->len == 0) { /* The last parameter without body */
235                         goto ok;
236                 }
237                 
238                 if (_s->s[0] == '=') {
239                         _s->s++;
240                         _s->len--;
241                         trim_leading(_s);
242
243                         if (_s->len == 0) {
244                                 LOG(L_ERR, "parse_cparams(): Body missing\n");
245                                 goto error;
246                         }
247
248                         if (parse_body(_s, c) < 0) {
249                                 LOG(L_ERR, "parse_cparams(): Error while parsing param body\n");
250                                 goto error;
251                         }
252
253                         trim_leading(_s);
254                         if (_s->len == 0) {
255                                 goto ok;
256                         }
257                 }
258
259                 if (_s->s[0] == ',') goto ok;
260
261                 if (_s->s[0] != ';') {
262                         LOG(L_ERR, "parse_cparams(): Invalid character, ; expected\n");
263                         goto error;
264                 }
265
266                 _s->s++;
267                 _s->len--;
268                 trim_leading(_s);
269                 
270                 if (_s->len == 0) {
271                         LOG(L_ERR, "parse_cparams(): Param name missing after ;\n");
272                         goto error;
273                 }
274
275                 c->next = *_p;
276                 *_p = c;
277                 switch(c->type) {    /* Update hook pointers */
278                 case CP_Q:       *_q = c; break;
279                 case CP_EXPIRES: *_e = c; break;
280                 case CP_METHOD:  *_m = c; break;
281                 case CP_OTHER:            break;
282                 }               
283         }
284
285  error:
286         if (c) pkg_free(c);
287         free_cparams(_p);
288         return -1;
289
290  ok:
291         c->next = *_p;
292         *_p = c;
293         switch(c->type) {    /* Update hook pointers */
294         case CP_Q:       *_q = c; break;
295         case CP_EXPIRES: *_e = c; break;
296         case CP_METHOD:  *_m = c; break;
297         case CP_OTHER:          ; break;
298         }
299         return 0;
300 }
301
302
303 /*
304  * Free the whole contact parameter list
305  */
306 void free_cparams(cparam_t** _p)
307 {
308         cparam_t* ptr;
309
310         while(*_p) {
311                 ptr = *_p;
312                 pkg_free(ptr);
313                 *_p = (*_p)->next;
314         }
315 }
316
317
318 /*
319  * Print contact parameter list
320  */
321 void print_cparams(cparam_t* _p)
322 {
323         cparam_t* ptr;
324         char* type;
325
326         ptr = _p;
327
328         while(ptr) {
329                 printf("...cparam(%p)...\n", ptr);
330
331                 switch(ptr->type) {
332                 case CP_OTHER:   type = "CP_OTHER";   break;
333                 case CP_Q:       type = "CP_Q";       break;
334                 case CP_EXPIRES: type = "CP_EXPIRES"; break;
335                 case CP_METHOD:  type = "CP_METHOD";  break;
336                 default:         type = "UNKNOWN";    break;
337                 }
338
339                 printf("type: %s\n", type);
340                 printf("name: \'%.*s\'\n", ptr->name.len, ptr->name.s);
341                 printf("body: \'%.*s\'\n", ptr->body.len, ptr->body.s);
342
343                 printf(".../cparam...\n");
344
345                 ptr = ptr->next;
346         }
347 }