diff options
author | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2005-08-23 02:22:33 +0000 |
---|---|---|
committer | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2005-08-23 02:22:33 +0000 |
commit | 89bf07cab32a022bd8d5f1caf426974d4d09928d (patch) | |
tree | 0c73b873409f35912621d09217c1457933edbb44 /res | |
parent | 3f7567fe1548a9eae22c3d19233139ff219209c9 (diff) |
add ability to map feature sequences to applications (issue #3764)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@6374 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'res')
-rwxr-xr-x | res/res_features.c | 215 |
1 files changed, 200 insertions, 15 deletions
diff --git a/res/res_features.c b/res/res_features.c index c4281ddc8..04d023698 100755 --- a/res/res_features.c +++ b/res/res_features.c @@ -429,7 +429,7 @@ int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int #define FEATURE_SENSE_CHAN (1 << 0) #define FEATURE_SENSE_PEER (1 << 1) -#define FEATURE_MAX_LEN 11 + static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) { @@ -841,26 +841,94 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st return FEATURE_RETURN_SUCCESS; } -struct ast_call_feature { - int feature_mask; - char *fname; - char *sname; - char exten[FEATURE_MAX_LEN]; - char default_exten[FEATURE_MAX_LEN]; - int (*operation)(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense); - unsigned int flags; -}; /* add atxfer and automon as undefined so you can only use em if you configure them */ #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) struct ast_call_feature builtin_features[] = -{ + { { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF }, { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF }, { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF }, { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF }, }; + +static AST_LIST_HEAD(feature_list,ast_call_feature) feature_list; + +/* register new feature into feature_list*/ +void ast_register_feature(struct ast_call_feature *feature) +{ + if (!feature) { + ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); + return; + } + + AST_LIST_LOCK(&feature_list); + AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); + AST_LIST_UNLOCK(&feature_list); + + if (option_verbose >= 2) + ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); +} + +/* unregister feature from feature_list */ +void ast_unregister_feature(struct ast_call_feature *feature) +{ + if (!feature) return; + + AST_LIST_LOCK(&feature_list); + AST_LIST_REMOVE(&feature_list,feature,feature_entry); + AST_LIST_UNLOCK(&feature_list); + free(feature); +} + + +/* find a feature by name */ +static struct ast_call_feature *find_feature(char *name) +{ + struct ast_call_feature *tmp; + + AST_LIST_LOCK(&feature_list); + AST_LIST_TRAVERSE(&feature_list,tmp,feature_entry) { + if (!strcasecmp(tmp->sname,name)) break; + } + AST_LIST_UNLOCK(&feature_list); + + return tmp; +} + +/* exec an app by feature */ +static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) +{ + struct ast_app *app; + struct ast_call_feature *feature; + int res; + + AST_LIST_LOCK(&feature_list); + AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) { + if (!strcasecmp(feature->exten,code)) break; + } + AST_LIST_UNLOCK(&feature_list); + + if (!feature) { /* shouldn't ever happen! */ + ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); + return -1; + } + + app = pbx_findapp(feature->app); + if (app) { + struct ast_channel *work=chan; + if (ast_test_flag(feature,AST_FEATURE_FLAG_CALLEE)) work=peer; + res = pbx_exec(work, app, feature->app_args, 1); + if (res<0) return res; + } else { + ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); + res = -2; + } + + return FEATURE_RETURN_SUCCESS; +} + static void unmap_features(void) { int x; @@ -889,6 +957,8 @@ static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *p int x; struct ast_flags features; int res = FEATURE_RETURN_PASSDIGITS; + struct ast_call_feature *feature; + char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES"); if (sense == FEATURE_SENSE_CHAN) ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); @@ -904,10 +974,46 @@ static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *p break; } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { if (res == FEATURE_RETURN_PASSDIGITS) + res = FEATURE_RETURN_STOREDIGITS; + } + } + } + + + if (dynamic_features) { + char *tmp=strdup(dynamic_features); + char *tok; + char *begin=tmp; + + if (!tmp) { + ast_log(LOG_ERROR,"strdup failed"); + return res; + } + + while ( (tok=strsep(&tmp,"#")) != NULL) { + AST_LIST_LOCK(&feature_list); + AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) { + if ( ! strcasecmp(tok,feature->sname)) + break; + } + AST_LIST_UNLOCK(&feature_list); + + if ( feature ) { + /* Feature is up for consideration */ + if (!strcmp(feature->exten, code)) { + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok); + res = feature->operation(chan, peer, config, code, sense); + break; + } else if (!strncmp(feature->exten, code, strlen(code))) { res = FEATURE_RETURN_STOREDIGITS; + } } } + + free(begin); } + return res; } @@ -1643,10 +1749,11 @@ static int handle_showfeatures(int fd, int argc, char *argv[]) { int i; int fcount; + struct ast_call_feature *feature; char format[] = "%-25s %-7s %-7s\n"; - ast_cli(fd, format, "Feature", "Default", "Current"); - ast_cli(fd, format, "-------", "-------", "-------"); + ast_cli(fd, format, "Builtin Feature", "Default", "Current"); + ast_cli(fd, format, "---------------", "-------", "-------"); ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ @@ -1656,7 +1763,15 @@ static int handle_showfeatures(int fd, int argc, char *argv[]) { ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); } - + ast_cli(fd, "\n"); + ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); + ast_cli(fd, format, "---------------", "-------", "-------"); + AST_LIST_LOCK(&feature_list); + AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) { + ast_cli(fd, format, feature->sname, "no def", feature->exten); + } + AST_LIST_UNLOCK(&feature_list); + return RESULT_SUCCESS; } @@ -1843,6 +1958,7 @@ static int load_config(void) } var = var->next; } + unmap_features(); var = ast_variable_browse(cfg, "featuremap"); while(var) { @@ -1850,8 +1966,74 @@ static int load_config(void) ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); var = var->next; } - ast_config_destroy(cfg); + + /* Map a key combination to an application*/ + var = ast_variable_browse(cfg, "applicationmap"); + while(var) { + char *tmp_val=strdup(var->value); + + if (!tmp_val) { + ast_log(LOG_ERROR, "res_features: strdup failed"); + continue; + } + + char *exten, *party=NULL, *app=NULL, *app_args=NULL; + + exten=strsep(&tmp_val,","); + if (exten) party=strsep(&tmp_val,","); + if (party) app=strsep(&tmp_val,","); + + if (app) app_args=strsep(&tmp_val,","); + + if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) { + ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name or app aren't provided %s %s %s %s\n",app,exten,party,var->name); + free(tmp_val); + var = var->next; + continue; + } + + { + struct ast_call_feature *feature=find_feature(var->name); + int mallocd=0; + + if (!feature) { + feature=malloc(sizeof(struct ast_call_feature)); + mallocd=1; + } + if (!feature) { + ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n"); + free(tmp_val); + var = var->next; + continue; + } + + memset(feature,0,sizeof(struct ast_call_feature)); + ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN); + ast_copy_string(feature->app,app,FEATURE_APP_LEN); + ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN); + free(tmp_val); + + if (app_args) + ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN); + + ast_copy_string(feature->exten, exten,sizeof(feature->exten)); + feature->operation=feature_exec_app; + ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF); + + if (!strcasecmp(party,"caller")) + ast_set_flag(feature,AST_FEATURE_FLAG_CALLER); + else + ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE); + + ast_register_feature(feature); + + if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten); + } + var = var->next; + } } + ast_config_destroy(cfg); + if (con) ast_context_remove_extension2(con, ast_parking_ext(), 1, registrar); @@ -1872,6 +2054,9 @@ int reload(void) { int load_module(void) { int res; + + AST_LIST_HEAD_INIT(&feature_list); + if ((res = load_config())) return res; ast_cli_register(&showparked); |