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