dialplan.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  *  2008-10-09 module is now using pcre regexp lib (juha heinanen)
00028  */
00029 
00044 #include <string.h>
00045 #include <stdlib.h>
00046 #include <stdio.h>
00047 #include <math.h>
00048 #include "../../sr_module.h"
00049 #include "../../lib/srdb1/db.h"
00050 #include "../../dprint.h"
00051 #include "../../error.h"
00052 #include "../../ut.h"
00053 #include "../../action.h"
00054 #include "../../pvar.h"
00055 #include "../../dset.h"
00056 #include "../../mem/mem.h"
00057 #include "../../lib/kmi/mi.h"
00058 #include "../../parser/parse_to.h"
00059 #include "../../rpc.h"
00060 #include "../../rpc_lookup.h"
00061 #include "../../lvalue.h"
00062 #include "dialplan.h"
00063 #include "dp_db.h"
00064 
00065 MODULE_VERSION
00066 
00067 #define DEFAULT_PARAM    "$ruri.user"
00068 
00069 static int mod_init(void);
00070 static int child_init(int rank);
00071 static void mod_destroy();
00072 static int mi_child_init();
00073 
00074 static int dialplan_init_rpc(void);
00075 
00076 static struct mi_root * mi_reload_rules(struct mi_root *cmd_tree,void *param);
00077 static struct mi_root * mi_translate(struct mi_root *cmd_tree, void *param);
00078 static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2);
00079 static int dp_trans_fixup(void ** param, int param_no);
00080 
00081 str attr_pvar_s = {NULL,0};
00082 pv_spec_t * attr_pvar = NULL;
00083 
00084 str default_param_s = str_init(DEFAULT_PARAM);
00085 dp_param_p default_par2 = NULL;
00086 
00087 int dp_fetch_rows = 1000;
00088 
00089 static param_export_t mod_params[]={
00090         { "db_url",                     STR_PARAM,      &dp_db_url.s },
00091         { "table_name",         STR_PARAM,      &dp_table_name.s },
00092         { "dpid_col",           STR_PARAM,      &dpid_column.s },
00093         { "pr_col",                     STR_PARAM,      &pr_column.s },
00094         { "match_op_col",       STR_PARAM,      &match_op_column.s },
00095         { "match_exp_col",      STR_PARAM,      &match_exp_column.s },
00096         { "match_len_col",      STR_PARAM,      &match_len_column.s },
00097         { "subst_exp_col",      STR_PARAM,      &subst_exp_column.s },
00098         { "repl_exp_col",       STR_PARAM,      &repl_exp_column.s },
00099         { "attrs_col",          STR_PARAM,      &attrs_column.s },
00100         { "attrs_pvar",     STR_PARAM,  &attr_pvar_s.s},
00101         { "attribute_pvar",     STR_PARAM,      &attr_pvar_s.s},
00102         { "fetch_rows",         INT_PARAM,      &dp_fetch_rows},
00103         {0,0,0}
00104 };
00105 
00106 static mi_export_t mi_cmds[] = {
00107         { "dp_reload",  mi_reload_rules,   MI_NO_INPUT_FLAG,  0,  mi_child_init},
00108         { "dp_translate",  mi_translate,   0,  0,  0},
00109         { 0, 0, 0, 0, 0}
00110 };
00111 
00112 static cmd_export_t cmds[]={
00113         {"dp_translate",(cmd_function)dp_translate_f,   2,      dp_trans_fixup,  0,
00114                 ANY_ROUTE},
00115         {"dp_translate",(cmd_function)dp_translate_f,   1,      dp_trans_fixup,  0,
00116                 ANY_ROUTE},
00117         {0,0,0,0,0,0}
00118 };
00119 
00120 struct module_exports exports= {
00121         "dialplan",     /* module's name */
00122         DEFAULT_DLFLAGS, /* dlopen flags */
00123         cmds,               /* exported functions */
00124         mod_params,     /* param exports */
00125         0,                              /* exported statistics */
00126         mi_cmds,                /* exported MI functions */
00127         0,                              /* exported pseudo-variables */
00128         0,                              /* additional processes */
00129         mod_init,               /* module initialization function */
00130         0,                              /* reply processing function */
00131         mod_destroy,
00132         child_init              /* per-child init function */
00133 };
00134 
00135 
00136 static int mod_init(void)
00137 {
00138         if(register_mi_mod(exports.name, mi_cmds)!=0)
00139         {
00140                 LM_ERR("failed to register MI commands\n");
00141                 return -1;
00142         }
00143         if(dialplan_init_rpc()!=0)
00144         {
00145                 LM_ERR("failed to register RPC commands\n");
00146                 return -1;
00147         }
00148 
00149 
00150         dp_db_url.len = dp_db_url.s ? strlen(dp_db_url.s) : 0;
00151         LM_DBG("db_url=%s/%d/%p\n", ZSW(dp_db_url.s), dp_db_url.len,dp_db_url.s);
00152         dp_table_name.len   = strlen(dp_table_name.s);
00153         dpid_column.len     = strlen( dpid_column.s);
00154         pr_column.len       = strlen(pr_column.s);
00155         match_op_column.len = strlen(match_op_column.s);
00156         match_exp_column.len= strlen(match_exp_column.s);
00157         match_len_column.len= strlen(match_len_column.s);
00158         subst_exp_column.len= strlen(subst_exp_column.s);
00159         repl_exp_column.len = strlen(repl_exp_column.s);
00160         attrs_column.len    = strlen(attrs_column.s);
00161 
00162         if(attr_pvar_s.s) {
00163                 attr_pvar = (pv_spec_t *)shm_malloc(sizeof(pv_spec_t));
00164                 if(!attr_pvar){
00165                         LM_ERR("out of shm memory\n");
00166                         return -1;
00167                 }
00168 
00169                 attr_pvar_s.len = strlen(attr_pvar_s.s);
00170                 if( (pv_parse_spec(&attr_pvar_s, attr_pvar)==NULL) ||
00171                                 ((attr_pvar->type != PVT_AVP) && (attr_pvar->type!=PVT_SCRIPTVAR))) {
00172                         LM_ERR("invalid pvar name\n");
00173                         return -1;
00174                 }
00175         }
00176 
00177         default_par2 = (dp_param_p)shm_malloc(sizeof(dp_param_t));
00178         if(default_par2 == NULL){
00179                 LM_ERR("no shm more memory\n");
00180                 return -1;
00181         }
00182         memset(default_par2, 0, sizeof(dp_param_t));
00183 
00184         default_param_s.len = strlen(default_param_s.s);
00185         if (pv_parse_spec( &default_param_s, &default_par2->v.sp[0])==NULL) {
00186                 LM_ERR("input pv is invalid\n");
00187                 return -1;
00188         }
00189 
00190         default_param_s.len = strlen(default_param_s.s);
00191         if (pv_parse_spec( &default_param_s, &default_par2->v.sp[1])==NULL) {
00192                 LM_ERR("output pv is invalid\n");
00193                 return -1;
00194         }
00195 
00196         if(dp_fetch_rows<=0)
00197                 dp_fetch_rows = 1000;
00198 
00199         if(init_data() != 0) {
00200                 LM_ERR("could not initialize data\n");
00201                 return -1;
00202         }
00203 
00204         return 0;
00205 }
00206 
00207 
00208 static int child_init(int rank)
00209 {
00210         return 0;
00211 }
00212 
00213 
00214 static void mod_destroy(void)
00215 {
00216         /*destroy shared memory*/
00217         if(default_par2){
00218                 shm_free(default_par2);
00219                 default_par2 = NULL;
00220         }
00221         if(attr_pvar){
00222                 shm_free(attr_pvar);
00223                 attr_pvar = NULL;
00224         }
00225         destroy_data();
00226 }
00227 
00228 
00229 static int mi_child_init(void)
00230 {
00231         return 0;
00232 }
00233 
00234 
00235 static int dp_get_ivalue(struct sip_msg* msg, dp_param_p dp, int *val)
00236 {
00237         pv_value_t value;
00238 
00239         if(dp->type==DP_VAL_INT) {
00240                 LM_DBG("integer value\n");
00241                 *val = dp->v.id;
00242                 return 0;
00243         }
00244 
00245         LM_DBG("searching %d\n",dp->v.sp[0].type);
00246 
00247         if( pv_get_spec_value( msg, &dp->v.sp[0], &value)!=0
00248                         || value.flags&(PV_VAL_NULL|PV_VAL_EMPTY) || !(value.flags&PV_VAL_INT)) {
00249                 LM_ERR("no AVP or SCRIPTVAR found (error in scripts)\n");
00250                 return -1;
00251         }
00252         *val = value.ri;
00253         return 0;
00254 }
00255 
00256 
00257 static int dp_get_svalue(struct sip_msg * msg, pv_spec_t spec, str* val)
00258 {
00259         pv_value_t value;
00260 
00261         LM_DBG("searching %d \n", spec.type);
00262 
00263         if ( pv_get_spec_value(msg,&spec,&value)!=0 || value.flags&PV_VAL_NULL
00264                         || value.flags&PV_VAL_EMPTY || !(value.flags&PV_VAL_STR)){
00265                 LM_ERR("no AVP or SCRIPTVAR found (error in scripts)\n");
00266                 return -1;
00267         }
00268 
00269         *val = value.rs;
00270         return 0;
00271 }
00272 
00273 
00274 static int dp_update(struct sip_msg * msg, pv_spec_t * src, pv_spec_t * dest,
00275                 str * repl, str * attrs)
00276 {
00277         int no_change;
00278         pv_value_t val;
00279 
00280         no_change = (dest->type == PVT_NONE) || (!repl->s) || (!repl->len);
00281 
00282         if (no_change)
00283                 goto set_attr_pvar;
00284 
00285         memset(&val, 0, sizeof(pv_value_t));
00286         val.flags = PV_VAL_STR;
00287         val.rs = *repl;
00288 
00289         if(dest->setf(msg, &dest->pvp, (int)EQ_T, &val)<0)
00290         {
00291                 LM_ERR("setting dst pseudo-variable failed\n");
00292                 return -1;
00293         }
00294 
00295         if(is_route_type(FAILURE_ROUTE)
00296                         && (dest->type==PVT_RURI || dest->type==PVT_RURI_USERNAME)) {
00297                 if (append_branch(msg, 0, 0, 0, Q_UNSPECIFIED, 0, 0)!=1 ){
00298                         LM_ERR("append_branch action failed\n");
00299                         return -1;
00300                 }
00301         }
00302 
00303 set_attr_pvar:
00304 
00305         if(!attr_pvar)
00306                 return 0;
00307 
00308         val.rs = *attrs;
00309         if(attr_pvar->setf(msg, &attr_pvar->pvp, (int)EQ_T, &val)<0)
00310         {
00311                 LM_ERR("setting attr pseudo-variable failed\n");
00312                 return -1;
00313         }
00314 
00315         return 0;
00316 }
00317 
00318 
00319 static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2)
00320 {
00321         int dpid;
00322         str input, output;
00323         dpl_id_p idp;
00324         dp_param_p id_par, repl_par;
00325         str attrs, * attrs_par;
00326 
00327         if(!msg)
00328                 return -1;
00329 
00330         /*verify first param's value*/
00331         id_par = (dp_param_p) str1;
00332         if (dp_get_ivalue(msg, id_par, &dpid) != 0){
00333                 LM_ERR("no dpid value\n");
00334                 return -1;
00335         }
00336 
00337         if ((idp = select_dpid(dpid)) ==0 ){
00338                 LM_DBG("no information available for dpid %i\n", dpid);
00339                 return -2;
00340         }
00341 
00342         repl_par = (str2!=NULL)? ((dp_param_p)str2):default_par2;
00343         if (dp_get_svalue(msg, repl_par->v.sp[0], &input)!=0){
00344                 LM_ERR("invalid param 2\n");
00345                 return -1;
00346         }
00347 
00348         LM_DBG("input is %.*s\n", input.len, input.s);
00349 
00350         attrs_par = (!attr_pvar)?NULL:&attrs;
00351         if (translate(msg, input, &output, idp, attrs_par)!=0){
00352                 LM_DBG("could not translate %.*s "
00353                                 "with dpid %i\n", input.len, input.s, idp->dp_id);
00354                 return -1;
00355         }
00356         LM_DBG("input %.*s with dpid %i => output %.*s\n",
00357                         input.len, input.s, idp->dp_id, output.len, output.s);
00358 
00359         /*set the output*/
00360         if (dp_update(msg, &repl_par->v.sp[0], &repl_par->v.sp[1], 
00361                                 &output, attrs_par) !=0){
00362                 LM_ERR("cannot set the output\n");
00363                 return -1;
00364         }
00365 
00366         return 1;
00367 
00368 }
00369 
00370 #define verify_par_type(_par_no, _spec)\
00371         do{\
00372                 if( ((_par_no == 1) \
00373                                         && ((_spec).type != PVT_AVP) && ((_spec).type!=PVT_SCRIPTVAR) )\
00374                                 ||((_par_no == 2) \
00375                                         && ((_spec).type != PVT_AVP) && ((_spec).type!=PVT_SCRIPTVAR) \
00376                                         && ((_spec).type!=PVT_RURI) && (_spec.type!=PVT_RURI_USERNAME))){\
00377                         \
00378                         LM_ERR("Unsupported Parameter TYPE\n");\
00379                         return E_UNSPEC;\
00380                 }\
00381         }while(0);
00382 
00383 
00384 /* first param: DPID: type: INT, AVP, SVAR
00385  * second param: SRC type: any psedo variable type
00386  * second param: DST type: RURI, RURI_USERNAME, AVP, SVAR, N/A
00387  * default value for the second param: $ru.user/$ru.user
00388  */
00389 static int dp_trans_fixup(void ** param, int param_no){
00390 
00391         int dpid;
00392         dp_param_p dp_par= NULL;
00393         char *p, *s=NULL;
00394         str lstr;
00395 
00396         if(param_no!=1 && param_no!=2) 
00397                 return 0;
00398 
00399         p = (char*)*param;
00400         if(!p || (*p == '\0')){
00401                 LM_DBG("null param %i\n", param_no);
00402                 return E_CFG;
00403         }
00404 
00405         LM_DBG("param_no is %i\n", param_no);
00406 
00407         dp_par = (dp_param_p)pkg_malloc(sizeof(dp_param_t));
00408         if(dp_par == NULL){
00409                 LM_ERR("no more pkg memory\n");
00410                 return E_OUT_OF_MEM;
00411         }
00412         memset(dp_par, 0, sizeof(dp_param_t));
00413 
00414         if(param_no == 1) {
00415                 if(*p != '$') {
00416                         dp_par->type = DP_VAL_INT;
00417                         lstr.s = *param; lstr.len = strlen(*param);
00418                         if(str2sint(&lstr, &dpid) != 0) {
00419                                 LM_ERR("bad number <%s>\n",(char *)(*param));
00420                                 pkg_free(dp_par);
00421                                 return E_CFG;
00422                         }
00423 
00424                         dp_par->type = DP_VAL_INT;
00425                         dp_par->v.id = dpid;
00426                 }else{
00427                         lstr.s = p; lstr.len = strlen(p);
00428                         if (pv_parse_spec( &lstr, &dp_par->v.sp[0])==NULL)
00429                                 goto error;
00430 
00431                         verify_par_type(param_no, dp_par->v.sp[0]);
00432                         dp_par->type = DP_VAL_SPEC;
00433                 }
00434         } else {
00435 
00436                 if (((s = strchr(p, '/')) != 0) && (*(s+1)=='\0'))
00437                         goto error;
00438 
00439                 if (s != 0) {
00440                         *s = '\0'; s++;
00441                 }
00442 
00443                 lstr.s = p; lstr.len = strlen(p);
00444                 if(pv_parse_spec( &lstr, &dp_par->v.sp[0])==NULL)
00445                         goto error;
00446 
00447                 if (s != 0) {
00448                         lstr.s = s; lstr.len = strlen(s);
00449                         if (pv_parse_spec( &lstr, &dp_par->v.sp[1] )==NULL)
00450                                 goto error;
00451                         verify_par_type(param_no, dp_par->v.sp[1]);
00452                 } else {
00453                         dp_par->v.sp[1].type = PVT_NONE;
00454                 }
00455 
00456                 dp_par->type = DP_VAL_SPEC;
00457 
00458         }
00459 
00460         *param = (void *)dp_par;
00461 
00462         return 0;
00463 
00464 error:
00465         LM_ERR("failed to parse param %i\n", param_no);
00466         return E_INVALID_PARAMS;
00467 }
00468 
00469 
00470 static struct mi_root * mi_reload_rules(struct mi_root *cmd_tree, void *param)
00471 {
00472         struct mi_root* rpl_tree= NULL;
00473 
00474         if (dp_connect_db() < 0) {
00475                 LM_ERR("failed to reload rules fron database (db connect)\n");
00476                 return 0;
00477         }
00478 
00479         if(dp_load_db() != 0){
00480                 LM_ERR("failed to reload rules fron database (db load)\n");
00481                 dp_disconnect_db();
00482                 return 0;
00483         }
00484 
00485         dp_disconnect_db();
00486 
00487         rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00488         if (rpl_tree==0)
00489                 return 0;
00490 
00491         return rpl_tree;
00492 }
00493 
00494 /* 
00495  *  mi cmd:  dp_translate
00496  *                      <dialplan id> 
00497  *                      <input>
00498  *              * */
00499 
00500 static struct mi_root * mi_translate(struct mi_root *cmd, void *param)
00501 {
00502 
00503         struct mi_root* rpl= NULL;
00504         struct mi_node* root, *node;
00505         dpl_id_p idp;
00506         str dpid_str;
00507         str input;
00508         int dpid;
00509         str attrs;
00510         str output= {0, 0};
00511 
00512         node = cmd->node.kids;
00513         if(node == NULL)
00514                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00515 
00516         /* Get the id parameter */
00517         dpid_str = node->value;
00518         if(dpid_str.s == NULL || dpid_str.len== 0)      {
00519                 LM_ERR( "empty idp parameter\n");
00520                 return init_mi_tree(404, "Empty id parameter", 18);
00521         }
00522         if(str2sint(&dpid_str, &dpid) != 0)     {
00523                 LM_ERR("Wrong id parameter - should be an integer\n");
00524                 return init_mi_tree(404, "Wrong id parameter", 18);
00525         }
00526 
00527         if ((idp = select_dpid(dpid)) ==0 ){
00528                 LM_ERR("no information available for dpid %i\n", dpid);
00529                 return init_mi_tree(404, "No information available for dpid", 33);
00530         }
00531 
00532         node = node->next;
00533         if(node == NULL)
00534                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00535 
00536         if(node->next!= NULL)
00537                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00538 
00539         input=  node->value;
00540         if(input.s == NULL || input.len== 0)    {
00541                 LM_ERR( "empty input parameter\n");
00542                 return init_mi_tree(404, "Empty input parameter", 21);
00543         }
00544 
00545         LM_DBG("trying to translate %.*s with dpid %i\n",
00546                         input.len, input.s, idp->dp_id);
00547         if (translate(NULL, input, &output, idp, &attrs)!=0){
00548                 LM_DBG("could not translate %.*s with dpid %i\n", 
00549                                 input.len, input.s, idp->dp_id);
00550                 return init_mi_tree(404, "No translation", 14);
00551         }
00552         LM_DBG("input %.*s with dpid %i => output %.*s\n",
00553                         input.len, input.s, idp->dp_id, output.len, output.s);
00554 
00555         rpl = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00556         if (rpl==0)
00557                 goto error;
00558 
00559         root= &rpl->node;
00560 
00561         node = add_mi_node_child(root, 0, "Output", 6, output.s, output.len );
00562         if( node == NULL)
00563                 goto error;
00564 
00565         node = add_mi_node_child(root, 0, "ATTRIBUTES", 10, attrs.s, attrs.len);
00566         if( node == NULL)
00567                 goto error;
00568 
00569         return rpl;
00570 
00571 error:
00572         if(rpl)
00573                 free_mi_tree(rpl);
00574         return 0;
00575 }
00576 
00577 static const char* dialplan_rpc_reload_doc[2] = {
00578         "Reload dialplan table from database",
00579         0
00580 };
00581 
00582 
00583 /*
00584  * RPC command to reload dialplan table
00585  */
00586 static void dialplan_rpc_reload(rpc_t* rpc, void* ctx)
00587 {
00588         if (dp_connect_db() < 0) {
00589                 LM_ERR("failed to reload rules fron database (db connect)\n");
00590                 rpc->fault(ctx, 500, "DB Connection Error");
00591                 return;
00592         }
00593 
00594         if(dp_load_db() != 0){
00595                 LM_ERR("failed to reload rules fron database (db load)\n");
00596                 dp_disconnect_db();
00597                 rpc->fault(ctx, 500, "Dialplan Reload Failed");
00598                 return;
00599         }
00600 
00601         dp_disconnect_db();
00602         return;
00603 }
00604 
00605 
00606 
00607 static const char* dialplan_rpc_translate_doc[2] = {
00608         "Perform dialplan translation",
00609         0
00610 };
00611 
00612 
00613 /*
00614  * RPC command to perform dialplan translation
00615  */
00616 static void dialplan_rpc_translate(rpc_t* rpc, void* ctx)
00617 {
00618         dpl_id_p idp;
00619         str input;
00620         int dpid;
00621         str attrs  = {"", 0};
00622         str output = {0, 0};
00623         void* th;
00624 
00625         if (rpc->scan(ctx, "dS", &dpid, &input) < 2)
00626         {
00627                 rpc->fault(ctx, 500, "Invalid parameters");
00628                 return;
00629         }
00630 
00631         if ((idp = select_dpid(dpid)) == 0 ){
00632                 LM_ERR("no information available for dpid %i\n", dpid);
00633                 rpc->fault(ctx, 500, "Dialplan ID not matched");
00634                 return;
00635         }
00636 
00637         if(input.s == NULL || input.len== 0)    {
00638                 LM_ERR("empty input parameter\n");
00639                 rpc->fault(ctx, 500, "Empty input parameter");
00640                 return;
00641         }
00642 
00643         LM_DBG("trying to translate %.*s with dpid %i\n",
00644                         input.len, input.s, idp->dp_id);
00645         if (translate(NULL, input, &output, idp, &attrs)!=0){
00646                 LM_DBG("could not translate %.*s with dpid %i\n",
00647                                 input.len, input.s, idp->dp_id);
00648                 rpc->fault(ctx, 500, "No translation");
00649                 return;
00650         }
00651         LM_DBG("input %.*s with dpid %i => output %.*s\n",
00652                         input.len, input.s, idp->dp_id, output.len, output.s);
00653 
00654         if (rpc->add(ctx, "{", &th) < 0)
00655         {
00656                 rpc->fault(ctx, 500, "Internal error creating rpc");
00657                 return;
00658         }
00659         if(rpc->struct_add(th, "SS",
00660                                 "Output", &output,
00661                                 "Attributes", &attrs)<0)
00662         {
00663                 rpc->fault(ctx, 500, "Internal error creating rpc");
00664                 return;
00665         }
00666 
00667         return;
00668 }
00669 
00670 
00671 rpc_export_t dialplan_rpc_list[] = {
00672         {"dialplan.reload", dialplan_rpc_reload,
00673                 dialplan_rpc_reload_doc, 0},
00674         {"dialplan.dump",   dialplan_rpc_translate,
00675                 dialplan_rpc_translate_doc, 0},
00676         {0, 0, 0, 0}
00677 };
00678 
00679 static int dialplan_init_rpc(void)
00680 {
00681         if (rpc_register_array(dialplan_rpc_list)!=0)
00682         {
00683                 LM_ERR("failed to register RPC commands\n");
00684                 return -1;
00685         }
00686         return 0;
00687 }