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