dialplan.c

Go to the documentation of this file.
00001 /*
00002  *  $Id: dialplan.c 5287 2008-12-03 10:54:29Z 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  *  2008-10-09 module is now using pcre regexp lib (juha heinanen)
00028  */
00029 
00030 
00031 #include <string.h>
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <math.h>
00035 #include "../../sr_module.h"
00036 #include "../../db/db.h"
00037 #include "../../dprint.h"
00038 #include "../../error.h"
00039 #include "../../ut.h"
00040 #include "../../action.h"
00041 #include "../../pvar.h"
00042 #include "../../dset.h"
00043 #include "../../mem/mem.h"
00044 #include "../../mi/mi.h"
00045 #include "../../parser/parse_to.h"
00046 #include "dialplan.h"
00047 #include "dp_db.h"
00048 
00049 MODULE_VERSION
00050 
00051 #define DEFAULT_PARAM    "$ruri.user"
00052 
00053 static int mod_init(void);
00054 static int child_init(int rank);
00055 static void mod_destroy();
00056 static int mi_child_init();
00057 
00058 static struct mi_root * mi_reload_rules(struct mi_root *cmd_tree,void *param);
00059 static struct mi_root * mi_translate(struct mi_root *cmd_tree, void *param);
00060 static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2);
00061 static int dp_trans_fixup(void ** param, int param_no);
00062 
00063 str attr_pvar_s = {NULL,0};
00064 pv_spec_t * attr_pvar = NULL;
00065 
00066 str default_param_s = str_init(DEFAULT_PARAM);
00067 dp_param_p default_par2 = NULL;
00068 
00069 int dp_fetch_rows = 1000;
00070 
00071 static param_export_t mod_params[]={
00072    { "db_url",       STR_PARAM,  &dp_db_url.s },
00073    { "table_name",      STR_PARAM,  &dp_table_name.s },
00074    { "dpid_col",     STR_PARAM,  &dpid_column.s },
00075    { "pr_col",       STR_PARAM,  &pr_column.s },
00076    { "match_op_col", STR_PARAM,  &match_op_column.s },
00077    { "match_exp_col",   STR_PARAM,  &match_exp_column.s },
00078    { "match_len_col",   STR_PARAM,  &match_len_column.s },
00079    { "subst_exp_col",   STR_PARAM,  &subst_exp_column.s },
00080    { "repl_exp_col", STR_PARAM,  &repl_exp_column.s },
00081    { "attrs_col",    STR_PARAM,  &attrs_column.s },
00082    { "attrs_pvar",       STR_PARAM, &attr_pvar_s.s},
00083    { "attribute_pvar",  STR_PARAM,  &attr_pvar_s.s},
00084    { "fetch_rows",      INT_PARAM,  &dp_fetch_rows},
00085    {0,0,0}
00086 };
00087 
00088 static mi_export_t mi_cmds[] = {
00089    { "dp_reload",  mi_reload_rules,   MI_NO_INPUT_FLAG,  0,  mi_child_init},
00090    { "dp_translate",  mi_translate,   0,  0,  0},
00091    { 0, 0, 0, 0, 0}
00092 };
00093 
00094 static cmd_export_t cmds[]={
00095    {"dp_translate",(cmd_function)dp_translate_f,   2, dp_trans_fixup,  0,
00096             REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE|BRANCH_ROUTE},
00097    {"dp_translate",(cmd_function)dp_translate_f,   1, dp_trans_fixup,  0,
00098             REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE|BRANCH_ROUTE},
00099    {0,0,0,0,0,0}
00100 };
00101 
00102 struct module_exports exports= {
00103    "dialplan",     /* module's name */
00104    DEFAULT_DLFLAGS, /* dlopen flags */
00105    cmds,           /* exported functions */
00106    mod_params,     /* param exports */
00107    0,          /* exported statistics */
00108    mi_cmds,    /* exported MI functions */
00109    0,          /* exported pseudo-variables */
00110    0,          /* additional processes */
00111    mod_init,      /* module initialization function */
00112    0,          /* reply processing function */
00113    mod_destroy,
00114    child_init     /* per-child init function */
00115 };
00116 
00117 
00118 static int mod_init(void)
00119 {
00120    dp_db_url.len = dp_db_url.s ? strlen(dp_db_url.s) : 0;
00121    LM_DBG("db_url=%s/%d/%p\n", ZSW(dp_db_url.s), dp_db_url.len,dp_db_url.s);
00122    dp_table_name.len   = strlen(dp_table_name.s);
00123    dpid_column.len     = strlen( dpid_column.s);
00124    pr_column.len       = strlen(pr_column.s);
00125    match_op_column.len = strlen(match_op_column.s);
00126    match_exp_column.len= strlen(match_exp_column.s);
00127    match_len_column.len= strlen(match_len_column.s);
00128    subst_exp_column.len= strlen(subst_exp_column.s);
00129    repl_exp_column.len = strlen(repl_exp_column.s);
00130    attrs_column.len    = strlen(attrs_column.s);
00131 
00132    if(attr_pvar_s.s) {
00133       attr_pvar = (pv_spec_t *)shm_malloc(sizeof(pv_spec_t));
00134       if(!attr_pvar){
00135          LM_ERR("out of shm memory\n");
00136          return -1;
00137       }
00138 
00139       attr_pvar_s.len = strlen(attr_pvar_s.s);
00140       if( (pv_parse_spec(&attr_pvar_s, attr_pvar)==NULL) ||
00141       ((attr_pvar->type != PVT_AVP) && (attr_pvar->type!=PVT_SCRIPTVAR))) {
00142             LM_ERR("invalid pvar name\n");
00143             return -1;
00144          }
00145    }
00146 
00147    default_par2 = (dp_param_p)shm_malloc(sizeof(dp_param_t));
00148    if(default_par2 == NULL){
00149       LM_ERR("no shm more memory\n");
00150       return -1;
00151    }
00152    memset(default_par2, 0, sizeof(dp_param_t));
00153 
00154    default_param_s.len = strlen(default_param_s.s);
00155    if (pv_parse_spec( &default_param_s, &default_par2->v.sp[0])==NULL) {
00156       LM_ERR("input pv is invalid\n");
00157       return -1;
00158    }
00159 
00160    default_param_s.len = strlen(default_param_s.s);
00161    if (pv_parse_spec( &default_param_s, &default_par2->v.sp[1])==NULL) {
00162       LM_ERR("output pv is invalid\n");
00163       return -1;
00164    }
00165 
00166    if(init_data() != 0) {
00167       LM_ERR("could not initialize data\n");
00168       return -1;
00169    }
00170 
00171    if(dp_fetch_rows<=0)
00172       dp_fetch_rows = 1000;
00173 
00174    return 0;
00175 }
00176 
00177 
00178 static int child_init(int rank)
00179 {
00180    if(rank>0)
00181       return dp_connect_db();
00182    return 0;
00183 }
00184 
00185 
00186 static void mod_destroy(void)
00187 {
00188    /*destroy shared memory*/
00189    if(default_par2){
00190       shm_free(default_par2);
00191       default_par2 = NULL;
00192    }
00193    if(attr_pvar){
00194       shm_free(attr_pvar);
00195       attr_pvar = NULL;
00196    }
00197    destroy_data();
00198 
00199    /*close database connection*/
00200    dp_disconnect_db();
00201 }
00202 
00203 
00204 static int mi_child_init(void)
00205 {
00206    return dp_connect_db();
00207 }
00208 
00209 
00210 static int dp_get_ivalue(struct sip_msg* msg, dp_param_p dp, int *val)
00211 {
00212    pv_value_t value;
00213 
00214    if(dp->type==DP_VAL_INT) {
00215       LM_DBG("integer value\n");
00216       *val = dp->v.id;
00217       return 0;
00218    }
00219 
00220    LM_DBG("searching %d\n",dp->v.sp[0].type);
00221 
00222    if( pv_get_spec_value( msg, &dp->v.sp[0], &value)!=0
00223    || value.flags&(PV_VAL_NULL|PV_VAL_EMPTY) || !(value.flags&PV_VAL_INT)) {
00224       LM_ERR("no AVP or SCRIPTVAR found (error in scripts)\n");
00225       return -1;
00226    }
00227    *val = value.ri;
00228    return 0;
00229 }
00230 
00231 
00232 static int dp_get_svalue(struct sip_msg * msg, pv_spec_t spec, str* val)
00233 {
00234    pv_value_t value;
00235 
00236    LM_DBG("searching %d \n", spec.type);
00237 
00238    if ( pv_get_spec_value(msg,&spec,&value)!=0 || value.flags&PV_VAL_NULL
00239    || value.flags&PV_VAL_EMPTY || !(value.flags&PV_VAL_STR)){
00240          LM_ERR("no AVP or SCRIPTVAR found (error in scripts)\n");
00241          return -1;
00242    }
00243 
00244    *val = value.rs;
00245    return 0;
00246 }
00247 
00248 
00249 static int dp_update(struct sip_msg * msg, pv_spec_t * src, pv_spec_t * dest,
00250                                  str * repl, str * attrs)
00251 {
00252    int no_change;
00253    pv_value_t val;
00254 
00255    no_change = ((!repl->s) || (!repl->len)) && (src->type == dest->type) 
00256       && ((src->type == PVT_RURI) || (src->type == PVT_RURI_USERNAME));
00257 
00258    if (no_change)
00259       goto set_attr_pvar;
00260 
00261    memset(&val, 0, sizeof(pv_value_t));
00262    val.flags = PV_VAL_STR;
00263    val.rs = *repl;
00264 
00265    if(dest->setf(msg, &dest->pvp, (int)EQ_T, &val)<0)
00266    {
00267       LM_ERR("setting dst pseudo-variable failed\n");
00268       return -1;
00269    }
00270 
00271    if(route_type==FAILURE_ROUTE
00272             && (dest->type==PVT_RURI || dest->type==PVT_RURI_USERNAME)) {
00273       if (append_branch(msg, 0, 0, 0, Q_UNSPECIFIED, 0, 0)!=1 ){
00274          LM_ERR("append_branch action failed\n");
00275          return -1;
00276       }
00277    }
00278 
00279 set_attr_pvar:
00280 
00281    if(!attr_pvar)
00282       return 0;
00283    
00284    val.rs = *attrs;
00285    if(attr_pvar->setf(msg, &attr_pvar->pvp, (int)EQ_T, &val)<0)
00286    {
00287       LM_ERR("setting attr pseudo-variable failed\n");
00288       return -1;
00289    }
00290 
00291    return 0;
00292 }
00293 
00294 
00295 static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2)
00296 {
00297    int dpid;
00298    str input, output;
00299    dpl_id_p idp;
00300    dp_param_p id_par, repl_par;
00301    str attrs, * attrs_par;
00302 
00303    if(!msg)
00304       return -1;
00305 
00306    /*verify first param's value*/
00307    id_par = (dp_param_p) str1;
00308    if (dp_get_ivalue(msg, id_par, &dpid) != 0){
00309       LM_ERR("no dpid value\n");
00310       return -1;
00311    }
00312    LM_DBG("dpid is %i\n", dpid);
00313 
00314    if ((idp = select_dpid(dpid)) ==0 ){
00315       LM_DBG("no information available for dpid %i\n", dpid);
00316       return -1;
00317    }
00318 
00319    repl_par = (str2!=NULL)? ((dp_param_p)str2):default_par2;
00320    if (dp_get_svalue(msg, repl_par->v.sp[0], &input)!=0){
00321       LM_ERR("invalid param 2\n");
00322       return -1;
00323    }
00324 
00325    LM_DBG("input is %.*s\n", input.len, input.s);
00326 
00327    attrs_par = (!attr_pvar)?NULL:&attrs;
00328    if (translate(msg, input, &output, idp, attrs_par)!=0){
00329       LM_DBG("could not translate %.*s "
00330          "with dpid %i\n", input.len, input.s, idp->dp_id);
00331       return -1;
00332    }
00333    LM_DBG("input %.*s with dpid %i => output %.*s\n",
00334          input.len, input.s, idp->dp_id, output.len, output.s);
00335 
00336    /*set the output*/
00337    if (dp_update(msg, &repl_par->v.sp[0], &repl_par->v.sp[1], 
00338    &output, attrs_par) !=0){
00339       LM_ERR("cannot set the output\n");
00340       return -1;
00341    }
00342 
00343    return 1;
00344       
00345 }
00346 
00347 #define verify_par_type(_par_no, _spec)\
00348    do{\
00349       if( ((_par_no == 1) \
00350          && ((_spec).type != PVT_AVP) && ((_spec).type!=PVT_SCRIPTVAR) )\
00351         ||((_par_no == 2) \
00352          && ((_spec).type != PVT_AVP) && ((_spec).type!=PVT_SCRIPTVAR) \
00353          && ((_spec).type!=PVT_RURI) && (_spec.type!=PVT_RURI_USERNAME))){\
00354             \
00355          LM_ERR("Unsupported Parameter TYPE\n");\
00356             return E_UNSPEC;\
00357          }\
00358    }while(0);
00359 
00360 
00361 /* first param: DPID: type: INT, AVP, SVAR
00362  * second param: SRC type: any psedo variable type
00363  * second param: DST type: RURI, RURI_USERNAME, AVP, SVAR
00364  * default value for the second param: $ru.user/$ru.user
00365  */
00366 static int dp_trans_fixup(void ** param, int param_no){
00367 
00368    int dpid, err;
00369    dp_param_p dp_par= NULL;
00370    char *p, *s=NULL;
00371    str lstr;
00372 
00373    if(param_no!=1 && param_no!=2) 
00374       return 0;
00375 
00376    p = (char*)*param;
00377    if(!p || (*p == '\0')){
00378       LM_DBG("null param %i\n", param_no);
00379       return E_CFG;
00380    }
00381 
00382    LM_DBG("param_no is %i\n", param_no);
00383 
00384    dp_par = (dp_param_p)pkg_malloc(sizeof(dp_param_t));
00385    if(dp_par == NULL){
00386       LM_ERR("no more pkg memory\n");
00387       return E_OUT_OF_MEM;
00388    }
00389    memset(dp_par, 0, sizeof(dp_param_t));
00390 
00391    if(param_no == 1) {
00392       if(*p != '$') {
00393          dp_par->type = DP_VAL_INT;
00394          dpid = str2s(*param, strlen(*param), &err);
00395          if (err != 0) {
00396             LM_ERR("bad number <%s>\n",(char *)(*param));
00397             pkg_free(dp_par);
00398             return E_CFG;
00399          }
00400 
00401          dp_par->type = DP_VAL_INT;
00402          dp_par->v.id = dpid;
00403       }else{
00404          lstr.s = p; lstr.len = strlen(p);
00405          if (pv_parse_spec( &lstr, &dp_par->v.sp[0])==NULL)
00406             goto error;
00407 
00408          verify_par_type(param_no, dp_par->v.sp[0]);
00409          dp_par->type = DP_VAL_SPEC;
00410       }
00411    } else {
00412       if( ((s = strchr(p, '/')) == 0) ||( *(s+1)=='\0'))
00413             goto error;
00414       *s = '\0'; s++;
00415 
00416       lstr.s = p; lstr.len = strlen(p);
00417       if(pv_parse_spec( &lstr, &dp_par->v.sp[0])==NULL)
00418          goto error;
00419 
00420       lstr.s = s; lstr.len = strlen(s);
00421       if (pv_parse_spec( &lstr, &dp_par->v.sp[1] )==NULL)
00422          goto error;
00423 
00424       verify_par_type(param_no, dp_par->v.sp[1]);
00425 
00426       dp_par->type = DP_VAL_SPEC;
00427    }
00428    
00429    *param = (void *)dp_par;
00430 
00431    return 0;
00432 
00433 error:
00434    LM_ERR("failed to parse param %i\n", param_no);
00435    return E_INVALID_PARAMS;
00436 }
00437 
00438 
00439 static struct mi_root * mi_reload_rules(struct mi_root *cmd_tree, void *param)
00440 {
00441    struct mi_root* rpl_tree= NULL;
00442 
00443    if(dp_load_db() != 0){
00444       LM_ERR("failed to reload database data\n");
00445       return 0;
00446    }
00447 
00448    rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00449    if (rpl_tree==0)
00450       return 0;
00451    
00452    return rpl_tree;
00453 }
00454 
00455 /* 
00456  *  mi cmd:  dp_translate
00457  *       <dialplan id> 
00458  *       <input>
00459  *    * */
00460 
00461 static struct mi_root * mi_translate(struct mi_root *cmd, void *param)
00462 {
00463 
00464    struct mi_root* rpl= NULL;
00465    struct mi_node* root, *node;
00466    dpl_id_p idp;
00467    str dpid_str;
00468    str input;
00469    int dpid;
00470    int err;
00471    str attrs;
00472    str output= {0, 0};
00473 
00474    node = cmd->node.kids;
00475    if(node == NULL)
00476       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00477 
00478    /* Get the id parameter */
00479    dpid_str = node->value;
00480    if(dpid_str.s == NULL || dpid_str.len== 0)   {
00481       LM_ERR( "empty idp parameter\n");
00482       return init_mi_tree(404, "Empty id parameter", 18);
00483    }
00484    dpid = str2s(dpid_str.s, dpid_str.len, &err);
00485    if(err != 0)    {
00486       LM_ERR("Wrong id parameter - should be an integer\n");
00487       return init_mi_tree(404, "Wrong id parameter", 18);
00488    }
00489 
00490    if ((idp = select_dpid(dpid)) ==0 ){
00491       LM_ERR("no information available for dpid %i\n", dpid);
00492       return init_mi_tree(404, "No information available for dpid", 33);
00493    }
00494 
00495    node = node->next;
00496    if(node == NULL)
00497       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00498 
00499    if(node->next!= NULL)
00500       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00501 
00502    input=  node->value;
00503    if(input.s == NULL || input.len== 0)   {
00504       LM_ERR( "empty input parameter\n");
00505       return init_mi_tree(404, "Empty input parameter", 21);
00506    }
00507 
00508    LM_DBG("input is %.*s\n", input.len, input.s);
00509 
00510    if (translate(NULL, input, &output, idp, &attrs)!=0){
00511       LM_DBG("could not translate %.*s with dpid %i\n", 
00512          input.len, input.s, idp->dp_id);
00513       return 0;
00514    }
00515    LM_DBG("input %.*s with dpid %i => output %.*s\n",
00516          input.len, input.s, idp->dp_id, output.len, output.s);
00517 
00518    rpl = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00519    if (rpl==0)
00520       goto error;
00521 
00522    root= &rpl->node;
00523 
00524    node = add_mi_node_child(root, 0, "Output", 6, output.s, output.len );
00525    if( node == NULL)
00526       goto error;
00527 
00528    node = add_mi_node_child(root, 0, "ATTRIBUTES", 10, attrs.s, attrs.len);
00529    if( node == NULL)
00530       goto error;
00531 
00532    return rpl;
00533 
00534 error:
00535    if(rpl)
00536       free_mi_tree(rpl);
00537    return 0;
00538 }
00539 

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