/** fparam_t free function. * Frees the "content" of a fparam, but not the fparam itself. * Note: it doesn't free fp->orig! * Assumes pkg_malloc'ed content. * @param fp - fparam to be freed * */ void fparam_free_contents(fparam_t* fp) { if (fp==0) return; switch(fp->type) { case FPARAM_UNSPEC: case FPARAM_STRING: /* asciiz string, not str */ case FPARAM_INT: case FPARAM_STR: /* nothing to do */ break; case FPARAM_REGEX: if (fp->v.regex){ regfree(fp->v.regex); pkg_free(fp->v.regex); fp->v.regex=0; } break; case FPARAM_AVP: free_avp_name(&fp->v.avp.flags, &fp->v.avp.name); break; case FPARAM_SELECT: if (fp->v.select){ free_select(fp->v.select); fp->v.select=0; } break; case FPARAM_SUBST: if (fp->v.subst){ subst_expr_free(fp->v.subst); fp->v.subst=0; } break; case FPARAM_PVS: if (fp->v.pvs){ pv_spec_free(fp->v.pvs); fp->v.pvs=0; } break; case FPARAM_PVE: if (fp->v.pve){ pv_elem_free_all(fp->v.pve); fp->v.pve=0; } break; } }
int tr_txt_eval_re(struct sip_msg *msg, tr_param_t *tp, int subtype, pv_value_t *val) { struct subst_expr *se = NULL; int nmatches; str* result; #define TR_TXT_BUF_SIZE 2048 static char tr_txt_buf[TR_TXT_BUF_SIZE]; pv_value_t v; if(val==NULL || (!(val->flags&PV_VAL_STR)) || val->rs.len<=0) return -1; switch(subtype) { case TR_TXT_RE_SUBST: if (tp->type == TR_PARAM_SUBST) { se = (struct subst_expr*)tp->v.data; if (se==NULL) return 0; } else if (tp->type == TR_PARAM_SPEC) { 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("Can't evaluate regexp\n"); return -1; } se=subst_parser(&v.rs); if (se==0) { LM_ERR("Can't compile regexp\n"); return -1; } } else { LM_ERR("Unknown parameter type\n"); return -1; } if(val->rs.len>=TR_TXT_BUF_SIZE-1) { LM_ERR("PV value too big %d, increase buffer size\n", val->rs.len); goto error; } memcpy(tr_txt_buf, val->rs.s, val->rs.len); tr_txt_buf[val->rs.len] = '\0'; /* pkg malloc'ed result */ result=subst_str(tr_txt_buf, msg, se, &nmatches); if (result == NULL) { if (nmatches==0) { LM_DBG("no match for subst expression\n"); break; } if (nmatches<0) LM_ERR("subst failed\n"); goto error; } if(result->len>=TR_TXT_BUF_SIZE-1) { LM_ERR("subst result too big %d, increase buffer size\n", result->len); goto error; } memcpy(tr_txt_buf, result->s, result->len); tr_txt_buf[result->len] = '\0'; memset(val, 0, sizeof(pv_value_t)); val->flags = PV_VAL_STR; val->rs.s = tr_txt_buf; val->rs.len = result->len; pkg_free(result->s); pkg_free(result); break; default: LM_ERR("unknown subtype %d\n", subtype); goto error; } if (tp->type == TR_PARAM_SPEC) { subst_expr_free(se); } return 0; error: if (tp->type == TR_PARAM_SPEC) { subst_expr_free(se); } return -1; }
char* tr_txt_parse_re(str *in, trans_t *t) { char *p; str name; str tok; struct subst_expr *se = NULL; tr_param_t *tp = NULL; int n; pv_spec_t *spec = NULL; if(in==NULL || t==NULL) return NULL; p = in->s; name.s = in->s; t->type = TR_TXT_RE; t->trf = tr_txt_eval_re; /* find next token */ while(is_in_str(p, in) && *p!=TR_PARAM_MARKER && *p!=TR_RBRACKET) p++; if(*p=='\0') goto error; name.len = p - name.s; trim(&name); if(name.len==5 && strncasecmp(name.s, "subst", 5)==0) { t->subtype = TR_TXT_RE_SUBST; if(*p!=TR_PARAM_MARKER) goto error; p++; if(*p==PV_MARKER) { spec = (pv_spec_t*)pkg_malloc(sizeof(pv_spec_t)); if(spec==NULL) { LM_ERR("no more private memory!\n"); return 0; } tok.s = p; tok.len = in->s + in->len - p; p = pv_parse_spec(&tok, spec); if(p==NULL) { LM_ERR("invalid pv spec in transformation: %.*s!\n", in->len, in->s); pkg_free(spec); return 0; } tp = (tr_param_t*)pkg_malloc(sizeof(tr_param_t)); if(tp==NULL) { LM_ERR("no more private memory!\n"); pkg_free(spec); goto error; } tp->type = TR_PARAM_SPEC; tp->v.data = (void*)spec; } else { /* get trans here */ n = 0; tok.s = p; while(is_in_str(p, in)) { if(*p==TR_RBRACKET) { if(n==0) break; n--; } if(*p == TR_LBRACKET) n++; p++; } if(!is_in_str(p, in)) goto error; if(p==tok.s) goto error; tok.len = p - tok.s; tp = (tr_param_t*)pkg_malloc(sizeof(tr_param_t)); if(tp==NULL) { LM_ERR("no more private memory!\n"); goto error; } se=subst_parser(&tok); if (se==0) goto error; tp->type = TR_PARAM_SUBST; tp->v.data = (void*)se; } t->params = tp; while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++; if(*p!=TR_RBRACKET) goto error; goto done; } LM_ERR("unknown transformation: %.*s/%.*s/%d!\n", in->len, in->s, name.len, name.s, name.len); error: LM_ERR("invalid transformation [%.*s] <%d>\n", in->len, in->s, (int)(p-in->s)); if(tp!=NULL) pkg_free(tp); if(se!=NULL) subst_expr_free(se); return NULL; done: t->name = name; return p; }
/* parse a /regular expression/replacement/flags into a subst_expr structure */ struct subst_expr* subst_parser(str* subst) { #define MAX_REPLACE_WITH 100 char c; char* end; char* p; char* re; char* re_end; char* repl; char* repl_end; struct replace_with rw[MAX_REPLACE_WITH]; int rw_no; int escape; int cflags; /* regcomp flags */ int replace_all; struct subst_expr* se; regex_t* regex; int max_pmatch; int r; /* init */ se=0; regex=0; cflags=REG_EXTENDED | REG_NEWLINE; /* don't match newline */ replace_all=0; if (subst->len<3){ LOG(L_ERR, "ERROR: subst_parser: expression is too short: %.*s\n", subst->len, subst->s); goto error; } p=subst->s; c=*p; if (c=='\\'){ LOG(L_ERR, "ERROR: subst_parser: invalid separator char <%c>" " in %.*s\n", c, subst->len, subst->s); goto error; } p++; end=subst->s+subst->len; /* find re */ re=p; for (;p<end;p++){ /* if unescaped sep. char */ if ((*p==c) && (*(p-1)!='\\')) goto found_re; } LOG(L_ERR, "ERROR: subst_parser: no separator found: %.*s\n", subst->len, subst->s); goto error; found_re: re_end=p; p++; /* parse replacement */ repl=p; rw_no=0; max_pmatch=0; escape=0; for(;p<end; p++){ if (escape){ escape=0; switch (*p){ /* special char escapes */ case '\\': rw[rw_no].size=2; rw[rw_no].offset=(p-1)-repl; rw[rw_no].type=REPLACE_CHAR; rw[rw_no].u.c='\\'; break; case 'n': rw[rw_no].size=2; rw[rw_no].offset=(p-1)-repl; rw[rw_no].type=REPLACE_CHAR; rw[rw_no].u.c='\n'; break; case 'r': rw[rw_no].size=2; rw[rw_no].offset=(p-1)-repl; rw[rw_no].type=REPLACE_CHAR; rw[rw_no].u.c='\r'; break; case 't': rw[rw_no].size=2; rw[rw_no].offset=(p-1)-repl; rw[rw_no].type=REPLACE_CHAR; rw[rw_no].u.c='\t'; break; /* special sip msg parts escapes */ case 'u': rw[rw_no].size=2; rw[rw_no].offset=(p-1)-repl; rw[rw_no].type=REPLACE_URI; break; /* re matches */ case '0': /* allow 0, too, reference to the whole match */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': rw[rw_no].size=2; rw[rw_no].offset=(p-1)-repl; rw[rw_no].type=REPLACE_NMATCH; rw[rw_no].u.nmatch=(*p)-'0';/* 0 is the whole matched str*/ if (max_pmatch<rw[rw_no].u.nmatch) max_pmatch=rw[rw_no].u.nmatch; break; default: /* just print current char */ if (*p!=c){ LOG(L_WARN, "subst_parser: WARNING: \\%c unknown" " escape in %.*s\n", *p, subst->len, subst->s); } rw[rw_no].size=2; rw[rw_no].offset=(p-1)-repl; rw[rw_no].type=REPLACE_CHAR; rw[rw_no].u.c=*p; break; } rw_no++; if (rw_no>=MAX_REPLACE_WITH){ LOG(L_ERR, "ERROR: subst_parser: too many escapes in the" " replace part %.*s\n", subst->len, subst->s); goto error; } }else if (*p=='\\') escape=1; else if (*p==c) goto found_repl; } LOG(L_ERR, "ERROR: subst_parser: missing separator: %.*s\n", subst->len, subst->s); goto error; found_repl: repl_end=p; p++; /* parse flags */ for(;p<end; p++){ switch(*p){ case 'i': cflags|=REG_ICASE; break; case 's': cflags&=(~REG_NEWLINE); break; case 'g': replace_all=1; break; default: LOG(L_ERR, "ERROR: subst_parser: unknown flag %c in %.*s\n", *p, subst->len, subst->s); goto error; } } /* compile the re */ if ((regex=pkg_malloc(sizeof(regex_t)))==0){ LOG(L_ERR, "ERROR: subst_parser: out of memory (re)\n"); goto error; } c=*re_end; /* regcomp expects null terminated strings -- save */ *re_end=0; if (regcomp(regex, re, cflags)!=0){ pkg_free(regex); *re_end=c; /* restore */ LOG(L_ERR, "ERROR: subst_parser: bad regular expression %.*s in " "%.*s\n", (int)(re_end-re), re, subst->len, subst->s); goto error; } *re_end=c; /* restore */ /* construct the subst_expr structure */ se=pkg_malloc(sizeof(struct subst_expr)+ ((rw_no)?(rw_no-1)*sizeof(struct replace_with):0)); /* 1 replace_with structure is already included in subst_expr */ if (se==0){ LOG(L_ERR, "ERROR: subst_parser: out of memory (subst_expr)\n"); goto error; } memset((void*)se, 0, sizeof(struct subst_expr)); se->replacement.len=repl_end-repl; if ((se->replacement.s=pkg_malloc(se->replacement.len))==0){ LOG(L_ERR, "ERROR: subst_parser: out of memory (replacement)\n"); goto error; } /* start copying */ memcpy(se->replacement.s, repl, se->replacement.len); se->re=regex; se->replace_all=replace_all; se->n_escapes=rw_no; se->max_pmatch=max_pmatch; for (r=0; r<rw_no; r++) se->replace[r]=rw[r]; DBG("subst_parser: ok, se is %p\n", se); return se; error: if (se) { subst_expr_free(se); regex=0; } if (regex) { regfree (regex); pkg_free(regex); } return 0; }
/*! \brief Parse a /regular expression/replacement/flags into a subst_expr structure */ struct subst_expr* subst_parser(str* subst) { char c; char* end; char* p; char* re; char* re_end; char* repl; char* repl_end; struct replace_with rw[MAX_REPLACE_WITH]; int rw_no; //int escape; int cflags; /* regcomp flags */ int replace_all; struct subst_expr* se; regex_t* regex; int max_pmatch; int r; /* init */ se=0; regex=0; cflags=REG_EXTENDED | REG_NEWLINE; /* don't match newline */ replace_all=0; if (subst->len<3){ LM_ERR("expression is too short: %.*s\n", subst->len, subst->s); goto error; } p=subst->s; end=subst->s+subst->len; c=*p; if (c=='\\'){ LM_ERR("invalid separator char <%c> in %.*s\n", c, subst->len, subst->s); goto error; } p++; /* find re */ re=p; for (;p<end;p++){ /* if unescaped sep. char */ if ((*p==c) && (*(p-1)!='\\')) goto found_re; } LM_ERR("no separator found: %.*s\n", subst->len, subst->s); goto error; found_re: re_end=p; if(end< (p+2) ){ LM_ERR("string too short\n"); goto error; } repl=p+1; if((rw_no = parse_repl(rw, &p, end, &max_pmatch, WITH_SEP))< 0) goto error; repl_end=p; p++; /* parse flags */ for(;p<end; p++){ switch(*p){ case 'i': cflags|=REG_ICASE; break; case 's': cflags&=(~REG_NEWLINE); break; case 'g': replace_all=1; break; default: LM_ERR("unknown flag %c in %.*s\n", *p, subst->len, subst->s); goto error; } } /* compile the re */ if ((regex=pkg_malloc(sizeof(regex_t)))==0){ LM_ERR("out of pkg memory (re)\n"); goto error; } c=*re_end; /* regcomp expects null terminated strings -- save */ *re_end=0; if (regcomp(regex, re, cflags)!=0){ pkg_free(regex); *re_end=c; /* restore */ LM_ERR("bad regular expression %.*s in %.*s\n", (int)(re_end-re), re, subst->len, subst->s); goto error; } *re_end=c; /* restore */ /* construct the subst_expr structure */ se=pkg_malloc(sizeof(struct subst_expr)+ ((rw_no)?(rw_no-1)*sizeof(struct replace_with):0)); /* 1 replace_with structure is already included in subst_expr */ if (se==0){ LM_ERR("out of pkg memory (subst_expr)\n"); goto error; } memset((void*)se, 0, sizeof(struct subst_expr)); se->replacement.len=repl_end-repl; if ((se->replacement.s=pkg_malloc(se->replacement.len))==0){ LM_ERR("out of pkg memory (replacement)\n"); goto error; } /* start copying */ memcpy(se->replacement.s, repl, se->replacement.len); se->re=regex; se->replace_all=replace_all; se->n_escapes=rw_no; se->max_pmatch=max_pmatch; for (r=0; r<rw_no; r++) se->replace[r]=rw[r]; LM_DBG("ok, se is %p\n", se); return se; error: if (se) { subst_expr_free(se); regex=0; } if (regex) { regfree (regex); pkg_free(regex); } return 0; }
static int fixup_free_substre(void** param) { subst_expr_free(*param); return 0; }