Update of /usr/cvsroot/asterisk/res
In directory mongoose.digium.com:/tmp/cvs-serv11443/res

Modified Files:
        res_features.c 
Log Message:
add ability to map feature sequences to applications (issue #3764)


Index: res_features.c
===================================================================
RCS file: /usr/cvsroot/asterisk/res/res_features.c,v
retrieving revision 1.65
retrieving revision 1.66
diff -u -d -r1.65 -r1.66
--- res_features.c      8 Aug 2005 01:16:44 -0000       1.65
+++ res_features.c      23 Aug 2005 02:22:33 -0000      1.66
@@ -429,7 +429,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)
 {
@@ -841,26 +841,94 @@
        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 @@
        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 @@
                                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 @@
 {
        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 @@
        {
                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 @@
                        }
                        var = var->next;
                }
+
                unmap_features();
                var = ast_variable_browse(cfg, "featuremap");
                while(var) {
@@ -1850,8 +1966,74 @@
                                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 load_module(void)
 {
        int res;
+       
+       AST_LIST_HEAD_INIT(&feature_list);
+
        if ((res = load_config()))
                return res;
        ast_cli_register(&showparked);

_______________________________________________
Asterisk-Cvs mailing list
[email protected]
http://lists.digium.com/mailman/listinfo/asterisk-cvs

Reply via email to