diff --git a/modules/dialplan/dialplan.h b/modules/dialplan/dialplan.h index ea976aad788..cde2c31cb84 100644 --- a/modules/dialplan/dialplan.h +++ b/modules/dialplan/dialplan.h @@ -103,7 +103,7 @@ dpl_id_p select_dpid(int id); struct subst_expr* repl_exp_parse(str subst); void repl_expr_free(struct subst_expr *se); int translate(struct sip_msg *msg, str user_name, str* repl_user, dpl_id_p idp, str *); -int rule_translate(struct sip_msg *msg, str , dpl_node_t * rule, str *); +int rule_translate(struct sip_msg *msg, str , dpl_node_t * rule, pcre *subst_comp, str *); pcre *reg_ex_comp(const char *pattern, int *cap_cnt, int mtype); #endif diff --git a/modules/dialplan/dp_repl.c b/modules/dialplan/dp_repl.c index 1e96ecf3dec..f62d003d009 100644 --- a/modules/dialplan/dp_repl.c +++ b/modules/dialplan/dp_repl.c @@ -37,45 +37,258 @@ #include #include "../../re.h" +#include "../../str_list.h" #include "../../mem/shm_mem.h" #include "dialplan.h" +typedef struct dpl_dyn_pcre +{ + pcre *re; + int cnt; + str expr; + + struct dpl_dyn_pcre * next; /* next rule */ +} dpl_dyn_pcre_t, *dpl_dyn_pcre_p; + +static void dpl_get_avp_val(avp_t *avp, str *dst) { + avp_value_t val; + + if (avp==0 || dst==0) return; -pcre *dpl_dynamic_pcre(sip_msg_t *msg, str *expr, int *cap_cnt) + /* Warning! it uses static buffer from int2str !!! */ + + get_avp_val(avp, &val); + if (avp->flags & AVP_VAL_STR) { + *dst = val.s; + } + else { /* probably (!) number */ + dst->s = int2str(val.n, &dst->len); + } +} + +int dpl_dyn_printf_s(sip_msg_t *msg, const pv_elem_p elem, + const pv_elem_p avp_elem, str *val, pv_elem_p *elem_prev, str *vexpr) +{ + pv_elem_p e = NULL; + pv_elem_p t = NULL; + str s = STR_NULL; + int ret = -1; + + if(elem==NULL||avp_elem==NULL||elem_prev==NULL) return -1; + if(str_append(&(avp_elem->text), val, &s)<0) return -1; + + if(pv_parse_format(&s, &e)<0) { + LM_ERR("parsing expression: %.*s\n", s.len, s.s); + goto clean; + } + if(*elem_prev==NULL && elem!=avp_elem) { + LM_DBG("search for elem_prev\n"); + for(t=elem; t!=NULL; t=t->next) { + if(t->next==avp_elem) { *elem_prev = t; + LM_DBG("found!\n"); + } + } + } + if(*elem_prev) (*elem_prev)->next = e; + e->next = avp_elem->next; + if(pv_printf_s(msg, e, vexpr)<0){ + LM_ERR("cannot get avp pcre dynamic expression value\n"); + goto clean; + } + ret = 0; +clean: + if(s.s) pkg_free(s.s); + if(e) pkg_free(e); + if(*elem_prev) (*elem_prev)->next = avp_elem; + return ret; +} + +int dpl_get_avp_values(sip_msg_t *msg, const pv_elem_p elem, + const pv_elem_p avp_elem, struct str_list **out) +{ + struct usr_avp *avp = NULL; + unsigned short name_type; + int_str avp_name, avp_value; + struct search_state state; + int sum = 0; + str s = STR_NULL; + str ts = STR_NULL; + pv_elem_p elem_prev = NULL; + struct str_list *tl = NULL; + + if(elem==NULL||avp_elem==NULL||out==NULL||*out==NULL) { + LM_ERR("wrong parameters\n"); + return -1; + } + if(pv_get_avp_name(msg, &(avp_elem->spec->pvp), &avp_name, &name_type)!=0) { + LM_ERR("invalid avp name\n"); + return -1; + } + avp = search_first_avp(name_type, avp_name, &avp_value, &state); + if(avp==NULL) { + LM_ERR("can't find first avp\n"); + return -1; + } + tl = *out; + dpl_get_avp_val(avp, &s); + dpl_dyn_printf_s(msg, elem, avp_elem, &s, &elem_prev, &tl->s); + /*LM_DBG("elem[%p] avp_elem[%p], elem_prev[%p] [%.*s]\n", + elem, avp_elem, elem_prev, tl->s.len, tl->s.s);*/ + sum = tl->s.len; + while ((avp=search_next_avp(&state, &avp_value))!=0) { + dpl_get_avp_val(avp, &s); + dpl_dyn_printf_s(msg, elem, avp_elem, &s, &elem_prev, &ts); + if(append_str_list(ts.s, ts.len, &tl, &sum)==NULL) { + while(*out) { + tl = (*out)->next; + pkg_free(*out); + *out = tl; + } + return -1; + } + /*LM_DBG("elem[%p] avp_elem[%p], elem_prev[%p] [%.*s] out[%p] out->next[%p]\n", + elem, avp_elem, elem_prev, tl->s.len, tl->s.s, + *out, (*out)->next); */ + } + return 0; +} + +int dpl_detect_avp_indx(const pv_elem_p elem, pv_elem_p *avp) +{ + int num, num_avp_all; + pv_elem_p e = elem;; + if(elem==NULL||avp==NULL) return -1; + + for(e=elem, num=num_avp_all=0; e!=NULL; e=e->next, num++) { + if(e->spec!=NULL && e->spec->type==PVT_AVP && + e->spec->pvp.pvi.type==PV_IDX_ITR) + { + *avp = e; + num_avp_all++; + } + } + if(num_avp_all==1) return 1; /* just one avp_indx supported */ + return 0; +} + +pcre *dpl_dyn_pcre_comp(sip_msg_t *msg, str *expr, str *vexpr, int *cap_cnt) { - pv_elem_t *pelem = NULL; pcre *re = NULL; int ccnt = 0; - str vexpr; - if(expr==NULL || expr->s==NULL || expr->len<=0) + if(expr==NULL || expr->s==NULL || expr->len<=0 || + vexpr==NULL || vexpr->s==NULL || vexpr->len<=0) return NULL; - if(pv_parse_format(expr, &pelem)<0){ - LM_ERR("parsing pcre expression: %.*s\n", - expr->len, expr->s); + re = reg_ex_comp(vexpr->s, &ccnt, 1); + if(!re) { + if(expr!=vexpr) + LM_ERR("failed to compile pcre expression: %.*s (%.*s)\n", + expr->len, expr->s, vexpr->len, vexpr->s); + else + LM_ERR("failed to compile pcre expression: %.*s\n", + vexpr->len, vexpr->s); return NULL; } - if(pv_printf_s(msg, pelem, &vexpr)<0){ - LM_ERR("cannot get pcre dynamic expression value: %.*s\n", - expr->len, expr->s); - pv_elem_free_all(pelem); + if(cap_cnt) { + *cap_cnt = ccnt; + } + if(expr!=vexpr) + LM_DBG("compiled dynamic pcre expression: %.*s (%.*s) %d\n", + expr->len, expr->s, vexpr->len, vexpr->s, ccnt); + else + LM_DBG("compiled dynamic pcre expression: %.*s %d\n", + vexpr->len, vexpr->s, ccnt); + return re; +} + +dpl_dyn_pcre_p dpl_dynamic_pcre_list(sip_msg_t *msg, str *expr) +{ + pv_elem_p elem = NULL; + pv_elem_p avp_elem = NULL; + dpl_dyn_pcre_p re_list = NULL; + dpl_dyn_pcre_p rt = NULL; + struct str_list *l = NULL; + struct str_list *t = NULL; + pcre *re = NULL; + int cnt = 0; + str vexpr = STR_NULL; + + if(expr==NULL || expr->s==NULL || expr->len<=0) + { + LM_ERR("wrong parameters\n"); return NULL; } - pv_elem_free_all(pelem); - re = reg_ex_comp(vexpr.s, &ccnt, 1); - if(!re) { - LM_ERR("failed to compile pcre expression: %.*s (%.*s)\n", - expr->len, expr->s, vexpr.len, vexpr.s); + if(pv_parse_format(expr, &elem)<0) { + LM_ERR("parsing pcre expression: %.*s\n", + expr->len, expr->s); return NULL; } - if(cap_cnt) { - *cap_cnt = ccnt; + LM_DBG("parsed pcre expression: %.*s\n", expr->len, expr->s); + if(dpl_detect_avp_indx(elem, &avp_elem)) { + l = pkg_malloc(sizeof(struct str_list)); + if(l==NULL) { + PKG_MEM_ERROR; + return NULL; + } + memset(l, 0, sizeof(struct str_list)); + if(dpl_get_avp_values(msg, elem, avp_elem, &l)<0) { + LM_ERR("can't get list of avp values\n"); + goto error; + } + t = l; + while(t) { + re = dpl_dyn_pcre_comp(msg, &(t->s), &(t->s), &cnt); + if(re!=NULL) { + rt = pkg_malloc(sizeof(dpl_dyn_pcre_t)); + if(rt==NULL) { + PKG_MEM_ERROR; + goto error; + } + rt->re = re; + rt->expr.s = t->s.s; + rt->expr.len = t->s.len; + rt->cnt = cnt; + rt->next = re_list; + re_list = rt; + } + t = t->next; + } } - LM_DBG("compiled dynamic pcre expression: %.*s (%.*s) %d\n", - expr->len, expr->s, vexpr.len, vexpr.s, ccnt); - return re; + else { + if(pv_printf_s(msg, elem, &vexpr)<0){ + LM_ERR("cannot get pcre dynamic expression value: %.*s\n", + expr->len, expr->s); + goto error; + } + re = dpl_dyn_pcre_comp(msg, expr, &vexpr, &cnt); + if(re!=NULL) { + rt = pkg_malloc(sizeof(dpl_dyn_pcre_t)); + if(rt==NULL) { + PKG_MEM_ERROR; + goto error; + } + rt->re = re; + rt->expr.s = expr->s; + rt->expr.len = expr->len; + rt->cnt = cnt; + rt->next = re_list; + re_list = rt; + } + } + goto clean; +error: + while(re_list) { + rt = re_list->next; + if(re_list->re) pcre_free(re_list->re); + pkg_free(re_list); + re_list = rt; + } +clean: + if(elem) pv_elem_free_all(elem); + while(l) { t = l->next; pkg_free(l); l = t;} + return re_list; } void repl_expr_free(struct subst_expr *se) @@ -161,14 +374,14 @@ struct subst_expr* repl_exp_parse(str subst) } + #define MAX_PHONE_NB_DIGITS 127 static char dp_output_buf[MAX_PHONE_NB_DIGITS+1]; int rule_translate(sip_msg_t *msg, str string, dpl_node_t * rule, - str * result) + pcre *subst_comp, str * result) { int repl_nb, offset, match_nb, rc, cap_cnt; struct replace_with token; - pcre *subst_comp; struct subst_expr * repl_comp; str match; pv_value_t sv; @@ -181,24 +394,12 @@ int rule_translate(sip_msg_t *msg, str string, dpl_node_t * rule, result->s = dp_output_buf; result->len = 0; - repl_comp = rule->repl_comp; + repl_comp = rule->repl_comp; if(!repl_comp){ LM_DBG("null replacement\n"); return 0; } - if(rule->tflags&DP_TFLAGS_PV_SUBST) { - subst_comp = dpl_dynamic_pcre(msg, &rule->subst_exp, &cap_cnt); - if (cap_cnt > MAX_REPLACE_WITH) { - LM_ERR("subst expression %.*s has too many sub-expressions\n", - rule->subst_exp.len, rule->subst_exp.s); - if(subst_comp) pcre_free(subst_comp); - return -1; - } - } else { - subst_comp = rule->subst_comp; - } - if(subst_comp){ /*just in case something went wrong at load time*/ rc = pcre_fullinfo(subst_comp, NULL, PCRE_INFO_CAPTURECOUNT, @@ -206,13 +407,16 @@ int rule_translate(sip_msg_t *msg, str string, dpl_node_t * rule, if (rc != 0) { LM_ERR("pcre_fullinfo on compiled pattern yielded error: %d\n", rc); - if(rule->tflags&DP_TFLAGS_PV_SUBST) pcre_free(subst_comp); return -1; } if(repl_comp->max_pmatch > cap_cnt){ LM_ERR("illegal access to %i-th subexpr of subst expr (max %d)\n", repl_comp->max_pmatch, cap_cnt); - if(rule->tflags&DP_TFLAGS_PV_SUBST) pcre_free(subst_comp); + return -1; + } + if (rule->tflags&DP_TFLAGS_PV_SUBST && (cap_cnt > MAX_REPLACE_WITH)) { + LM_ERR("subst expression %.*s has too many sub-expressions\n", + rule->subst_exp.len, rule->subst_exp.s); return -1; } @@ -224,7 +428,6 @@ int rule_translate(sip_msg_t *msg, str string, dpl_node_t * rule, string.len, string.s, rule->match_exp.len, rule->match_exp.s, rule->subst_exp.len, rule->subst_exp.s); - if(rule->tflags&DP_TFLAGS_PV_SUBST) pcre_free(subst_comp); return -1; } } @@ -241,7 +444,6 @@ int rule_translate(sip_msg_t *msg, str string, dpl_node_t * rule, repl_comp->replacement.len); result->len = repl_comp->replacement.len; result->s[result->len] = '\0'; - if(rule->tflags&DP_TFLAGS_PV_SUBST) pcre_free(subst_comp); return 0; } @@ -351,12 +553,9 @@ int rule_translate(sip_msg_t *msg, str string, dpl_node_t * rule, } result->s[result->len] = '\0'; - if(rule->tflags&DP_TFLAGS_PV_SUBST) pcre_free(subst_comp); return 0; error: - if((rule->tflags&DP_TFLAGS_PV_SUBST) && subst_comp!=NULL) - pcre_free(subst_comp); result->s = 0; result->len = 0; return -1; @@ -371,7 +570,8 @@ int translate(sip_msg_t *msg, str input, str *output, dpl_id_p idp, dpl_index_p indexp; int user_len, rez; char b; - pcre *match_re; + dpl_dyn_pcre_p re_list = NULL; + dpl_dyn_pcre_p rt = NULL; if(!input.s || !input.len) { LM_ERR("invalid input string\n"); @@ -396,18 +596,31 @@ int translate(sip_msg_t *msg, str input, str *output, dpl_id_p idp, LM_DBG("regex operator testing over [%.*s]\n", input.len, input.s); if(rulep->tflags&DP_TFLAGS_PV_MATCH) { - match_re = dpl_dynamic_pcre(msg, &rulep->match_exp, NULL); - if(match_re==NULL) { + re_list = dpl_dynamic_pcre_list(msg, &rulep->match_exp); + if(re_list==NULL) { /* failed to compile dynamic pcre -- ignore */ + LM_DBG("failed to compile dynamic pcre[%.*s]\n", + rulep->match_exp.len, rulep->match_exp.s); continue; } + rez = -1; + do { + if(rez<0) { + rez = pcre_exec(re_list->re, NULL, input.s, input.len, + 0, 0, NULL, 0); + LM_DBG("match check: [%.*s] %d\n", + re_list->expr.len, re_list->expr.s, rez); + } + else LM_DBG("match check skipped: [%.*s] %d\n", + re_list->expr.len, re_list->expr.s, rez); + rt = re_list->next; + pcre_free(re_list->re); + pkg_free(re_list); + re_list = rt; + } while(re_list); } else { - match_re = rulep->match_comp; - } - rez = pcre_exec(match_re, NULL, input.s, input.len, + rez = pcre_exec(rulep->match_comp, NULL, input.s, input.len, 0, 0, NULL, 0); - if(rulep->tflags&DP_TFLAGS_PV_MATCH) { - pcre_free(match_re); } break; @@ -472,11 +685,34 @@ int translate(sip_msg_t *msg, str input, str *output, dpl_id_p idp, attrs->len, attrs->s); } } - - if(rule_translate(msg, input, rulep, output)!=0){ - LM_ERR("could not build the output\n"); - return -1; + if(rulep->tflags&DP_TFLAGS_PV_SUBST) { + re_list = dpl_dynamic_pcre_list(msg, &rulep->match_exp); + if(re_list==NULL) { + /* failed to compile dynamic pcre -- ignore */ + LM_DBG("failed to compile dynamic pcre[%.*s]\n", + rulep->subst_exp.len, rulep->subst_exp.s); + return -1; + } + rez = -1; + do { + if(rez<0) { + rez = rule_translate(msg, input, rulep, re_list->re, output); + LM_DBG("subst check: [%.*s] %d\n", + re_list->expr.len, re_list->expr.s, rez); + } + else LM_DBG("subst check skipped: [%.*s] %d\n", + re_list->expr.len, re_list->expr.s, rez); + rt = re_list->next; + pcre_free(re_list->re); + pkg_free(re_list); + re_list = rt; + } while(re_list); + } + else { + if(rule_translate(msg, input, rulep, rulep->subst_comp, output)!=0){ + LM_ERR("could not build the output\n"); + return -1; + } } - return 0; } diff --git a/pvapi.c b/pvapi.c index 710b460b8ee..ccf981475e1 100644 --- a/pvapi.c +++ b/pvapi.c @@ -667,6 +667,11 @@ int pv_parse_index(pv_spec_p sp, str *in) sp->pvp.pvi.type = PV_IDX_ALL; return 0; } + if(*p=='+' && in->len==1) + { + sp->pvp.pvi.type = PV_IDX_ITR; + return 0; + } sign = 1; if(*p=='-') { @@ -1225,7 +1230,10 @@ int pv_get_spec_index(struct sip_msg* msg, pv_param_p ip, int *idx, int *flags) *flags = PV_IDX_ALL; return 0; } - + if(ip->pvi.type == PV_IDX_ITR) { + *flags = PV_IDX_ITR; + return 0; + } if(ip->pvi.type == PV_IDX_INT) { *idx = ip->pvi.u.ival; diff --git a/pvar.h b/pvar.h index 601f0efba6b..da138062313 100644 --- a/pvar.h +++ b/pvar.h @@ -60,6 +60,7 @@ #define PV_IDX_INT 0 #define PV_IDX_PVAR 1 #define PV_IDX_ALL 2 +#define PV_IDX_ITR 3 /*! if PV name is dynamic, integer, or str */ #define pv_has_dname(pv) ((pv)->pvp.pvn.type==PV_NAME_PVAR)