/* * $Id: transformations.c 2600 2007-08-14 13:05:42Z miconda $ * * Copyright (C) 2007 voice-system.ro * * This file is part of openser, a free SIP server. * * openser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * openser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include "dprint.h" #include "mem/mem.h" #include "ut.h" #include "trim.h" #include "dset.h" #include "usr_avp.h" #include "errinfo.h" #include "parser/parse_param.h" #include "parser/parse_uri.h" #include "strcommon.h" #include "transformations.h" #define TR_BUFFER_SIZE 65536 static char _tr_buffer[TR_BUFFER_SIZE]; int run_transformations(struct sip_msg *msg, trans_t *tr, xl_value_t *val) { trans_t *it; int ret = 0; if(tr==NULL || val==NULL) return -1; it = tr; while(it) { ret = (*it->trf)(msg, it->params, it->subtype, val); if(ret!=0) return ret; it = it->next; } return 0; } int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype, xl_value_t *val) { int i, j; char *p, *s; str st; xl_value_t v; if(val==NULL || val->flags&XL_VAL_NULL) return -1; switch(subtype) { case TR_S_LEN: if(!(val->flags&XL_VAL_STR)) val->rs.s = int2str(val->ri, &val->rs.len); val->flags = XL_TYPE_INT|XL_VAL_INT|XL_VAL_STR; val->ri = val->rs.len; val->rs.s = int2str(val->ri, &val->rs.len); break; case TR_S_INT: if(!(val->flags&XL_VAL_INT)) { if(str2sint(&val->rs, &val->ri)!=0) return -1; } else { if(!(val->flags&XL_VAL_STR)) val->rs.s = int2str(val->ri, &val->rs.len); } val->flags = XL_TYPE_INT|XL_VAL_INT|XL_VAL_STR; break; case TR_S_MD5: if(!(val->flags&XL_VAL_STR)) val->rs.s = int2str(val->ri, &val->rs.len); compute_md5(_tr_buffer, val->rs.s, val->rs.len); _tr_buffer[MD5_LEN] = '\0'; val->flags = XL_VAL_STR; val->ri = 0; val->rs.s = _tr_buffer; val->rs.len = MD5_LEN; break; case TR_S_ENCODEHEXA: if(!(val->flags&XL_VAL_STR)) val->rs.s = int2str(val->ri, &val->rs.len); if(val->rs.len>TR_BUFFER_SIZE/2-1) return -1; j = 0; for(i=0; irs.len; i++) { _tr_buffer[j++] = fourbits2char[val->rs.s[i] >> 4]; _tr_buffer[j++] = fourbits2char[val->rs.s[i] & 0xf]; } _tr_buffer[j] = '\0'; memset(val, 0, sizeof(xl_value_t)); val->flags = XL_VAL_STR; val->rs.s = _tr_buffer; val->rs.len = j; break; case TR_S_DECODEHEXA: if(!(val->flags&XL_VAL_STR)) val->rs.s = int2str(val->ri, &val->rs.len); if(val->rs.len>TR_BUFFER_SIZE*2-1) return -1; for(i=0; irs.len/2; i++) { if(val->rs.s[2*i]>='0'&&val->rs.s[2*i]<='9') _tr_buffer[i] = (val->rs.s[2*i]-'0') << 4; else if(val->rs.s[2*i]>='a'&&val->rs.s[2*i]<='f') _tr_buffer[i] = (val->rs.s[2*i]-'a'+10) << 4; else if(val->rs.s[2*i]>='A'&&val->rs.s[2*i]<='F') _tr_buffer[i] = (val->rs.s[2*i]-'A'+10) << 4; else return -1; if(val->rs.s[2*i+1]>='0'&&val->rs.s[2*i+1]<='9') _tr_buffer[i] += val->rs.s[2*i+1]-'0'; else if(val->rs.s[2*i+1]>='a'&&val->rs.s[2*i+1]<='f') _tr_buffer[i] += val->rs.s[2*i+1]-'a'+10; else if(val->rs.s[2*i+1]>='A'&&val->rs.s[2*i+1]<='F') _tr_buffer[i] += val->rs.s[2*i+1]-'A'+10; else return -1; } _tr_buffer[i] = '\0'; memset(val, 0, sizeof(xl_value_t)); val->flags = XL_VAL_STR; val->rs.s = _tr_buffer; val->rs.len = i; break; case TR_S_ESCAPECOMMON: if(!(val->flags&XL_VAL_STR)) val->rs.s = int2str(val->ri, &val->rs.len); if(val->rs.len>TR_BUFFER_SIZE/2-1) return -1; i = escape_common(_tr_buffer, val->rs.s, val->rs.len); _tr_buffer[i] = '\0'; memset(val, 0, sizeof(xl_value_t)); val->flags = XL_VAL_STR; val->rs.s = _tr_buffer; val->rs.len = i; break; case TR_S_UNESCAPECOMMON: if(!(val->flags&XL_VAL_STR)) val->rs.s = int2str(val->ri, &val->rs.len); if(val->rs.len>TR_BUFFER_SIZE-1) return -1; i = unescape_common(_tr_buffer, val->rs.s, val->rs.len); _tr_buffer[i] = '\0'; memset(val, 0, sizeof(xl_value_t)); val->flags = XL_VAL_STR; val->rs.s = _tr_buffer; val->rs.len = i; break; case TR_S_ESCAPEUSER: if(!(val->flags&XL_VAL_STR)) val->rs.s = int2str(val->ri, &val->rs.len); if(val->rs.len>TR_BUFFER_SIZE/2-1) return -1; st.s = _tr_buffer; st.len = TR_BUFFER_SIZE; escape_user(&val->rs, &st); memset(val, 0, sizeof(xl_value_t)); val->flags = XL_VAL_STR; val->rs = st; break; case TR_S_UNESCAPEUSER: if(!(val->flags&XL_VAL_STR)) val->rs.s = int2str(val->ri, &val->rs.len); if(val->rs.len>TR_BUFFER_SIZE-1) return -1; st.s = _tr_buffer; st.len = TR_BUFFER_SIZE; unescape_user(&val->rs, &st); memset(val, 0, sizeof(xl_value_t)); val->flags = XL_VAL_STR; val->rs = st; break; case TR_S_SUBSTR: if(tp==NULL || tp->next==NULL) { LOG(L_ERR, "tr_eval_string: substr invalid parameters\n"); return -1; } if(!(val->flags&XL_VAL_STR)) val->rs.s = int2str(val->ri, &val->rs.len); if(tp->type==TR_PARAM_NUMBER) { i = tp->v.n; } else { if(xl_get_spec_value(msg, (xl_spec_p)tp->v.data, &v, 0)!=0 || (!(v.flags&XL_VAL_INT))) { LOG(L_ERR, "tr_eval_string: substr cannot get p1\n"); return -1; } i = v.ri; } if(tp->next->type==TR_PARAM_NUMBER) { j = tp->next->v.n; } else { if(xl_get_spec_value(msg, (xl_spec_p)tp->next->v.data, &v, 0)!=0 || (!(v.flags&XL_VAL_INT))) { LOG(L_ERR, "tr_eval_string: substr cannot get p2\n"); return -1; } j = v.ri; } DBG("tr_eval_string: i=%d j=%d\n", i, j); if(j<0) { LOG(L_ERR, "tr_eval_string: substr negative offset\n"); return -1; } val->flags = XL_VAL_STR; val->ri = 0; if(i>=0) { if(i>=val->rs.len) { LOG(L_ERR, "tr_eval_string: substr out of range\n"); return -1; } if(i+j>=val->rs.len) j=0; if(j==0) { /* to end */ val->rs.s += i; val->rs.len -= i; break; } val->rs.s += i; val->rs.len = j; break; } i = -i; if(i>val->rs.len) { LOG(L_ERR, "tr_eval_string: substr out of range\n"); return -1; } if(irs.s += val->rs.len-i; val->rs.len = i; break; } val->rs.s += val->rs.len-i; val->rs.len = j; break; case TR_S_SELECT: if(tp==NULL || tp->next==NULL) { LOG(L_ERR, "tr_eval_string: select invalid parameters\n"); return -1; } if(!(val->flags&XL_VAL_STR)) val->rs.s = int2str(val->ri, &val->rs.len); if(tp->type==TR_PARAM_NUMBER) { i = tp->v.n; } else { if(xl_get_spec_value(msg, (xl_spec_p)tp->v.data, &v, 0)!=0 || (!(v.flags&XL_VAL_INT))) { LOG(L_ERR, "tr_eval_string: select cannot get p1\n"); return -1; } i = v.ri; } val->flags = XL_VAL_STR; val->ri = 0; if(i<0) { s = val->rs.s+val->rs.len-1; p = s; i = -i; i--; while(p>=val->rs.s) { if(*p==tp->next->v.s.s[0]) { if(i==0) break; s = p-1; i--; } p--; } if(i==0) { val->rs.s = p+1; val->rs.len = s-p; } else { val->rs.s = ""; val->rs.len = 0; } } else { s = val->rs.s; p = s; while(prs.s+val->rs.len) { if(*p==tp->next->v.s.s[0]) { if(i==0) break; s = p + 1; i--; } p++; } if(i==0) { val->rs.s = s; val->rs.len = p-s; } else { val->rs.s = ""; val->rs.len = 0; } } break; default: LOG(L_ERR, "tr_eval_string: unknown subtype %d\n", subtype); return -1; } return 0; } static str _tr_empty = { "", 0 }; static str _tr_uri = {0, 0}; static struct sip_uri _tr_parsed_uri; static param_t* _tr_uri_params = NULL; int tr_eval_uri(struct sip_msg *msg, tr_param_t *tp, int subtype, xl_value_t *val) { xl_value_t v; str sv; param_hooks_t phooks; param_t *pit=NULL; if(val==NULL || (!(val->flags&XL_VAL_STR)) || val->rs.len<=0) return -1; if(_tr_uri.len==0 || _tr_uri.len!=val->rs.len || strncmp(_tr_uri.s, val->rs.s, val->rs.len)!=0) { if(val->rs.len>_tr_uri.len) { if(_tr_uri.s) pkg_free(_tr_uri.s); _tr_uri.s = (char*)pkg_malloc((val->rs.len+1)*sizeof(char)); if(_tr_uri.s==NULL) { LOG(L_ERR, "tr_eval_uri: no more memory\n"); if(_tr_uri_params != NULL) { free_params(_tr_uri_params); _tr_uri_params = 0; } memset(&_tr_uri, 0, sizeof(str)); memset(&_tr_parsed_uri, 0, sizeof(struct sip_uri)); return -1; } } _tr_uri.len = val->rs.len; memcpy(_tr_uri.s, val->rs.s, val->rs.len); _tr_uri.s[_tr_uri.len] = '\0'; /* reset old values */ memset(&_tr_parsed_uri, 0, sizeof(struct sip_uri)); if(_tr_uri_params != NULL) { free_params(_tr_uri_params); _tr_uri_params = 0; } /* parse uri -- params only when requested */ if(parse_uri(_tr_uri.s, _tr_uri.len, &_tr_parsed_uri)!=0) { LOG(L_ERR, "tr_eval_uri: invalid uri [%.*s]\n", _tr_uri.len, _tr_uri.s); if(_tr_uri_params != NULL) { free_params(_tr_uri_params); _tr_uri_params = 0; } pkg_free(_tr_uri.s); memset(&_tr_uri, 0, sizeof(str)); memset(&_tr_parsed_uri, 0, sizeof(struct sip_uri)); return -1; } } memset(val, 0, sizeof(xl_value_t)); val->flags = XL_VAL_STR; switch(subtype) { case TR_URI_USER: val->rs = (_tr_parsed_uri.user.s)?_tr_parsed_uri.user:_tr_empty; break; case TR_URI_HOST: val->rs = (_tr_parsed_uri.host.s)?_tr_parsed_uri.host:_tr_empty; break; case TR_URI_PASSWD: val->rs = (_tr_parsed_uri.passwd.s)?_tr_parsed_uri.passwd:_tr_empty; break; case TR_URI_PORT: val->flags |= XL_TYPE_INT|XL_VAL_INT; val->rs = (_tr_parsed_uri.port.s)?_tr_parsed_uri.port:_tr_empty; val->ri = _tr_parsed_uri.port_no; break; case TR_URI_PARAMS: val->rs = (_tr_parsed_uri.params.s)?_tr_parsed_uri.params:_tr_empty; break; case TR_URI_PARAM: if(tp==NULL) { LOG(L_ERR, "tr_eval_uri: param invalid parameters\n"); return -1; } if(_tr_parsed_uri.params.len<=0) { LOG(L_DBG, "tr_eval_uri: params are empty [%.*s]\n", _tr_uri.len, _tr_uri.s); val->rs = _tr_empty; val->flags = XL_VAL_STR; val->ri = 0; break; } if(_tr_uri_params == NULL) { sv = _tr_parsed_uri.params; if (parse_params(&sv, CLASS_ANY, &phooks, &_tr_uri_params)<0) return -1; LOG(L_DBG, "tr_eval_uri: params are parsed [%.*s]\n", _tr_uri.len, _tr_uri.s); } if(tp->type==TR_PARAM_STRING) { sv = tp->v.s; } else { if(xl_get_spec_value(msg, (xl_spec_p)tp->v.data, &v, 0)!=0 || (!(v.flags&XL_VAL_STR)) || v.rs.len<=0) { LOG(L_ERR, "tr_eval_uri: param cannot get p1\n"); return -1; } sv = v.rs; } for (pit = _tr_uri_params; pit; pit=pit->next) { if (pit->name.len==sv.len && strncasecmp(pit->name.s, sv.s, sv.len)==0) { val->rs = pit->body; LOG(L_DBG, "tr_eval_uri: param found [%.*s] [%.*s]\n", _tr_uri.len, _tr_uri.s, val->rs.len, val->rs.s); goto done; } } LOG(L_DBG, "tr_eval_uri: param not found [%.*s]\n", _tr_uri.len, _tr_uri.s); val->rs = _tr_empty; break; case TR_URI_HEADERS: val->rs = (_tr_parsed_uri.headers.s)?_tr_parsed_uri.headers: _tr_empty; break; case TR_URI_TRANSPORT: val->rs = (_tr_parsed_uri.transport_val.s)? _tr_parsed_uri.transport_val:_tr_empty; break; case TR_URI_TTL: val->rs = (_tr_parsed_uri.ttl_val.s)? _tr_parsed_uri.ttl_val:_tr_empty; break; case TR_URI_UPARAM: val->rs = (_tr_parsed_uri.user_param_val.s)? _tr_parsed_uri.user_param_val:_tr_empty; break; case TR_URI_MADDR: val->rs = (_tr_parsed_uri.maddr_val.s)? _tr_parsed_uri.maddr_val:_tr_empty; break; case TR_URI_METHOD: val->rs = (_tr_parsed_uri.method_val.s)? _tr_parsed_uri.method_val:_tr_empty; break; case TR_URI_LR: val->rs = (_tr_parsed_uri.lr_val.s)? _tr_parsed_uri.lr_val:_tr_empty; break; case TR_URI_R2: val->rs = (_tr_parsed_uri.r2_val.s)? _tr_parsed_uri.r2_val:_tr_empty; break; default: LOG(L_ERR, "tr_eval_uri: unknown subtype %d\n", subtype); return -1; } done: return 0; } static str _tr_params_str = {0, 0}; static param_t* _tr_params_list = NULL; int tr_eval_paramlist(struct sip_msg *msg, tr_param_t *tp, int subtype, xl_value_t *val) { xl_value_t v; str sv; int n, i; param_hooks_t phooks; param_t *pit=NULL; if(val==NULL || (!(val->flags&XL_VAL_STR)) || val->rs.len<=0) return -1; if(_tr_params_str.len==0 || _tr_params_str.len!=val->rs.len || strncmp(_tr_params_str.s, val->rs.s, val->rs.len)!=0) { if(val->rs.len>_tr_params_str.len) { if(_tr_params_str.s) pkg_free(_tr_params_str.s); _tr_params_str.s = (char*)pkg_malloc((val->rs.len+1)*sizeof(char)); if(_tr_params_str.s==NULL) { LOG(L_ERR, "tr_eval_paramlist: no more memory\n"); memset(&_tr_params_str, 0, sizeof(str)); if(_tr_params_list != NULL) { free_params(_tr_params_list); _tr_params_list = 0; } return -1; } } _tr_params_str.len = val->rs.len; memcpy(_tr_params_str.s, val->rs.s, val->rs.len); _tr_params_str.s[_tr_params_str.len] = '\0'; /* reset old values */ if(_tr_params_list != NULL) { free_params(_tr_params_list); _tr_params_list = 0; } /* parse params */ sv = _tr_params_str; if (parse_params(&sv, CLASS_ANY, &phooks, &_tr_params_list)<0) return -1; } if(_tr_params_list==NULL) return -1; memset(val, 0, sizeof(xl_value_t)); val->flags = XL_VAL_STR; switch(subtype) { case TR_PL_VALUE: if(tp==NULL) { LOG(L_ERR, "tr_eval_paramlist: value invalid parameters\n"); return -1; } if(tp->type==TR_PARAM_STRING) { sv = tp->v.s; } else { if(xl_get_spec_value(msg, (xl_spec_p)tp->v.data, &v, 0)!=0 || (!(v.flags&XL_VAL_STR)) || v.rs.len<=0) { LOG(L_ERR, "tr_eval_paramlist: value cannot get p1\n"); return -1; } sv = v.rs; } for (pit = _tr_params_list; pit; pit=pit->next) { if (pit->name.len==sv.len && strncasecmp(pit->name.s, sv.s, sv.len)==0) { val->rs = pit->body; goto done; } } val->rs = _tr_empty; break; case TR_PL_NAME: if(tp==NULL) { LOG(L_ERR, "tr_eval_paramlist: name invalid parameters\n"); return -1; } if(tp->type==TR_PARAM_NUMBER) { n = tp->v.n; } else { if(xl_get_spec_value(msg, (xl_spec_p)tp->v.data, &v, 0)!=0 || (!(v.flags&XL_VAL_INT))) { LOG(L_ERR, "tr_eval_paramlist: name cannot get p1\n"); return -1; } n = v.ri; } if(n<0) { n = -n; n--; for (pit = _tr_params_list; pit; pit=pit->next) { if(n==0) { val->rs = pit->name; goto done; } n--; } } else { /* ugly hack -- params are in reverse order * - first count then find */ i = 0; for (pit = _tr_params_list; pit; pit=pit->next) i++; if(nnext) { if(n==0) { val->rs = pit->name; goto done; } n--; } } } val->rs = _tr_empty; break; default: LOG(L_ERR, "tr_eval_paramlist: unknown subtype %d\n", subtype); return -1; } done: return 0; } char* parse_transformation(char *s, trans_t **tr) { char *p; char *p0; str tclass; trans_t *t = NULL; trans_t *t0 = NULL; if(s==NULL || tr==NULL) return NULL; p = s; do { while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++; if(*p != TR_LBRACKET) break; p++; t = (trans_t*)pkg_malloc(sizeof(trans_t)); if(t == NULL) { LOG(L_ERR, "parse_transformation: no more memory\n"); return NULL; } memset(t, 0, sizeof(trans_t)); if(t0==NULL) *tr = t; else t0->next = t;; t0 = t; /* find transformation class */ tclass.s = p; while(*p && *p!=TR_CLASS_MARKER) p++; if(*p!=TR_CLASS_MARKER || tclass.s == p) { LOG(L_ERR, "parse_transformation: invalid transformation: %s!\n", s); goto error; } tclass.len = p - tclass.s; p++; if(tclass.len==1 && (*tclass.s=='s' || *tclass.s=='S')) { t->type = TR_STRING; t->trf = tr_eval_string; p0 = tr_parse_string(p, t); if(p0==NULL) goto error; p = p0; } else if(tclass.len==3 && strncasecmp(tclass.s, "uri", 3)==0) { t->type = TR_URI; t->trf = tr_eval_uri; p0 = tr_parse_uri(p, t); if(p0==NULL) goto error; p = p0; } else if(tclass.len==5 && strncasecmp(tclass.s, "param", 5)==0) { t->type = TR_PARAMLIST; t->trf = tr_eval_paramlist; p0 = tr_parse_paramlist(p, t); if(p0==NULL) goto error; p = p0; } else { LOG(L_ERR, "parse_transformation: unknown transformation: [%.*s] in [%s]\n", tclass.len, tclass.s, s); goto error; } if(*p != TR_RBRACKET) { LOG(L_ERR, "parse_transformation: invalid transformation: %s!!\n", s); goto error; } p++; } while(1); return p; error: LOG(L_ERR, "parse_transformation: error parsing [%s]\n", s); t = *tr; while(t) { t0 = t; t = t->next; destroy_transformation(t0); pkg_free(t0); } return NULL; } #define _tr_parse_nparam(_p, _p0, _tp, _spec, _n, _sign, _s) \ while(*_p && (*_p==' ' || *_p=='\t' || *_p=='\n')) _p++; \ if(*_p==ITEM_MARKER) \ { /* pseudo-variable */ \ _spec = (xl_spec_t*)pkg_malloc(sizeof(xl_spec_t)); \ if(_spec==NULL) \ { \ LOG(L_ERR, "tr_parse_nparam: no more memory!\n"); \ goto error; \ } \ _p0 = xl_parse_spec(_p, _spec, 0); \ if(_p0==NULL) \ { \ LOG(L_ERR, \ "tr_parse_nparam: invalid spec in substr transformation: %s!\n", \ _s); \ goto error; \ } \ _p = _p0; \ _tp = (tr_param_t*)pkg_malloc(sizeof(tr_param_t)); \ if(_tp==NULL) \ { \ LOG(L_ERR, "tr_nparam_string: no more memory!\n"); \ goto error; \ } \ memset(_tp, 0, sizeof(tr_param_t)); \ _tp->type = TR_PARAM_SPEC; \ _tp->v.data = (void*)_spec; \ } else { \ if(*_p=='+' || *_p=='-' || (*_p>='0' && *_p<='9')) \ { /* number */ \ _sign = 1; \ if(*_p=='-') { \ _p++; \ _sign = -1; \ } else if(*_p=='+') _p++; \ _n = 0; \ while(*_p && (*_p==' ' || *_p=='\t' || *_p=='\n')) _p++; \ while(*_p>='0' && *_p<='9') \ { \ _n = _n*10 + *_p - '0'; \ _p++; \ } \ _tp = (tr_param_t*)pkg_malloc(sizeof(tr_param_t)); \ if(_tp==NULL) \ { \ LOG(L_ERR, "tr_parse_nparam: no more memory!\n"); \ goto error; \ } \ memset(_tp, 0, sizeof(tr_param_t)); \ _tp->type = TR_PARAM_NUMBER; \ _tp->v.n = sign*n; \ } else { \ LOG(L_ERR, \ "tr_parse_nparam: invalid param in transformation: %s!!\n", \ _s); \ goto error; \ } \ } #define _tr_parse_sparam(_p, _p0, _tp, _spec, _ps, _s) \ while(*_p && (*_p==' ' || *_p=='\t' || *_p=='\n')) _p++; \ if(*_p==ITEM_MARKER) \ { /* pseudo-variable */ \ _spec = (xl_spec_t*)pkg_malloc(sizeof(xl_spec_t)); \ if(_spec==NULL) \ { \ LOG(L_ERR, "tr_parse_sparam: no more memory!\n"); \ goto error; \ } \ _p0 = xl_parse_spec(_p, _spec, 0); \ if(_p0==NULL) \ { \ LOG(L_ERR, \ "tr_parse_sparam: invalid spec in substr transformation: %s!\n", \ _s); \ goto error; \ } \ _p = _p0; \ _tp = (tr_param_t*)pkg_malloc(sizeof(tr_param_t)); \ if(_tp==NULL) \ { \ LOG(L_ERR, "tr_sparam_string: no more memory!\n"); \ goto error; \ } \ memset(_tp, 0, sizeof(tr_param_t)); \ _tp->type = TR_PARAM_SPEC; \ _tp->v.data = (void*)_spec; \ } else { /* string */ \ while(*_p && (*_p==' ' || *_p=='\t' || *_p=='\n')) _p++; \ _ps = _p; \ while(*_p!='\0' && *_p!=' ' && *_p!='\t' && *_p!='\n' \ && *_p!=TR_PARAM_MARKER && *_p!=TR_RBRACKET) \ _p++; \ if(*_p=='\0') \ { \ LOG(L_ERR, \ "tr_parse_sparam: invalid param in transformation: %s!!\n", \ _s); \ goto error; \ } \ _tp = (tr_param_t*)pkg_malloc(sizeof(tr_param_t)); \ if(_tp==NULL) \ { \ LOG(L_ERR, "tr_parse_sparam: no more memory!\n"); \ goto error; \ } \ memset(_tp, 0, sizeof(tr_param_t)); \ _tp->type = TR_PARAM_STRING; \ _tp->v.s.s = _ps; \ _tp->v.s.len = _p - _ps; \ } char* tr_parse_string(char* s, trans_t *t) { char *p; char *p0; str name; xl_spec_t *spec = NULL; int n; int sign; tr_param_t *tp = NULL; if(s==NULL || t==NULL) return NULL; p = s; name.s = s; /* find next token */ while(*p && *p!=TR_PARAM_MARKER && *p!=TR_RBRACKET) p++; if(*p=='\0') { LOG(L_ERR, "tr_parse_string: invalid transformation: %s\n", s); goto error; } name.len = p - name.s; trim(&name); if(name.len==3 && strncasecmp(name.s, "len", 3)==0) { t->subtype = TR_S_LEN; return p; } else if(name.len==3 && strncasecmp(name.s, "int", 3)==0) { t->subtype = TR_S_INT; return p; } else if(name.len==3 && strncasecmp(name.s, "md5", 3)==0) { t->subtype = TR_S_MD5; return p; } else if(name.len==11 && strncasecmp(name.s, "encode.hexa", 11)==0) { t->subtype = TR_S_ENCODEHEXA; return p; } else if(name.len==11 && strncasecmp(name.s, "decode.hexa", 11)==0) { t->subtype = TR_S_DECODEHEXA; return p; } else if(name.len==13 && strncasecmp(name.s, "escape.common", 13)==0) { t->subtype = TR_S_ESCAPECOMMON; return p; } else if(name.len==15 && strncasecmp(name.s, "unescape.common", 15)==0) { t->subtype = TR_S_UNESCAPECOMMON; return p; } else if(name.len==11 && strncasecmp(name.s, "escape.user", 11)==0) { t->subtype = TR_S_ESCAPEUSER; return p; } else if(name.len==13 && strncasecmp(name.s, "unescape.user", 13)==0) { t->subtype = TR_S_UNESCAPEUSER; return p; } else if(name.len==6 && strncasecmp(name.s, "substr", 6)==0) { t->subtype = TR_S_SUBSTR; if(*p!=TR_PARAM_MARKER) { LOG(L_ERR, "tr_parse_string: invalid substr transformation: %s!\n", s); goto error; } p++; _tr_parse_nparam(p, p0, tp, spec, n, sign, s); t->params = tp; tp = 0; while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++; if(*p!=TR_PARAM_MARKER) { LOG(L_ERR, "tr_parse_string: invalid substr transformation: %s!\n", s); goto error; } p++; _tr_parse_nparam(p, p0, tp, spec, n, sign, s); if(tp->type==TR_PARAM_NUMBER && tp->v.n<0) { LOG(L_ERR, "tr_parse_string: substr negative offset\n"); goto error; } t->params->next = tp; tp = 0; while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++; if(*p!=TR_RBRACKET) { LOG(L_ERR, "tr_parse_string: invalid substr transformation: %s!!\n", s); goto error; } return p; } else if(name.len==6 && strncasecmp(name.s, "select", 6)==0) { t->subtype = TR_S_SELECT; if(*p!=TR_PARAM_MARKER) { LOG(L_ERR, "tr_parse_string: invalid select transformation: %s!\n", s); goto error; } p++; _tr_parse_nparam(p, p0, tp, spec, n, sign, s); t->params = tp; tp = 0; while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++; if(*p!=TR_PARAM_MARKER || *(p+1)=='\0') { LOG(L_ERR, "tr_parse_string: invalid select transformation: %s!\n", s); goto error; } p++; tp = (tr_param_t*)pkg_malloc(sizeof(tr_param_t)); if(tp==NULL) { LOG(L_ERR, "tr_parse_string: no more memory!\n"); goto error; } memset(tp, 0, sizeof(tr_param_t)); tp->type = TR_PARAM_STRING; tp->v.s.s = p; tp->v.s.len = 1; t->params->next = tp; tp = 0; p++; while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++; if(*p!=TR_RBRACKET) { LOG(L_ERR, "tr_parse_string: invalid select transformation: %s!!\n", s); goto error; } return p; } LOG(L_ERR, "tr_parse_string: unknown transformation: %s/%s/%d!\n", s, name.s, name.len); error: if(tp) free_tr_param(tp); if(spec) xl_spec_free(spec); return NULL; } char* tr_parse_uri(char* s, trans_t *t) { char *p; char *p0; char *ps; str name; xl_spec_t *spec = NULL; tr_param_t *tp = NULL; if(s==NULL || t==NULL) return NULL; p = s; name.s = s; /* find next token */ while(*p && *p!=TR_PARAM_MARKER && *p!=TR_RBRACKET) p++; if(*p=='\0') { LOG(L_ERR, "tr_parse_uri: invalid transformation: %s\n", s); goto error; } name.len = p - name.s; trim(&name); if(name.len==4 && strncasecmp(name.s, "user", 4)==0) { t->subtype = TR_URI_USER; return p; } else if((name.len==4 && strncasecmp(name.s, "host", 4)==0) || (name.len==6 && strncasecmp(name.s, "domain", 6)==0)) { t->subtype = TR_URI_HOST; return p; } else if(name.len==6 && strncasecmp(name.s, "passwd", 6)==0) { t->subtype = TR_URI_PASSWD; return p; } else if(name.len==4 && strncasecmp(name.s, "port", 4)==0) { t->subtype = TR_URI_PORT; return p; } else if(name.len==6 && strncasecmp(name.s, "params", 6)==0) { t->subtype = TR_URI_PARAMS; return p; } else if(name.len==5 && strncasecmp(name.s, "param", 5)==0) { t->subtype = TR_URI_PARAM; if(*p!=TR_PARAM_MARKER) { LOG(L_ERR, "tr_parse_uri: invalid param transformation: %s\n", s); goto error; } p++; _tr_parse_sparam(p, p0, tp, spec, ps, s); t->params = tp; tp = 0; while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++; if(*p!=TR_RBRACKET) { LOG(L_ERR, "tr_parse_uri: invalid param transformation: %s!\n", s); goto error; } return p; } else if(name.len==9 && strncasecmp(name.s, "transport", 9)==0) { t->subtype = TR_URI_TRANSPORT; return p; } else if(name.len==3 && strncasecmp(name.s, "ttl", 3)==0) { t->subtype = TR_URI_TTL; return p; } else if(name.len==6 && strncasecmp(name.s, "uparam", 6)==0) { t->subtype = TR_URI_UPARAM; return p; } else if(name.len==5 && strncasecmp(name.s, "maddr", 5)==0) { t->subtype = TR_URI_MADDR; return p; } else if(name.len==6 && strncasecmp(name.s, "method", 6)==0) { t->subtype = TR_URI_METHOD; return p; } else if(name.len==2 && strncasecmp(name.s, "lr", 2)==0) { t->subtype = TR_URI_LR; return p; } else if(name.len==2 && strncasecmp(name.s, "r2", 2)==0) { t->subtype = TR_URI_R2; return p; } LOG(L_ERR, "tr_parse_uri: unknown transformation: %s/%.*s!\n", s, name.len, name.s); error: if(tp) free_tr_param(tp); if(spec) xl_spec_free(spec); return NULL; } char* tr_parse_paramlist(char* s, trans_t *t) { char *p; char *p0; char *ps; str name; int n; int sign; xl_spec_t *spec = NULL; tr_param_t *tp = NULL; if(s==NULL || t==NULL) return NULL; p = s; name.s = s; /* find next token */ while(*p && *p!=TR_PARAM_MARKER && *p!=TR_RBRACKET) p++; if(*p=='\0') { LOG(L_ERR, "tr_parse_param: invalid transformation: %s\n", s); goto error; } name.len = p - name.s; trim(&name); if(name.len==5 && strncasecmp(name.s, "value", 5)==0) { t->subtype = TR_PL_VALUE; if(*p!=TR_PARAM_MARKER) { LOG(L_ERR, "tr_parse_param: invalid value transformation: %s\n", s); goto error; } p++; _tr_parse_sparam(p, p0, tp, spec, ps, s); t->params = tp; tp = 0; while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++; if(*p!=TR_RBRACKET) { LOG(L_ERR, "tr_parse_param: invalid value transformation: %s!\n", s); goto error; } return p; } else if(name.len==4 && strncasecmp(name.s, "name", 4)==0) { t->subtype = TR_PL_NAME; if(*p!=TR_PARAM_MARKER) { LOG(L_ERR, "tr_parse_param: invalid name transformation: %s\n", s); goto error; } p++; _tr_parse_nparam(p, p0, tp, spec, n, sign, s) t->params = tp; tp = 0; while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++; if(*p!=TR_RBRACKET) { LOG(L_ERR, "tr_parse_param: invalid name transformation: %s!\n", s); goto error; } return p; } LOG(L_ERR, "tr_parse_param: unknown transformation: %s/%.*s!\n", s, name.len, name.s); error: if(tp) free_tr_param(tp); if(spec) xl_spec_free(spec); return NULL; } void destroy_transformation(trans_t *t) { tr_param_t *tp; tr_param_t *tp0; if(t==NULL) return; tp = t->params; while(tp) { tp0 = tp; tp = tp->next; free_tr_param(tp0); } memset(t, 0, sizeof(trans_t)); } void free_transformation(trans_t *t) { trans_t *t0; while(t) { t0 = t; t = t->next; destroy_transformation(t0); pkg_free(t0); } } void free_tr_param(tr_param_t *tp) { tr_param_t *tp0; if(tp==NULL) return; while(tp) { tp0 = tp; tp = tp->next; if(tp0->type==TR_PARAM_SPEC) xl_spec_free((xl_spec_t*)tp0->v.data); pkg_free(tp0); } }