Index: res/res_features.c =================================================================== RCS file: /usr/cvsroot/asterisk/res/res_features.c,v retrieving revision 1.44 diff -u -r1.44 res_features.c --- res/res_features.c 17 Mar 2005 21:52:57 -0000 1.44 +++ res/res_features.c 23 Mar 2005 16:19:12 -0000 @@ -362,7 +362,7 @@ #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) { @@ -767,26 +767,113 @@ 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 }, }; + +/* First we have an empty feature set*/ +struct ast_call_feature *feature_set=NULL; +AST_MUTEX_DEFINE_STATIC(feature_set_lock); + + +/* register new feature into feature_set*/ +void ast_register_feature(struct ast_call_feature *feature) +{ + struct ast_call_feature *tmp; + + if (!feature) { + ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); + return; + } + + feature->next=NULL; + + ast_mutex_lock(&feature_set_lock); + if (!feature_set) { + feature_set=feature; + } else { + + for (tmp=feature_set; tmp && tmp->next; tmp=tmp->next ) ; + tmp->next=feature; + } + ast_mutex_unlock(&feature_set_lock); + if (option_verbose >= 2) + ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->fname); +} + +/* unregister feature from feature_set*/ +void ast_unregister_feature(struct ast_call_feature *feature) +{ + struct ast_call_feature *tmp; + + ast_mutex_lock(&feature_set_lock); + for (tmp=feature_set; tmp && tmp->next; tmp=tmp->next ) + if (tmp->next==feature) break; + + if (tmp ) { + tmp->next=tmp->next->next; + } + + if (feature == feature_set ) { + feature_set=NULL; + } + ast_mutex_unlock(&feature_set_lock); +} + + +/* find a feature by name */ +static struct ast_call_feature *find_feature(char *name) +{ + struct ast_call_feature *tmp=NULL; + + + ast_mutex_lock(&feature_set_lock); + for (tmp=feature_set; tmp; tmp=tmp->next ) + if (!strcasecmp(tmp->sname,name)) break; + ast_mutex_unlock(&feature_set_lock); + + 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_mutex_lock(&feature_set_lock); + for (feature=feature_set; feature; feature=feature->next ) + if (!strcasecmp(feature->exten,code)) break; + ast_mutex_unlock(&feature_set_lock); + + 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; @@ -815,6 +902,8 @@ int x; struct ast_flags features; int res = FEATURE_RETURN_PASSDIGITS; + struct ast_call_feature *feature=NULL; + 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); @@ -830,10 +919,31 @@ break; } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { if (res == FEATURE_RETURN_PASSDIGITS) - res = FEATURE_RETURN_STOREDIGITS; + res = FEATURE_RETURN_STOREDIGITS; } } } + + + if (dynamic_features) { + ast_mutex_lock(&feature_set_lock); + for (feature=feature_set; feature; feature=feature->next) { + if (!ast_strlen_zero(feature->exten) && + strstr(dynamic_features,feature->sname) ) { + /* Feature is up for consideration */ + if (!strcmp(feature->exten, code)) { + ast_mutex_unlock(&feature_set_lock); + res = feature->operation(chan, peer, config, code, sense); + ast_mutex_lock(&feature_set_lock); + break; + } else if (!strncmp(feature->exten, code, strlen(code))) { + res = FEATURE_RETURN_STOREDIGITS; + } + } + } + ast_mutex_unlock(&feature_set_lock); + } + return res; } @@ -1553,12 +1663,70 @@ } var = var->next; } + unmap_features(); var = ast_variable_browse(cfg, "featuremap"); while(var) { if (remap_feature(var->name, var->value)) ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); var = var->next; + } + + /* Map a key combination to an application*/ + var = ast_variable_browse(cfg, "applicationmap"); + while(var) { + char *exten=NULL, *party=NULL, *app=NULL, *app_args=NULL, *tokb; + exten=strtok_r(var->value,",",&tokb); + if (exten) party=strtok_r(NULL,",",&tokb); + if (party) app=strtok_r(NULL,",",&tokb); + + if (app) app_args=strtok_r(NULL,",",&tokb); + + if (!app || !exten || !party) { + ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension or app aren't provided\n"); + continue; + } + + { + struct ast_call_feature *feature=find_feature(var->name); + if (!feature) { + feature=malloc(sizeof(struct ast_call_feature)); + memset(feature,0,sizeof(struct ast_call_feature)); + if (!feature) { + ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n"); + continue; + } + + strncpy(feature->sname,var->name,FEATURE_SNAME_LEN); + strncpy(feature->app,app,FEATURE_APP_LEN); + if (!strcasecmp(party,"caller")) + ast_set_flag(feature,AST_FEATURE_FLAG_CALLER); + else + ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE); + if (app_args) strncpy(feature->app_args,app_args,FEATURE_APP_ARGS_LEN); + strcpy(feature->exten, exten); + feature->operation=feature_exec_app; + ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF); + ast_register_feature(feature); + } else { + strncpy(feature->sname,var->name,FEATURE_SNAME_LEN); + ast_clear_flag(feature, AST_FEATURE_FLAG_CALLER); + ast_clear_flag(feature, AST_FEATURE_FLAG_CALLEE); + if (!strcasecmp(party,"caller")) + ast_set_flag(feature,AST_FEATURE_FLAG_CALLER); + else + ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE); + + strncpy(feature->app,app,FEATURE_APP_LEN); + if (app_args) strncpy(feature->app_args,app_args,FEATURE_APP_ARGS_LEN); + strcpy(feature->exten, exten); + ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF); + } + + if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "ReMapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten); + + } + var = var->next; } ast_config_destroy(cfg); } Index: include/asterisk/features.h =================================================================== RCS file: /usr/cvsroot/asterisk/include/asterisk/features.h,v retrieving revision 1.4 diff -u -r1.4 features.h --- include/asterisk/features.h 15 Jan 2005 23:48:12 -0000 1.4 +++ include/asterisk/features.h 23 Mar 2005 16:19:12 -0000 @@ -17,6 +17,27 @@ #ifndef _AST_FEATURES_H #define _AST_FEATURES_H + +#define FEATURE_MAX_LEN 11 +#define FEATURE_APP_LEN 64 +#define FEATURE_APP_ARGS_LEN 256 +#define FEATURE_SNAME_LEN 32 +/* main call feature structure */ +struct ast_call_feature { + int feature_mask; + char *fname; + char sname[FEATURE_SNAME_LEN]; + 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; + char app[FEATURE_APP_LEN]; + char app_args[FEATURE_APP_ARGS_LEN]; + struct ast_call_feature *next; +}; + + + /*! Park a call and read back parked location */ /*! \param chan the channel to actually be parked \param host the channel which will have the parked location read to @@ -50,5 +71,15 @@ extern int ast_pickup_call(struct ast_channel *chan); +/*! register new feature into feature_set + \param feature an ast_call_feature object which contains a keysequence + and a callback function which is called when this keysequence is pressed + during a call. */ +extern void ast_register_feature(struct ast_call_feature *feature); + +/*! unregister feature from feature_set + \param feature the ast_call_feature object which was registered before*/ +extern void ast_unregister_feature(struct ast_call_feature *feature); + #endif /* _AST_FEATURES_H */ Index: configs/features.conf.sample =================================================================== RCS file: /usr/cvsroot/asterisk/configs/features.conf.sample,v retrieving revision 1.9 diff -u -r1.9 features.conf.sample --- configs/features.conf.sample 5 Jan 2005 21:31:40 -0000 1.9 +++ configs/features.conf.sample 23 Mar 2005 16:19:12 -0000 @@ -24,3 +24,8 @@ ;disconnect => *0 ; Disconnect ;automon => *1 ; One Touch Record ;atxfer => *2 ; Attended transfer + +[applicationmap] +;testfeature => #9,callee,Playback,tt-monkeys ;Play tt-monkes to + ;callee if #9 was pressed +