2 * $Id: parse_param.c,v 1.21 2004/09/01 12:50:40 janakj Exp $
4 * Generic Parameter Parser
6 * Copyright (C) 2001-2003 FhG Fokus
8 * This file is part of ser, a free SIP server.
10 * ser is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version
15 * For a license to use the ser software under conditions
16 * other than those described here, or to purchase support for this
17 * software, please contact iptel.org by e-mail at the following addresses:
20 * ser is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 * 2003-03-24 Created by janakj
32 * 2003-04-07 shm duplication added (janakj)
33 * 2003-04-07 URI class added (janakj)
39 #include "../dprint.h"
41 #include "../mem/mem.h"
42 #include "../mem/shm_mem.h"
43 #include "parse_param.h"
47 * Try to find out parameter name, recognized parameters
48 * are q, expires and method
50 static inline void parse_contact_class(param_hooks_t* _h, param_t* _p)
54 LOG(L_ERR, "ERROR: parse_contact_class: empty value\n");
57 switch(_p->name.s[0]) {
60 if (_p->name.len == 1) {
68 if ((_p->name.len == 7) &&
69 (!strncasecmp(_p->name.s + 1, "xpires", 6))) {
71 _h->contact.expires = _p;
77 if ((_p->name.len == 6) &&
78 (!strncasecmp(_p->name.s + 1, "ethod", 5))) {
80 _h->contact.method = _p;
86 if ((_p->name.len == 8) &&
87 (!strncasecmp(_p->name.s + 1, "eceived", 7))) {
88 _p->type = P_RECEIVED;
89 _h->contact.received = _p;
97 * Try to find out parameter name, recognized parameters
98 * are transport, lr, r2, maddr
100 static inline void parse_uri_class(param_hooks_t* _h, param_t* _p)
104 LOG(L_ERR, "ERROR: parse_uri_class: empty value\n");
107 switch(_p->name.s[0]) {
110 if ((_p->name.len == 9) &&
111 (!strncasecmp(_p->name.s + 1, "ransport", 8))) {
112 _p->type = P_TRANSPORT;
113 _h->uri.transport = _p;
114 } else if (_p->name.len == 2) {
115 if (((_p->name.s[1] == 't') || (_p->name.s[1] == 'T')) &&
116 ((_p->name.s[2] == 'l') || (_p->name.s[2] == 'L'))) {
125 if ((_p->name.len == 2) && ((_p->name.s[1] == 'r') || (_p->name.s[1] == 'R'))) {
133 if ((_p->name.len == 2) && (_p->name.s[1] == '2')) {
141 if ((_p->name.len == 5) &&
142 (!strncasecmp(_p->name.s + 1, "addr", 4))) {
152 * Parse quoted string in a parameter body
153 * return the string without quotes in _r
154 * parameter and update _s to point behind the
157 static inline int parse_quoted_param(str* _s, str* _r)
161 /* The string must have at least
168 /* Skip opening quote */
173 /* Find closing quote */
174 end_quote = q_memchr(_s->s, '\"', _s->len);
176 /* Not found, return error */
181 /* Let _r point to the string without
185 _r->len = end_quote - _s->s;
187 /* Update _s parameter to point
188 * behind the closing quote
190 _s->len -= (end_quote - _s->s + 1);
191 _s->s = end_quote + 1;
193 /* Everything went OK */
199 * Parse unquoted token in a parameter body
200 * let _r point to the token and update _s
201 * to point right behind the token
203 static inline int parse_token_param(str* _s, str* _r)
207 /* There is nothing to parse,
214 /* Save the begining of the
219 /* Iterate through the
222 for(i = 0; i < _s->len; i++) {
224 /* All these characters
225 * mark end of the token
246 /* Save length of the token */
249 /* Update _s parameter so it points
250 * right behind the end of the token
255 /* Everything went OK */
261 * Parse a parameter name
263 static inline void parse_param_name(str* _s, pclass_t _c, param_hooks_t* _h, param_t* _p)
267 DBG("DEBUG: parse_param_name: empty parameter\n");
289 _p->name.len = _s->s - _p->name.s;
292 case CLASS_CONTACT: parse_contact_class(_h, _p); break;
293 case CLASS_URI: parse_uri_class(_h, _p); break;
303 * Parse body of a parameter. It can be quoted string or
306 static inline int parse_param_body(str* _s, param_t* _c)
308 if (_s->s[0] == '\"') {
309 if (parse_quoted_param(_s, &(_c->body)) < 0) {
310 LOG(L_ERR, "parse_param_body(): Error while parsing quoted string\n");
314 if (parse_token_param(_s, &(_c->body)) < 0) {
315 LOG(L_ERR, "parse_param_body(): Error while parsing token\n");
326 * _s is string containing parameters, it will be updated to point behind the parameters
327 * _c is class of parameters
328 * _h is pointer to structure that will be filled with pointer to well known parameters
329 * linked list of parsed parameters will be stored in
330 * the variable _p is pointing to
331 * The function returns 0 on success and negative number
334 int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p)
338 if (!_s || !_h || !_p) {
339 LOG(L_ERR, "parse_params(): Invalid parameter value\n");
343 memset(_h, 0, sizeof(param_hooks_t));
346 if (!_s->s) { /* no parameters at all -- we're done */
347 DBG("DEBUG: parse_params: empty uri params, skipping\n");
352 t = (param_t*)pkg_malloc(sizeof(param_t));
354 LOG(L_ERR, "parse_params(): No memory left\n");
357 memset(t, 0, sizeof(param_t));
359 parse_param_name(_s, _c, _h, t);
362 if (_s->len == 0) { /* The last parameter without body */
366 if (_s->s[0] == '=') {
372 LOG(L_ERR, "parse_params(): Body missing\n");
376 if (parse_param_body(_s, t) < 0) {
377 LOG(L_ERR, "parse_params(): Error while parsing param body\n");
381 t->len = _s->s - t->name.s;
388 t->len = t->name.len;
391 if (_s->s[0] == ',') goto ok; /* To be able to parse header parameters */
392 if (_s->s[0] == '>') goto ok; /* To be able to parse URI parameters */
394 if (_s->s[0] != ';') {
395 LOG(L_ERR, "parse_params(): Invalid character, ; expected\n");
404 LOG(L_ERR, "parse_params(): Param name missing after ;\n");
425 * Free linked list of parameters
427 static inline void do_free_params(param_t* _p, int _shm)
434 if (_shm) shm_free(ptr);
441 * Free linked list of parameters
443 void free_params(param_t* _p)
445 do_free_params(_p, 0);
450 * Free linked list of parameters
452 void shm_free_params(param_t* _p)
454 do_free_params(_p, 1);
459 * Print a parameter structure, just for debugging
461 static inline void print_param(FILE* _o, param_t* _p)
465 fprintf(_o, "---param(%p)---\n", _p);
468 case P_OTHER: type = "P_OTHER"; break;
469 case P_Q: type = "P_Q"; break;
470 case P_EXPIRES: type = "P_EXPIRES"; break;
471 case P_METHOD: type = "P_METHOD"; break;
472 case P_TRANSPORT: type = "P_TRANSPORT"; break;
473 case P_LR: type = "P_LR"; break;
474 case P_R2: type = "P_R2"; break;
475 case P_MADDR: type = "P_MADDR"; break;
476 case P_TTL: type = "P_TTL"; break;
477 case P_RECEIVED: type = "P_RECEIVED"; break;
478 default: type = "UNKNOWN"; break;
481 fprintf(_o, "type: %s\n", type);
482 fprintf(_o, "name: \'%.*s\'\n", _p->name.len, _p->name.s);
483 fprintf(_o, "body: \'%.*s\'\n", _p->body.len, _p->body.s);
484 fprintf(_o, "len : %d\n", _p->len);
485 fprintf(_o, "---/param---\n");
490 * Print linked list of parameters, just for debugging
492 void print_params(FILE* _o, param_t* _p)
498 print_param(_o, ptr);
505 * Duplicate linked list of parameters
507 static inline int do_duplicate_params(param_t** _n, param_t* _p, int _shm)
509 param_t* last, *ptr, *t;
512 LOG(L_ERR, "duplicate_params(): Invalid parameter value\n");
521 t = (param_t*)shm_malloc(sizeof(param_t));
523 t = (param_t*)pkg_malloc(sizeof(param_t));
526 LOG(L_ERR, "duplicate_params(): Invalid parameter value\n");
529 memcpy(t, ptr, sizeof(param_t));
533 if (last) last->next = t;
541 do_free_params(*_n, _shm);
547 * Duplicate linked list of parameters
549 int duplicate_params(param_t** _n, param_t* _p)
551 return do_duplicate_params(_n, _p, 0);
556 * Duplicate linked list of parameters
558 int shm_duplicate_params(param_t** _n, param_t* _p)
560 return do_duplicate_params(_n, _p, 1);