Module: sip-router Branch: master Commit: 0f598b1a5798ecd403ef588f7d4c6b38177883ce URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=0f598b1a...
Author: Daniel-Constantin Mierla miconda@gmail.com Committer: Daniel-Constantin Mierla miconda@gmail.com Date: Fri Dec 16 13:10:57 2011 +0100
pv: new transformation class 'line'
- {line.count} - return number of lines in PV - {line.at,pos} - return the line at position pos - {line.sw,exp} - return the line starting with 'exp'
---
modules_k/pv/pv.c | 2 + modules_k/pv/pv_trans.c | 291 +++++++++++++++++++++++++++++++++++++++++++++++ modules_k/pv/pv_trans.h | 6 +- 3 files changed, 298 insertions(+), 1 deletions(-)
diff --git a/modules_k/pv/pv.c b/modules_k/pv/pv.c index f5784d9..bc47e1a 100644 --- a/modules_k/pv/pv.c +++ b/modules_k/pv/pv.c @@ -53,6 +53,8 @@ static tr_export_t mod_trans[] = { tr_parse_paramlist }, { {"tobody", sizeof("tobody")-1}, /* param class */ tr_parse_tobody }, + { {"line", sizeof("line")-1}, /* line class */ + tr_parse_line },
{ { 0, 0 }, 0 } }; diff --git a/modules_k/pv/pv_trans.c b/modules_k/pv/pv_trans.c index f1dcce3..22d3a9e 100644 --- a/modules_k/pv/pv_trans.c +++ b/modules_k/pv/pv_trans.c @@ -1342,6 +1342,202 @@ int tr_eval_tobody(struct sip_msg *msg, tr_param_t *tp, int subtype, return 0; }
+void *memfindrchr(const void *buf, int c, size_t n) +{ + int i; + unsigned char *p; + + p = (unsigned char*)buf; + + for (i=n-1; i>=0; i--) { + if (p[i] == (unsigned char)c) { + return (void*)(p+i); + } + } + return NULL; +} + +/*! + * \brief Evaluate line transformations + * \param msg SIP message + * \param tp transformation + * \param subtype transformation type + * \param val pseudo-variable + * \return 0 on success, -1 on error + */ +int tr_eval_line(struct sip_msg *msg, tr_param_t *tp, int subtype, + pv_value_t *val) +{ + pv_value_t v; + str sv; + str mv; + char *p; + int n, i; + + if(val==NULL || (!(val->flags&PV_VAL_STR)) || val->rs.len<=0) + return -1; + + switch(subtype) + { + case TR_LINE_SW: + if(tp==NULL) + { + LM_ERR("value invalid parameters\n"); + return -1; + } + + if(tp->type==TR_PARAM_STRING) + { + sv = tp->v.s; + } else { + if(pv_get_spec_value(msg, (pv_spec_p)tp->v.data, &v)!=0 + || (!(v.flags&PV_VAL_STR)) || v.rs.len<=0) + { + LM_ERR("value cannot get p1\n"); + return -1; + } + sv = v.rs; + } + + if(val->rs.len < sv.len) + { + val->rs = _tr_empty; + goto done; + } + p = val->rs.s; + do { + if(strncmp(p, sv.s, sv.len)==0) + { + /* match */ + mv.s = p; + p += sv.len; + p = memchr(p, '\n', (val->rs.s + val->rs.len) - p); + if(p==NULL) + { + /* last line */ + mv.len = (val->rs.s + val->rs.len) - p; + } else { + mv.len = p - mv.s; + } + val->rs = mv; + goto done; + } + p = memchr(p, '\n', (val->rs.s + val->rs.len) - p); + } while(p && ((++p)<=val->rs.s+val->rs.len-sv.len)); + val->rs = _tr_empty; + break; + + case TR_LINE_AT: + if(tp==NULL) + { + LM_ERR("name invalid parameters\n"); + return -1; + } + + if(tp->type==TR_PARAM_NUMBER) + { + n = tp->v.n; + } else { + if(pv_get_spec_value(msg, (pv_spec_p)tp->v.data, &v)!=0 + || (!(v.flags&PV_VAL_INT))) + { + LM_ERR("name cannot get p1\n"); + return -1; + } + n = v.ri; + } + if(n<0) + { + p = val->rs.s + val->rs.len - 1; + if(*p=='\n') + p--; + mv.s = p; + n = -n; + i=1; + p = memfindrchr(val->rs.s, '\n', p - val->rs.s); + if(p!=NULL) + p--; + while(i<n && p) + { + mv.s = p; + p = memfindrchr(val->rs.s, '\n', p - val->rs.s); + if(p!=NULL) + p--; + i++; + } + if(i==n) + { + if(p==NULL) + { + /* first line */ + mv.len = mv.s - val->rs.s + 1; + mv.s = val->rs.s; + } else { + mv.len = mv.s - p - 1; + mv.s = p + 2; + } + val->rs = mv; + goto done; + } + } else { + p = val->rs.s; + i = 0; + while(i<n && p) + { + p = memchr(p, '\n', (val->rs.s + val->rs.len) - p); + if(p!=NULL) + p++; + i++; + } + if(i==n && p!=NULL) + { + /* line found */ + mv.s = p; + p = memchr(p, '\n', (val->rs.s + val->rs.len) - p); + if(p==NULL) + { + /* last line */ + mv.len = (val->rs.s + val->rs.len) - p; + } else { + mv.len = p - mv.s; + } + val->rs = mv; + goto done; + } + } + val->rs = _tr_empty; + break; + + case TR_LINE_COUNT: + n=0; + for(i=0; i<val->rs.len; i++) + if(val->rs.s[i]=='\n') + n++; + if(n==0 && val->rs.len>0) + n = 1; + val->flags = PV_TYPE_INT|PV_VAL_INT|PV_VAL_STR; + val->ri = n; + val->rs.s = int2str(val->ri, &val->rs.len); + break; + + break; + + default: + LM_ERR("unknown subtype %d\n", + subtype); + return -1; + } +done: + if(val->rs.len>0) + { + /* skip ending '\r' if present */ + if(val->rs.s[val->rs.len-1]=='\r') + val->rs.len--; + } + val->flags = PV_VAL_STR; + return 0; +} +
#define _tr_parse_nparam(_p, _p0, _tp, _spec, _n, _sign, _in, _s) \ while(is_in_str(_p, _in) && (*_p==' ' || *_p=='\t' || *_p=='\n')) _p++; \ @@ -2113,3 +2309,98 @@ done: t->name = name; return p; } + +/*! + * \brief Helper fuction to parse a line transformation + * \param in parsed string + * \param t transformation + * \return pointer to the end of the transformation in the string - '}', null on error + */ +char* tr_parse_line(str* in, trans_t *t) +{ + char *p; + char *p0; + char *ps; + str s; + str name; + int n; + int sign; + pv_spec_t *spec = NULL; + tr_param_t *tp = NULL; + + + if(in==NULL || t==NULL) + return NULL; + + p = in->s; + name.s = in->s; + t->type = TR_LINE; + t->trf = tr_eval_line; + + /* find next token */ + while(is_in_str(p, in) && *p!=TR_PARAM_MARKER && *p!=TR_RBRACKET) p++; + if(*p=='\0') + { + LM_ERR("invalid transformation: %.*s\n", + in->len, in->s); + goto error; + } + name.len = p - name.s; + trim(&name); + + if(name.len==2 && strncasecmp(name.s, "at", 2)==0) + { + t->subtype = TR_LINE_AT; + if(*p!=TR_PARAM_MARKER) + { + LM_ERR("invalid name transformation: %.*s\n", + in->len, in->s); + goto error; + } + p++; + _tr_parse_nparam(p, p0, tp, spec, n, sign, in, s) + t->params = tp; + tp = 0; + while(is_in_str(p, in) && (*p==' ' || *p=='\t' || *p=='\n')) p++; + if(*p!=TR_RBRACKET) + { + LM_ERR("invalid name transformation: %.*s!\n", + in->len, in->s); + goto error; + } + + goto done; + } else if(name.len==2 && strncasecmp(name.s, "sw", 2)==0) { + t->subtype = TR_LINE_SW; + if(*p!=TR_PARAM_MARKER) + { + LM_ERR("invalid value transformation: %.*s\n", + in->len, in->s); + goto error; + } + p++; + _tr_parse_sparam(p, p0, tp, spec, ps, in, s); + t->params = tp; + tp = 0; + while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++; + if(*p!=TR_RBRACKET) + { + LM_ERR("invalid value transformation: %.*s!\n", + in->len, in->s); + goto error; + } + goto done; + } else if(name.len==5 && strncasecmp(name.s, "count", 5)==0) { + t->subtype = TR_LINE_COUNT; + goto done; + } + + + LM_ERR("unknown transformation: %.*s/%.*s/%d!\n", in->len, in->s, + name.len, name.s, name.len); +error: + return NULL; +done: + t->name = name; + return p; +} diff --git a/modules_k/pv/pv_trans.h b/modules_k/pv/pv_trans.h index 4d77e1d..c660102 100644 --- a/modules_k/pv/pv_trans.h +++ b/modules_k/pv/pv_trans.h @@ -33,7 +33,7 @@
enum _tr_type { TR_NONE=0, TR_STRING, TR_URI, TR_PARAMLIST, TR_NAMEADDR, - TR_TOBODY }; + TR_TOBODY, TR_LINE }; enum _tr_s_subtype { TR_S_NONE=0, TR_S_LEN, TR_S_INT, TR_S_MD5, TR_S_SUBSTR, TR_S_SELECT, TR_S_ENCODEHEXA, TR_S_DECODEHEXA, @@ -58,6 +58,9 @@ enum _tr_tobody_subtype { TR_TOBODY_NONE=0, TR_TOBODY_DISPLAY, TR_TOBODY_URI, TR_TOBODY_TAG, TR_TOBODY_URI_USER, TR_TOBODY_URI_HOST, TR_TOBODY_PARAMS }; +enum _tr_line_subtype { + TR_LINE_NONE=0, TR_LINE_COUNT, TR_LINE_AT, TR_LINE_SW +};
char* tr_parse_string(str *in, trans_t *tr); @@ -65,6 +68,7 @@ char* tr_parse_uri(str *in, trans_t *tr); char* tr_parse_paramlist(str *in, trans_t *tr); char* tr_parse_nameaddr(str *in, trans_t *tr); char* tr_parse_tobody(str* in, trans_t *t); +char* tr_parse_line(str* in, trans_t *t);
int tr_init_buffers(void);