dp_repl.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2007-2008 Voice Sistem SRL
00005  *
00006  * Copyright (C) 2008 Juha Heinanen
00007  *
00008  * This file is part of SIP-router, a free SIP server.
00009  *
00010  * SIP-router 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  * SIP-router 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 
00037 #include <fnmatch.h>
00038 
00039 #include "../../re.h"
00040 #include "../../mem/shm_mem.h"
00041 #include "dialplan.h"
00042 
00043 
00044 void repl_expr_free(struct subst_expr *se)
00045 {
00046         if(!se)
00047                 return;
00048 
00049         if(se->replacement.s){
00050                 shm_free(se->replacement.s);
00051                 se->replacement.s = 0;
00052         }
00053 
00054         shm_free(se);
00055         se = 0;
00056 }
00057 
00058 
00059 struct subst_expr* repl_exp_parse(str subst)
00060 {
00061         struct replace_with rw[MAX_REPLACE_WITH];
00062         int rw_no;
00063         struct subst_expr * se;
00064         int replace_all;
00065         char * p, *end, *repl, *repl_end;
00066         int max_pmatch, r;
00067         str shms;
00068 
00069         se = 0;
00070         replace_all = 0;
00071         shms.s = NULL;
00072 
00073         if (!(shms.s=shm_malloc((subst.len+1) * sizeof(char))) ){
00074                 LM_ERR("out of shm memory\n");
00075                 goto error;
00076         }
00077         memcpy(shms.s, subst.s, subst.len);
00078         shms.len = subst.len;
00079         shms.s[shms.len] = '\0';
00080 
00081         p = shms.s;
00082         end = p + shms.len;
00083         rw_no = 0;
00084 
00085         repl = p;
00086         if((rw_no = parse_repl(rw, &p, end, &max_pmatch, WITHOUT_SEP))< 0)
00087                 goto error;
00088 
00089         repl_end=p;
00090 
00091         /* construct the subst_expr structure */
00092         se = shm_malloc(sizeof(struct subst_expr)+
00093                         ((rw_no)?(rw_no-1)*sizeof(struct replace_with):0));
00094         /* 1 replace_with structure is  already included in subst_expr */
00095         if (se==0){
00096                 LM_ERR("out of shm memory (subst_expr)\n");
00097                 goto error;
00098         }
00099         memset((void*)se, 0, sizeof(struct subst_expr));
00100 
00101         se->replacement.s = shms.s;
00102         shms.s = NULL;
00103         se->replacement.len=repl_end-repl;
00104         if(!rw_no){
00105                 replace_all = 1;
00106         }
00107         /* start copying */
00108         LM_DBG("replacement expression is [%.*s]\n", se->replacement.len,
00109                         se->replacement.s);
00110         se->re=0;
00111         se->replace_all=replace_all;
00112         se->n_escapes=rw_no;
00113         se->max_pmatch=max_pmatch;
00114 
00115         /*replace_with is a simple structure, no shm alloc needed*/
00116         for (r=0; r<rw_no; r++) se->replace[r]=rw[r];
00117         return se;
00118 
00119 error:
00120         if(shms.s != NULL)
00121                 shm_free(shms.s);
00122         if (se) { repl_expr_free(se);}
00123         return NULL;
00124 }
00125 
00126 
00127 #define MAX_PHONE_NB_DIGITS             127
00128 static char dp_output_buf[MAX_PHONE_NB_DIGITS+1];
00129 int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
00130                 str * result)
00131 {
00132         int repl_nb, offset, match_nb, rc, cap_cnt;
00133         struct replace_with token;
00134         pcre *subst_comp;
00135         struct subst_expr * repl_comp;
00136         str match;
00137         pv_value_t sv;
00138         str* uri;
00139         int ovector[3 * (MAX_REPLACE_WITH + 1)];
00140         char *p;
00141         int size;
00142 
00143         dp_output_buf[0] = '\0';
00144         result->s = dp_output_buf;
00145         result->len = 0;
00146 
00147         subst_comp      = rule->subst_comp;
00148         repl_comp       = rule->repl_comp;
00149 
00150         if(!repl_comp){
00151                 LM_DBG("null replacement\n");
00152                 return 0;
00153         }
00154 
00155         if(subst_comp){
00156                 /*just in case something went wrong at load time*/
00157                 rc = pcre_fullinfo(subst_comp, NULL, PCRE_INFO_CAPTURECOUNT,
00158                                 &cap_cnt);
00159                 if (rc != 0) {
00160                         LM_ERR("pcre_fullinfo on compiled pattern yielded error: %d\n",
00161                                         rc);
00162                         return -1;;
00163                 }
00164                 if(repl_comp->max_pmatch > cap_cnt){
00165                         LM_ERR("illegal access to the %i-th subexpr of the subst expr\n",
00166                                         repl_comp->max_pmatch);
00167                         return -1;
00168                 }
00169 
00170                 /*search for the pattern from the compiled subst_exp*/
00171                 if (pcre_exec(rule->subst_comp, NULL, string.s, string.len,
00172                                         0, 0, ovector, 3 * (MAX_REPLACE_WITH + 1)) <= 0) {
00173                         LM_ERR("the string %.*s matched "
00174                                         "the match_exp %.*s but not the subst_exp %.*s!\n", 
00175                                         string.len, string.s, 
00176                                         rule->match_exp.len, rule->match_exp.s,
00177                                         rule->subst_exp.len, rule->subst_exp.s);
00178                         return -1;
00179                 }
00180         }
00181 
00182         /*simply copy from the replacing string*/
00183         if(!subst_comp || (repl_comp->n_escapes <=0)){
00184                 if(!repl_comp->replacement.s || repl_comp->replacement.len == 0){
00185                         LM_ERR("invalid replacing string\n");
00186                         goto error;
00187                 }
00188                 LM_DBG("simply replace the string, subst_comp %p, n_escapes %i\n",
00189                                 subst_comp, repl_comp->n_escapes);
00190                 memcpy(result->s, repl_comp->replacement.s,
00191                                 repl_comp->replacement.len);
00192                 result->len = repl_comp->replacement.len;
00193                 result->s[result->len] = '\0';
00194                 return 0;
00195         }
00196 
00197         /* offset- offset in the replacement string */
00198         result->len = repl_nb = offset = 0;
00199         p=repl_comp->replacement.s;
00200 
00201         while( repl_nb < repl_comp->n_escapes){
00202 
00203                 token = repl_comp->replace[repl_nb];
00204 
00205                 if(offset< token.offset){
00206                         if((repl_comp->replacement.len < offset)||
00207                                         (result->len + token.offset -offset >= MAX_PHONE_NB_DIGITS)){
00208                                 LM_ERR("invalid length\n");
00209                                 goto error;
00210                         }
00211                         /*copy from the replacing string*/
00212                         size = token.offset - offset;
00213                         memcpy(result->s + result->len, p + offset, size);
00214                         LM_DBG("copying <%.*s> from replacing string\n",
00215                                         size, p + offset);
00216                         result->len += size;
00217                         offset = token.offset;
00218                 }
00219 
00220                 switch(token.type) {
00221                         case REPLACE_NMATCH:
00222                                 /*copy from the match subexpression*/   
00223                                 match_nb = token.u.nmatch * 2;
00224                                 match.s =  string.s + ovector[match_nb];
00225                                 match.len = ovector[match_nb + 1] - ovector[match_nb];
00226                                 if(result->len + match.len >= MAX_PHONE_NB_DIGITS){
00227                                         LM_ERR("overflow\n");
00228                                         goto error;
00229                                 }
00230 
00231                                 memcpy(result->s + result->len, match.s, match.len);
00232                                 LM_DBG("copying match <%.*s> token size %d\n",
00233                                                 match.len, match.s, token.size);
00234                                 result->len += match.len;
00235                                 offset += token.size;
00236                                 break;
00237                         case REPLACE_CHAR:
00238                                 if(result->len + 1>= MAX_PHONE_NB_DIGITS){
00239                                         LM_ERR("overflow\n");
00240                                         goto error;
00241                                 }
00242                                 *(result->s + result->len) = token.u.c;
00243                                 LM_DBG("copying char <%c> token size %d\n",
00244                                                 token.u.c, token.size);
00245                                 result->len++;
00246                                 offset += token.size;
00247                                 break;
00248                         case REPLACE_URI:       
00249                                 if ( msg== NULL || msg->first_line.type!=SIP_REQUEST){
00250                                         LM_CRIT("uri substitution attempt on no request"
00251                                                         " message\n");
00252                                         break; /* ignore, we can continue */
00253                                 }
00254                                 uri= (msg->new_uri.s)?(&msg->new_uri):
00255                                         (&msg->first_line.u.request.uri);
00256                                 if(result->len+uri->len>=MAX_PHONE_NB_DIGITS){
00257                                         LM_ERR("overflow\n");
00258                                         goto error;
00259                                 }
00260                                 memcpy(result->s + result->len, uri->s, uri->len);
00261                                 LM_DBG("copying uri <%.*s> token size %d\n",
00262                                                 uri->len, uri->s, token.size);
00263                                 result->len+=uri->len;
00264                                 offset += token.size;
00265                                 break;
00266                         case REPLACE_SPEC:
00267                                 if (msg== NULL) {
00268                                         LM_DBG("replace spec attempted on no message\n");
00269                                         break;
00270                                 }
00271                                 if (pv_get_spec_value(msg, &token.u.spec, &sv) != 0) {
00272                                         LM_CRIT("item substitution returned error\n");
00273                                         break; /* ignore, we can continue */
00274                                 }
00275                                 if(result->len+sv.rs.len>=MAX_PHONE_NB_DIGITS){
00276                                         LM_ERR("rule_translate: overflow\n");
00277                                         goto error;
00278                                 }
00279                                 memcpy(result->s + result->len, sv.rs.s,
00280                                                 sv.rs.len);
00281                                 LM_DBG("copying pvar value <%.*s> token size %d\n",
00282                                                 sv.rs.len, sv.rs.s, token.size);
00283                                 result->len+=sv.rs.len;
00284                                 offset += token.size;
00285                                 break;
00286                         default:
00287                                 LM_CRIT("unknown type %d\n", repl_comp->replace[repl_nb].type);
00288                                 /* ignore it */
00289                 }
00290                 repl_nb++;
00291         }
00292         /* anything left? */
00293         if( repl_nb && offset < repl_comp->replacement.len){
00294                 /*copy from the replacing string*/
00295                 size = repl_comp->replacement.len - offset;
00296                 memcpy(result->s + result->len, p + offset, size);
00297                 LM_DBG("copying leftover <%.*s> from replacing string\n",
00298                                 size, p + offset);
00299                 result->len += size;
00300         }
00301 
00302         result->s[result->len] = '\0';
00303         return 0;
00304 
00305 error:
00306         result->s = 0;
00307         result->len = 0;
00308         return -1;
00309 }
00310 
00311 #define DP_MAX_ATTRS_LEN        128
00312 static char dp_attrs_buf[DP_MAX_ATTRS_LEN+1];
00313 int translate(struct sip_msg *msg, str input, str *output, dpl_id_p idp,
00314                 str *attrs)
00315 {
00316         dpl_node_p rulep;
00317         dpl_index_p indexp;
00318         int user_len, rez;
00319         char b;
00320 
00321         if(!input.s || !input.len) {
00322                 LM_ERR("invalid input string\n");
00323                 return -1;
00324         }
00325 
00326         user_len = input.len;
00327         for(indexp = idp->first_index; indexp!=NULL; indexp = indexp->next)
00328                 if(!indexp->len || (indexp->len!=0 && indexp->len == user_len) )
00329                         break;
00330 
00331         if(!indexp || (indexp!= NULL && !indexp->first_rule)){
00332                 LM_DBG("no rule for len %i\n", input.len);
00333                 return -1;
00334         }
00335 
00336 search_rule:
00337         for(rulep=indexp->first_rule; rulep!=NULL; rulep= rulep->next) {
00338                 switch(rulep->matchop) {
00339 
00340                         case DP_REGEX_OP:
00341                                 LM_DBG("regex operator testing\n");
00342                                 rez = pcre_exec(rulep->match_comp, NULL, input.s, input.len,
00343                                                 0, 0, NULL, 0);
00344                                 break;
00345 
00346                         case DP_EQUAL_OP:
00347                                 LM_DBG("equal operator testing\n");
00348                                 if(rulep->match_exp.len != input.len) {
00349                                         rez = -1;
00350                                 } else {
00351                                         rez = strncmp(rulep->match_exp.s,input.s,input.len);
00352                                         rez = (rez==0)?0:-1;
00353                                 }
00354                                 break;
00355 
00356                         case DP_FNMATCH_OP:
00357                                 LM_DBG("fnmatch operator testing\n");
00358                                 b = input.s[input.len];
00359                                 input.s[input.len] = '\0';
00360                                 rez = fnmatch(rulep->match_exp.s, input.s, 0);
00361                                 input.s[input.len] = b;
00362                                 rez = (rez==0)?0:-1;
00363                                 break;
00364 
00365                         default:
00366                                 LM_ERR("bogus match operator code %i\n", rulep->matchop);
00367                                 return -1;
00368                 }
00369                 if(rez >= 0)
00370                         goto repl;
00371         }
00372         /*test the rules with len 0*/
00373         if(indexp->len){
00374                 for(indexp = indexp->next; indexp!=NULL; indexp = indexp->next)
00375                         if(!indexp->len)
00376                                 break;
00377                 if(indexp)
00378                         goto search_rule;
00379         }
00380 
00381         LM_DBG("no matching rule\n");
00382         return -1;
00383 
00384 repl:
00385         LM_DBG("found a matching rule %p: pr %i, match_exp %.*s\n",
00386                         rulep, rulep->pr, rulep->match_exp.len, rulep->match_exp.s);
00387 
00388         if(attrs) {
00389                 attrs->len = 0;
00390                 attrs->s = 0;
00391                 if(rulep->attrs.len>0) {
00392                         LM_DBG("the rule's attrs are %.*s\n",
00393                                         rulep->attrs.len, rulep->attrs.s);
00394                         if(rulep->attrs.len >= DP_MAX_ATTRS_LEN) {
00395                                 LM_ERR("out of memory for attributes\n");
00396                                 return -1;
00397                         }
00398                         attrs->s = dp_attrs_buf;
00399                         memcpy(attrs->s, rulep->attrs.s, rulep->attrs.len*sizeof(char));
00400                         attrs->len = rulep->attrs.len;
00401                         attrs->s[attrs->len] = '\0';
00402 
00403                         LM_DBG("the copied attributes are: %.*s\n",
00404                                         attrs->len, attrs->s);
00405                 }
00406         }
00407 
00408         if(rule_translate(msg, input, rulep, output)!=0){
00409                 LM_ERR("could not build the output\n");
00410                 return -1;
00411         }
00412 
00413         return 0;
00414 }