dp_repl.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dp_repl.c 5469 2009-01-14 18:25:19Z miconda $
00003  *
00004  * Copyright (C) 2007-2008 Voice Sistem SRL
00005  *
00006  * Copyright (C) 2008 Juha Heinanen
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  * History:
00025  * --------
00026  *  2007-08-01 initial version (ancuta onofrei)
00027  */
00028 
00029 #include "../../re.h"
00030 #include "../../mem/shm_mem.h"
00031 #include "dialplan.h"
00032 
00033 
00034 void repl_expr_free(struct subst_expr *se)
00035 {
00036     if(!se)
00037       return;
00038 
00039    if(se->replacement.s){
00040       shm_free(se->replacement.s);
00041       se->replacement.s = 0;
00042    }
00043 
00044    shm_free(se);
00045    se = 0;
00046 }
00047 
00048 
00049 struct subst_expr* repl_exp_parse(str subst)
00050 {
00051    struct replace_with rw[MAX_REPLACE_WITH];
00052    int rw_no;
00053    struct subst_expr * se;
00054    int replace_all;
00055    char * p, *end, *repl, *repl_end;
00056    int max_pmatch, r;
00057 
00058    se = 0;
00059    replace_all = 0;
00060    p = subst.s;
00061    end = p + subst.len;
00062    rw_no = 0;
00063 
00064    repl = p;
00065    if((rw_no = parse_repl(rw, &p, end, &max_pmatch, WITHOUT_SEP))< 0)
00066       goto error;
00067    
00068    repl_end=p;
00069 
00070     /* construct the subst_expr structure */
00071    se = shm_malloc(sizeof(struct subst_expr)+
00072          ((rw_no)?(rw_no-1)*sizeof(struct replace_with):0));
00073    /* 1 replace_with structure is  already included in subst_expr */
00074    if (se==0){
00075       LM_ERR("out of shm memory (subst_expr)\n");
00076       goto error;
00077    }
00078    memset((void*)se, 0, sizeof(struct subst_expr));
00079 
00080    se->replacement.len=repl_end-repl;
00081    if (!(se->replacement.s=shm_malloc(se->replacement.len * sizeof(char))) ){
00082       LM_ERR("out of shm memory \n");
00083       goto error;
00084    }
00085    if(!rw_no){
00086       replace_all = 1;
00087    }
00088    /* start copying */
00089    memcpy(se->replacement.s, repl, se->replacement.len);
00090    se->re=0;
00091    se->replace_all=replace_all;
00092    se->n_escapes=rw_no;
00093    se->max_pmatch=max_pmatch;
00094 
00095     /*replace_with is a simple structure, no shm alloc needed*/
00096    for (r=0; r<rw_no; r++) se->replace[r]=rw[r];
00097    return se;
00098 
00099 error:
00100    if (se) { repl_expr_free(se);}
00101    return NULL;
00102 }
00103 
00104 
00105 #define MAX_PHONE_NB_DIGITS      127
00106 static char dp_output_buf[MAX_PHONE_NB_DIGITS+1];
00107 int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
00108          str * result)
00109 {
00110    int repl_nb, offset, match_nb, rc, cap_cnt;
00111    struct replace_with token;
00112    pcre *subst_comp;
00113    struct subst_expr * repl_comp;
00114    str match;
00115    pv_value_t sv;
00116    str* uri;
00117    int ovector[3 * (MAX_REPLACE_WITH + 1)];
00118 
00119    dp_output_buf[0] = '\0';
00120    result->s = dp_output_buf;
00121    result->len = 0;
00122 
00123    subst_comp  = rule->subst_comp;
00124    repl_comp   = rule->repl_comp;
00125 
00126    if(!repl_comp){
00127       LM_DBG("null replacement\n");
00128       return 0;
00129    }
00130 
00131    if(subst_comp){
00132       /*just in case something went wrong at load time*/
00133       rc = pcre_fullinfo(subst_comp, NULL, PCRE_INFO_CAPTURECOUNT,
00134             &cap_cnt);
00135       if (rc != 0) {
00136          LM_ERR("pcre_fullinfo on compiled pattern yielded error: %d\n",
00137             rc);
00138          return -1;;
00139       }
00140       if(repl_comp->max_pmatch > cap_cnt){
00141          LM_ERR("illegal access to the %i-th subexpr of the subst expr\n",
00142             repl_comp->max_pmatch);
00143          return -1;
00144       }
00145 
00146       /*search for the pattern from the compiled subst_exp*/
00147       if (pcre_exec(rule->subst_comp, NULL, string.s, string.len,
00148             0, 0, ovector, 3 * (MAX_REPLACE_WITH + 1)) <= 0) {
00149          LM_ERR("the string %.*s matched "
00150             "the match_exp %.*s but not the subst_exp %.*s!\n", 
00151             string.len, string.s, 
00152             rule->match_exp.len, rule->match_exp.s,
00153             rule->subst_exp.len, rule->subst_exp.s);
00154          return -1;
00155       }
00156    }
00157 
00158    /*simply copy from the replacing string*/
00159    if(!subst_comp || (repl_comp->n_escapes <=0)){
00160       if(!repl_comp->replacement.s || repl_comp->replacement.len == 0){
00161          LM_ERR("invalid replacing string\n");
00162          goto error;
00163       }
00164       LM_DBG("simply replace the string, subst_comp %p, n_escapes %i\n",
00165             subst_comp, repl_comp->n_escapes);
00166       memcpy(result->s, repl_comp->replacement.s,
00167             repl_comp->replacement.len);
00168       result->len = repl_comp->replacement.len;
00169       result->s[result->len] = '\0';
00170       return 0;
00171    }
00172 
00173    /* offset- offset in the replacement string */
00174    result->len = repl_nb = offset = 0;
00175    
00176    while( repl_nb < repl_comp->n_escapes){
00177       token = repl_comp->replace[repl_nb];
00178       
00179       if(offset< token.offset){
00180          if((repl_comp->replacement.len < offset)||
00181             (result->len + token.offset -offset >= MAX_PHONE_NB_DIGITS)){
00182             LM_ERR("invalid length\n");
00183             goto error;
00184          }
00185          /*copy from the replacing string*/
00186          memcpy(result->s + result->len, repl_comp->replacement.s + offset,
00187             token.offset-offset);
00188          result->len += (token.offset - offset);
00189          offset += token.offset-offset; /*update the offset*/
00190       }
00191 
00192       switch(token.type) {
00193          case REPLACE_NMATCH:
00194             /*copy from the match subexpression*/  
00195             match_nb = token.u.nmatch * 2;
00196             match.s =  string.s + ovector[match_nb];
00197             match.len = ovector[match_nb + 1] - ovector[match_nb];
00198             if(result->len + match.len >= MAX_PHONE_NB_DIGITS){
00199                LM_ERR("overflow\n");
00200                goto error;
00201             }
00202 
00203             memcpy(result->s + result->len, match.s, match.len);
00204             result->len += match.len;
00205             offset += token.size; /*update the offset*/
00206          break;
00207          case REPLACE_CHAR:
00208             if(result->len + 1>= MAX_PHONE_NB_DIGITS){
00209                LM_ERR("overflow\n");
00210                goto error;
00211             }
00212             *result->s=repl_comp->replace[repl_nb].u.c;
00213             result->len++;
00214          break;
00215          case REPLACE_URI: 
00216             if ( msg== NULL || msg->first_line.type!=SIP_REQUEST){
00217                LM_CRIT("uri substitution attempt on no request"
00218                   " message\n");
00219                break; /* ignore, we can continue */
00220             }
00221             uri= (msg->new_uri.s)?(&msg->new_uri):
00222                (&msg->first_line.u.request.uri);
00223             if(result->len+uri->len>=MAX_PHONE_NB_DIGITS){
00224                LM_ERR("overflow\n");
00225                goto error;
00226             }
00227             memcpy(result->s + result->len, uri->s, uri->len);
00228             result->len+=uri->len;
00229          break;
00230          case REPLACE_SPEC:
00231             if (msg== NULL) {
00232                LM_DBG("replace spec attempted on no message\n");
00233                break;
00234             }
00235             if(pv_get_spec_value(msg, 
00236                   &repl_comp->replace[repl_nb].u.spec, &sv)!=0){
00237                LM_CRIT("item substitution returned error\n");
00238                break; /* ignore, we can continue */
00239             }
00240             if(result->len+sv.rs.len>=MAX_PHONE_NB_DIGITS){
00241                LM_ERR("rule_translate: overflow\n");
00242                goto error;
00243             }
00244             memcpy(result->s + result->len, sv.rs.s, sv.rs.len);
00245             result->len+=sv.rs.len;
00246          break;
00247          default:
00248             LM_CRIT("unknown type %d\n", repl_comp->replace[repl_nb].type);
00249             /* ignore it */
00250       }
00251       repl_nb++;
00252    }
00253    result->s[result->len] = '\0';
00254    return 0;
00255 
00256 error:
00257    result->s = 0;
00258    result->len = 0;
00259    return -1;
00260 }
00261 
00262 #define DP_MAX_ATTRS_LEN   32
00263 static char dp_attrs_buf[DP_MAX_ATTRS_LEN+1];
00264 int translate(struct sip_msg *msg, str input, str *output, dpl_id_p idp,
00265          str *attrs)
00266 {
00267    dpl_node_p rulep;
00268    dpl_index_p indexp;
00269    int user_len, rez;
00270    
00271    if(!input.s || !input.len) {
00272       LM_ERR("invalid input string\n");
00273       return -1;
00274    }
00275 
00276    user_len = input.len;
00277    for(indexp = idp->first_index; indexp!=NULL; indexp = indexp->next)
00278       if(!indexp->len || (indexp->len!=0 && indexp->len == user_len) )
00279          break;
00280 
00281    if(!indexp || (indexp!= NULL && !indexp->first_rule)){
00282       LM_DBG("no rule for len %i\n", input.len);
00283       return -1;
00284    }
00285 
00286 search_rule:
00287    for(rulep=indexp->first_rule; rulep!=NULL; rulep= rulep->next) {
00288       switch(rulep->matchop) {
00289 
00290          case REGEX_OP:
00291              LM_DBG("regex operator testing\n");
00292             rez = pcre_exec(rulep->match_comp, NULL, input.s, input.len,
00293                 0, 0, NULL, 0);
00294           break;
00295 
00296          case EQUAL_OP:
00297             LM_DBG("equal operator testing\n");
00298              if(rulep->match_exp.len != input.len)
00299                rez = -1;
00300              else 
00301                rez = strncmp(rulep->match_exp.s,input.s,input.len);
00302           break;
00303        
00304          default:
00305              LM_ERR("bogus match operator code %i\n", rulep->matchop);
00306             return -1;
00307       }
00308       if(rez >= 0)
00309           goto repl;
00310    }
00311     /*test the rules with len 0*/
00312     if(indexp->len){
00313       for(indexp = indexp->next; indexp!=NULL; indexp = indexp->next)
00314          if(!indexp->len)
00315             break;
00316       if(indexp)
00317           goto search_rule;
00318    }
00319    
00320     LM_DBG("no matching rule\n");
00321     return -1;
00322 
00323 repl:
00324    LM_DBG("found a matching rule %p: pr %i, match_exp %.*s\n",
00325       rulep, rulep->pr, rulep->match_exp.len, rulep->match_exp.s);
00326 
00327    if(attrs) {
00328       attrs->len = 0;
00329       attrs->s = 0;
00330       if(rulep->attrs.len>0) {
00331          LM_DBG("the rule's attrs are %.*s\n",
00332             rulep->attrs.len, rulep->attrs.s);
00333          if(rulep->attrs.len >= DP_MAX_ATTRS_LEN) {
00334             LM_ERR("out of memory for attributes\n");
00335             return -1;
00336           }
00337          attrs->s = dp_attrs_buf;
00338          memcpy(attrs->s, rulep->attrs.s, rulep->attrs.len*sizeof(char));
00339          attrs->len = rulep->attrs.len;
00340          attrs->s[attrs->len] = '\0';
00341 
00342          LM_DBG("the copied attributes are: %.*s\n",
00343             attrs->len, attrs->s);
00344       }
00345    }
00346 
00347    if(rule_translate(msg, input, rulep, output)!=0){
00348       LM_ERR("could not build the output\n");
00349       return -1;
00350    }
00351 
00352    return 0;
00353 }

Generated on Tue May 22 16:00:27 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6