Allow manager originate to specifiy more than one variable to be set.
authorRussell Bryant <russell@russellbryant.com>
Fri, 15 Jul 2005 23:24:51 +0000 (23:24 +0000)
committerRussell Bryant <russell@russellbryant.com>
Fri, 15 Jul 2005 23:24:51 +0000 (23:24 +0000)
Allow manager originate and spool files to set writable dialplan functions,
including those that use the pipe symbol to seperate arguments.
Allow CDR dialplan function to be able to set the account code and userfield.
This deprecates the use of the Account header in manager originate and spool
files, as well as the SetAccount and SetCDRUserField applications.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6147 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channel.c
funcs/func_cdr.c
include/asterisk/channel.h
include/asterisk/manager.h
include/asterisk/pbx.h
manager.c
pbx.c
pbx/pbx_spool.c
sample.call

index 60e972b..c73b0f3 100755 (executable)
--- a/channel.c
+++ b/channel.c
@@ -2031,20 +2031,8 @@ struct ast_channel *__ast_request_and_dial(const char *type, int format, void *d
        chan = ast_request(type, format, data, &cause);
        if (chan) {
                if (oh) {
        chan = ast_request(type, format, data, &cause);
        if (chan) {
                if (oh) {
-                       char *tmp, *var;
-                       /* JDG chanvar */
-                       if (oh->variable)
-                               variable = ast_strdupa(oh->variable);
-                       else
-                               variable = NULL;
-                       tmp = variable;
-                       /* FIXME replace this call with strsep  NOT*/
-                       while( (var = strtok_r(NULL, "|", &tmp)) ) {
-                               pbx_builtin_setvar( chan, var );
-                       } /* /JDG */
+                       ast_set_variables(chan, oh->vars);
                        ast_set_callerid(chan, oh->cid_num, oh->cid_name, oh->cid_num);
                        ast_set_callerid(chan, oh->cid_num, oh->cid_name, oh->cid_num);
-                       if (oh->account && *oh->account)
-                               ast_cdr_setaccount(chan, oh->account);
                }
                ast_set_callerid(chan, cid_num, cid_name, cid_num);
 
                }
                ast_set_callerid(chan, cid_num, cid_name, cid_num);
 
@@ -2107,7 +2095,8 @@ struct ast_channel *__ast_request_and_dial(const char *type, int format, void *d
                                ast_copy_string(chan->context, oh->context, sizeof(chan->context));
                        if (oh->exten && *oh->exten)
                                ast_copy_string(chan->exten, oh->exten, sizeof(chan->exten));
                                ast_copy_string(chan->context, oh->context, sizeof(chan->context));
                        if (oh->exten && *oh->exten)
                                ast_copy_string(chan->exten, oh->exten, sizeof(chan->exten));
-                       chan->priority = oh->priority;
+                       if (oh->priority)       
+                               chan->priority = oh->priority;
                }
                if (chan->_state == AST_STATE_UP) 
                        state = AST_CONTROL_ANSWER;
                }
                if (chan->_state == AST_STATE_UP) 
                        state = AST_CONTROL_ANSWER;
@@ -3450,3 +3439,11 @@ char *ast_print_group(char *buf, int buflen, ast_group_t group)
        }
        return(buf);
 }
        }
        return(buf);
 }
+
+void ast_set_variables(struct ast_channel *chan, struct ast_variable *vars)
+{
+       struct ast_variable *cur;
+
+       for (cur = vars; cur; cur = cur->next)
+               pbx_builtin_setvar_helper(chan, cur->name, cur->value); 
+}
index 0e9a13e..1220a82 100755 (executable)
@@ -77,7 +77,12 @@ static void builtin_function_cdr_write(struct ast_channel *chan, char *cmd, char
                        recursive = 1;
        }
 
                        recursive = 1;
        }
 
-       ast_cdr_setvar(chan->cdr, argv[0], value, recursive);
+       if (!strcasecmp(argv[0], "accountcode"))
+               ast_cdr_setaccount(chan, value);
+       else if (!strcasecmp(argv[0], "userfield"))
+               ast_cdr_setuserfield(chan, value);
+       else
+               ast_cdr_setvar(chan->cdr, argv[0], value, recursive);
 }
 
 #ifndef BUILTIN_FUNC
 }
 
 #ifndef BUILTIN_FUNC
index 49a7342..9dd3124 100755 (executable)
@@ -20,6 +20,7 @@
 #include "asterisk/frame.h"
 #include "asterisk/sched.h"
 #include "asterisk/chanvars.h"
 #include "asterisk/frame.h"
 #include "asterisk/sched.h"
 #include "asterisk/chanvars.h"
+#include "asterisk/config.h"
 
 #include <unistd.h>
 #include <setjmp.h>
 
 #include <unistd.h>
 #include <setjmp.h>
@@ -387,8 +388,7 @@ struct chanmon;
        oh.priority = priority; \
        oh.cid_num = cid_num; \
        oh.cid_name = cid_name; \
        oh.priority = priority; \
        oh.cid_num = cid_num; \
        oh.cid_name = cid_name; \
-       oh.variable = variable; \
-       oh.account = account; \
+       oh.vars = vars; \
 } 
 
 struct outgoing_helper {
 } 
 
 struct outgoing_helper {
@@ -397,8 +397,7 @@ struct outgoing_helper {
        int priority;
        const char *cid_num;
        const char *cid_name;
        int priority;
        const char *cid_num;
        const char *cid_name;
-       const char *variable;
-       const char *account;
+       struct ast_variable *vars;
 };
 
 #define AST_CDR_TRANSFER       (1 << 0)
 };
 
 #define AST_CDR_TRANSFER       (1 << 0)
@@ -947,6 +946,16 @@ struct ast_channel *ast_bridged_channel(struct ast_channel *chan);
 */
 void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child);
 
 */
 void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child);
 
+/*!
+  \brief adds a list of channel variables to a channel
+  \param chan the channel
+  \param vars a linked list of variables
+
+  Variable names can be for a regular channel variable or a dialplan function
+  that has the ability to be written to.
+*/
+void ast_set_variables(struct ast_channel *chan, struct ast_variable *vars);
+
 /* Misc. functions below */
 
 /* Helper function for migrating select to poll */
 /* Misc. functions below */
 
 /* Helper function for migrating select to poll */
index 6245425..0b2712d 100755 (executable)
@@ -141,6 +141,10 @@ extern int manager_event(int category, char *event, char *contents, ...)
 
 /*! Get header from mananger transaction */
 extern char *astman_get_header(struct message *m, char *var);
 
 /*! Get header from mananger transaction */
 extern char *astman_get_header(struct message *m, char *var);
+
+/*! Get a linked list of the Variable: headers */
+struct ast_variable *astman_get_variables(struct message *m);
+
 /*! Send error in manager transaction */
 extern void astman_send_error(struct mansession *s, struct message *m, char *error);
 extern void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg);
 /*! Send error in manager transaction */
 extern void astman_send_error(struct mansession *s, struct message *m, char *error);
 extern void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg);
index 187372d..b0ca14c 100755 (executable)
@@ -516,11 +516,11 @@ int ast_async_goto_by_name(const char *chan, const char *context, const char *ex
 
 /* Synchronously or asynchronously make an outbound call and send it to a
    particular extension */
 
 /* Synchronously or asynchronously make an outbound call and send it to a
    particular extension */
-int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, const char *variable, const char *account, struct ast_channel **locked_channel);
+int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel);
 
 /* Synchronously or asynchronously make an outbound call and send it to a
    particular application with given extension */
 
 /* Synchronously or asynchronously make an outbound call and send it to a
    particular application with given extension */
-int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, const char *variable, const char *account, struct ast_channel **locked_channel);
+int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel);
 
 /* Functions for returning values from structures */
 const char *ast_get_context_name(struct ast_context *con);
 
 /* Functions for returning values from structures */
 const char *ast_get_context_name(struct ast_context *con);
index 1ebd223..306c217 100755 (executable)
--- a/manager.c
+++ b/manager.c
@@ -46,8 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/acl.h"
 #include "asterisk/utils.h"
 
 #include "asterisk/acl.h"
 #include "asterisk/utils.h"
 
-struct fast_originate_helper
-{
+struct fast_originate_helper {
        char tech[256];
        char data[256];
        int timeout;
        char tech[256];
        char data[256];
        int timeout;
@@ -55,12 +54,11 @@ struct fast_originate_helper
        char appdata[256];
        char cid_name[256];
        char cid_num[256];
        char appdata[256];
        char cid_name[256];
        char cid_num[256];
-       char variable[256];
-       char account[256];
        char context[256];
        char exten[256];
        char idtext[256];
        int priority;
        char context[256];
        char exten[256];
        char idtext[256];
        int priority;
+       struct ast_variable *vars;
 };
 
 static int enabled = 0;
 };
 
 static int enabled = 0;
@@ -283,6 +281,30 @@ char *astman_get_header(struct message *m, char *var)
        return "";
 }
 
        return "";
 }
 
+struct ast_variable *astman_get_variables(struct message *m)
+{
+       int varlen, x;
+       struct ast_variable *head = NULL, *cur;
+       char *var, *val;
+       
+       varlen = strlen("Variable: ");  
+
+       for (x = 0; x < m->hdrcount; x++) {
+               if (!strncasecmp("Variable: ", m->headers[x], varlen)) {
+                       var = val = ast_strdupa(m->headers[x] + varlen);
+                       strsep(&val, "=");
+                       cur = ast_variable_new(var, val);
+                       if (head) {
+                               cur->next = head;
+                               head = cur;
+                       } else
+                               head = cur;
+               }
+       }
+
+       return head;
+}
+
 void astman_send_error(struct mansession *s, struct message *m, char *error)
 {
        char *id = astman_get_header(m,"ActionID");
 void astman_send_error(struct mansession *s, struct message *m, char *error)
 {
        char *id = astman_get_header(m,"ActionID");
@@ -864,12 +886,12 @@ static void *fast_originate(void *data)
                res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, 
                        !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL, 
                        !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
                res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, 
                        !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL, 
                        !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
-                       in->variable, in->account, &chan);
+                       in->vars, &chan);
        } else {
                res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, 
                        !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL, 
                        !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
        } else {
                res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, 
                        !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL, 
                        !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
-                       in->variable, in->account, &chan);
+                       in->vars, &chan);
        }   
        if (!res)
                manager_event(EVENT_FLAG_CALL,
        }   
        if (!res)
                manager_event(EVENT_FLAG_CALL,
@@ -923,12 +945,12 @@ static int action_originate(struct mansession *s, struct message *m)
        char *priority = astman_get_header(m, "Priority");
        char *timeout = astman_get_header(m, "Timeout");
        char *callerid = astman_get_header(m, "CallerID");
        char *priority = astman_get_header(m, "Priority");
        char *timeout = astman_get_header(m, "Timeout");
        char *callerid = astman_get_header(m, "CallerID");
-       char *variable = astman_get_header(m, "Variable");
        char *account = astman_get_header(m, "Account");
        char *app = astman_get_header(m, "Application");
        char *appdata = astman_get_header(m, "Data");
        char *async = astman_get_header(m, "Async");
        char *id = astman_get_header(m, "ActionID");
        char *account = astman_get_header(m, "Account");
        char *app = astman_get_header(m, "Application");
        char *appdata = astman_get_header(m, "Data");
        char *async = astman_get_header(m, "Async");
        char *id = astman_get_header(m, "ActionID");
+       struct ast_variable *vars = astman_get_variables(m);
        char *tech, *data;
        char *l=NULL, *n=NULL;
        int pi = 0;
        char *tech, *data;
        char *l=NULL, *n=NULL;
        int pi = 0;
@@ -936,7 +958,7 @@ static int action_originate(struct mansession *s, struct message *m)
        int to = 30000;
        int reason = 0;
        char tmp[256];
        int to = 30000;
        int reason = 0;
        char tmp[256];
-       char tmp2[256]="";
+       char tmp2[256];
        
        pthread_t th;
        pthread_attr_t attr;
        
        pthread_t th;
        pthread_attr_t attr;
@@ -972,6 +994,12 @@ static int action_originate(struct mansession *s, struct message *m)
                if (ast_strlen_zero(l))
                        l = NULL;
        }
                if (ast_strlen_zero(l))
                        l = NULL;
        }
+       if (account) {
+               struct ast_variable *newvar;
+               newvar = ast_variable_new("CDR(accountcode|r)", account);
+               newvar->next = vars;
+               vars = newvar;
+       }
        if (ast_true(async)) {
                struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
                if (!fast) {
        if (ast_true(async)) {
                struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
                if (!fast) {
@@ -988,8 +1016,7 @@ static int action_originate(struct mansession *s, struct message *m)
                                ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
                        if (n)
                                ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
                                ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
                        if (n)
                                ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
-                       ast_copy_string(fast->variable, variable, sizeof(fast->variable));
-                       ast_copy_string(fast->account, account, sizeof(fast->account));
+                       fast->vars = vars;      
                        ast_copy_string(fast->context, context, sizeof(fast->context));
                        ast_copy_string(fast->exten, exten, sizeof(fast->exten));
                        fast->timeout = to;
                        ast_copy_string(fast->context, context, sizeof(fast->context));
                        ast_copy_string(fast->exten, exten, sizeof(fast->exten));
                        fast->timeout = to;
@@ -1003,10 +1030,10 @@ static int action_originate(struct mansession *s, struct message *m)
                        }
                }
        } else if (!ast_strlen_zero(app)) {
                        }
                }
        } else if (!ast_strlen_zero(app)) {
-               res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, variable, account, NULL);
+               res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, NULL);
        } else {
                if (exten && context && pi)
        } else {
                if (exten && context && pi)
-                       res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, variable, account, NULL);
+                       res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, NULL);
                else {
                        astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
                        return 0;
                else {
                        astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
                        return 0;
diff --git a/pbx.c b/pbx.c
index 3d1d002..be56630 100755 (executable)
--- a/pbx.c
+++ b/pbx.c
@@ -4742,15 +4742,14 @@ int ast_pbx_outgoing_cdr_failed(void)
        return 0;  /* success */
 }
 
        return 0;  /* success */
 }
 
-int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, const char *variable, const char *account, struct ast_channel **channel)
+int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **channel)
 {
        struct ast_channel *chan;
        struct async_stat *as;
        int res = -1, cdr_res = -1;
 {
        struct ast_channel *chan;
        struct async_stat *as;
        int res = -1, cdr_res = -1;
-       char *var, *tmp;
        struct outgoing_helper oh;
        pthread_attr_t attr;
        struct outgoing_helper oh;
        pthread_attr_t attr;
-               
+
        if (sync) {
                LOAD_OH(oh);
                chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
        if (sync) {
                LOAD_OH(oh);
                chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
@@ -4760,25 +4759,21 @@ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout
                                ast_mutex_lock(&chan->lock);
                }
                if (chan) {
                                ast_mutex_lock(&chan->lock);
                }
                if (chan) {
-                       
-                       if (account)
-                               ast_cdr_setaccount(chan, account);
-                       
                        if(chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
                                ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
                        } else {
                                chan->cdr = ast_cdr_alloc();   /* allocate a cdr for the channel */
                        if(chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
                                ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
                        } else {
                                chan->cdr = ast_cdr_alloc();   /* allocate a cdr for the channel */
-                               if(!chan->cdr) {
+                               if (!chan->cdr) {
                                        /* allocation of the cdr failed */
                                        ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
                                        free(chan->pbx);
                                        /* allocation of the cdr failed */
                                        ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
                                        free(chan->pbx);
-                                       return -1;  /* return failure */
+                                       res = -1;
+                                       goto outgoing_exten_cleanup;
                                }
                                /* allocation of the cdr was successful */
                                ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
                                ast_cdr_start(chan->cdr);
                        }
                                }
                                /* allocation of the cdr was successful */
                                ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
                                ast_cdr_start(chan->cdr);
                        }
-
                        if (chan->_state == AST_STATE_UP) {
                                        res = 0;
                                if (option_verbose > 3)
                        if (chan->_state == AST_STATE_UP) {
                                        res = 0;
                                if (option_verbose > 3)
@@ -4805,7 +4800,7 @@ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout
                                if(chan->cdr) { /* update the cdr */
                                        /* here we update the status of the call, which sould be busy.
                                         * if that fails then we set the status to failed */
                                if(chan->cdr) { /* update the cdr */
                                        /* here we update the status of the call, which sould be busy.
                                         * if that fails then we set the status to failed */
-                                       if(ast_cdr_disposition(chan->cdr, chan->hangupcause))
+                                       if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
                                                ast_cdr_failed(chan->cdr);
                                }
                        
                                                ast_cdr_failed(chan->cdr);
                                }
                        
@@ -4814,29 +4809,26 @@ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout
                }
 
                if(res < 0) { /* the call failed for some reason */
                }
 
                if(res < 0) { /* the call failed for some reason */
-                       if(*reason == 0) { /* if the call failed (not busy or no answer)
+                       if (*reason == 0) { /* if the call failed (not busy or no answer)
                                            * update the cdr with the failed message */
                                cdr_res = ast_pbx_outgoing_cdr_failed();
                                            * update the cdr with the failed message */
                                cdr_res = ast_pbx_outgoing_cdr_failed();
-                               if(cdr_res != 0)
-                                       return cdr_res;
+                               if (cdr_res != 0) {
+                                       res = cdr_res;
+                                       goto outgoing_exten_cleanup;
+                               }
                        }
                        
                        /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
                        /* check if "failed" exists */
                        if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
                                chan = ast_channel_alloc(0);
                        }
                        
                        /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
                        /* check if "failed" exists */
                        if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
                                chan = ast_channel_alloc(0);
-                               if(chan) {
+                               if (chan) {
                                        ast_copy_string(chan->name, "OutgoingSpoolFailed", sizeof(chan->name));
                                        if (context && !ast_strlen_zero(context))
                                                ast_copy_string(chan->context, context, sizeof(chan->context));
                                        ast_copy_string(chan->exten, "failed", sizeof(chan->exten));
                                        chan->priority = 1;
                                        ast_copy_string(chan->name, "OutgoingSpoolFailed", sizeof(chan->name));
                                        if (context && !ast_strlen_zero(context))
                                                ast_copy_string(chan->context, context, sizeof(chan->context));
                                        ast_copy_string(chan->exten, "failed", sizeof(chan->exten));
                                        chan->priority = 1;
-                                       if (variable) {
-                                               tmp = ast_strdupa(variable);
-                                               for (var = strtok_r(tmp, "|", &tmp); var; var = strtok_r(NULL, "|", &tmp)) {
-                                                       pbx_builtin_setvar( chan, var );
-                                               }
-                                       }
+                                       ast_set_variables(chan, vars);
                                        ast_pbx_run(chan);      
                                } else 
                                        ast_log(LOG_WARNING, "Can't allocate the channel structure, skipping execution of extension 'failed'\n");
                                        ast_pbx_run(chan);      
                                } else 
                                        ast_log(LOG_WARNING, "Can't allocate the channel structure, skipping execution of extension 'failed'\n");
@@ -4844,8 +4836,10 @@ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout
                }
        } else {
                as = malloc(sizeof(struct async_stat));
                }
        } else {
                as = malloc(sizeof(struct async_stat));
-               if (!as)
-                       return -1;
+               if (!as) {
+                       res = -1;
+                       goto outgoing_exten_cleanup;
+               }       
                memset(as, 0, sizeof(struct async_stat));
                chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
                if (channel) {
                memset(as, 0, sizeof(struct async_stat));
                chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
                if (channel) {
@@ -4855,30 +4849,28 @@ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout
                }
                if (!chan) {
                        free(as);
                }
                if (!chan) {
                        free(as);
-                       return -1;
+                       res = -1;
+                       goto outgoing_exten_cleanup;
                }
                }
-               if (account)
-                       ast_cdr_setaccount(chan, account);
                as->chan = chan;
                ast_copy_string(as->context, context, sizeof(as->context));
                ast_copy_string(as->exten,  exten, sizeof(as->exten));
                as->priority = priority;
                as->timeout = timeout;
                as->chan = chan;
                ast_copy_string(as->context, context, sizeof(as->context));
                ast_copy_string(as->exten,  exten, sizeof(as->exten));
                as->priority = priority;
                as->timeout = timeout;
-               if (variable) {
-                       tmp = ast_strdupa(variable);
-                       for (var = strtok_r(tmp, "|", &tmp); var; var = strtok_r(NULL, "|", &tmp))
-                               pbx_builtin_setvar( chan, var );
-               }
+               ast_set_variables(chan, vars);
                pthread_attr_init(&attr);
                pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
                if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
                        ast_log(LOG_WARNING, "Failed to start async wait\n");
                        free(as);
                        ast_hangup(chan);
                pthread_attr_init(&attr);
                pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
                if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
                        ast_log(LOG_WARNING, "Failed to start async wait\n");
                        free(as);
                        ast_hangup(chan);
-                       return -1;
+                       res = -1;
+                       goto outgoing_exten_cleanup;
                }
                res = 0;
        }
                }
                res = 0;
        }
+outgoing_exten_cleanup:
+       ast_variables_destroy(vars);
        return res;
 }
 
        return res;
 }
 
@@ -4905,26 +4897,28 @@ static void *ast_pbx_run_app(void *data)
        return NULL;
 }
 
        return NULL;
 }
 
-int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, const char *variable, const char *account, struct ast_channel **locked_channel)
+int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel)
 {
        struct ast_channel *chan;
        struct async_stat *as;
        struct app_tmp *tmp;
 {
        struct ast_channel *chan;
        struct async_stat *as;
        struct app_tmp *tmp;
-       char *var, *vartmp;
        int res = -1, cdr_res = -1;
        int res = -1, cdr_res = -1;
+       struct outgoing_helper oh;
        pthread_attr_t attr;
        
        pthread_attr_t attr;
        
+       memset(&oh, 0, sizeof(oh));
+       oh.vars = vars; 
+
        if (locked_channel) 
                *locked_channel = NULL;
        if (locked_channel) 
                *locked_channel = NULL;
-       if (!app || ast_strlen_zero(app))
-               return -1;
+       if (!app || ast_strlen_zero(app)) {
+               res = -1;
+               goto outgoing_app_cleanup;      
+       }
        if (sync) {
        if (sync) {
-               chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
+               chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
                if (chan) {
                if (chan) {
-                       if (account)
-                               ast_cdr_setaccount(chan, account);
-                       
-                       if(chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
+                       if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
                                ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
                        } else {
                                chan->cdr = ast_cdr_alloc();   /* allocate a cdr for the channel */
                                ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
                        } else {
                                chan->cdr = ast_cdr_alloc();   /* allocate a cdr for the channel */
@@ -4932,19 +4926,14 @@ int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout,
                                        /* allocation of the cdr failed */
                                        ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
                                        free(chan->pbx);
                                        /* allocation of the cdr failed */
                                        ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
                                        free(chan->pbx);
-                                       return -1;  /* return failure */
+                                       res = -1;
+                                       goto outgoing_app_cleanup;
                                }
                                /* allocation of the cdr was successful */
                                ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
                                ast_cdr_start(chan->cdr);
                        }
                                }
                                /* allocation of the cdr was successful */
                                ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
                                ast_cdr_start(chan->cdr);
                        }
-                       
-                       if (variable) {
-                               vartmp = ast_strdupa(variable);
-                               for (var = strtok_r(vartmp, "|", &vartmp); var; var = strtok_r(NULL, "|", &vartmp)) {
-                                       pbx_builtin_setvar( chan, var );
-                               }
-                       }
+                       ast_set_variables(chan, vars);
                        if (chan->_state == AST_STATE_UP) {
                                res = 0;
                                if (option_verbose > 3)
                        if (chan->_state == AST_STATE_UP) {
                                res = 0;
                                if (option_verbose > 3)
@@ -4984,47 +4973,46 @@ int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout,
                        } else {
                                if (option_verbose > 3)
                                        ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
                        } else {
                                if (option_verbose > 3)
                                        ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
-                               if(chan->cdr) { /* update the cdr */
+                               if (chan->cdr) { /* update the cdr */
                                        /* here we update the status of the call, which sould be busy.
                                         * if that fails then we set the status to failed */
                                        /* here we update the status of the call, which sould be busy.
                                         * if that fails then we set the status to failed */
-                                       if(ast_cdr_disposition(chan->cdr, chan->hangupcause))
+                                       if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
                                                ast_cdr_failed(chan->cdr);
                                }
                                ast_hangup(chan);
                        }
                }
                
                                                ast_cdr_failed(chan->cdr);
                                }
                                ast_hangup(chan);
                        }
                }
                
-               if(res < 0) { /* the call failed for some reason */
-                       if(*reason == 0) { /* if the call failed (not busy or no answer)
+               if (res < 0) { /* the call failed for some reason */
+                       if (*reason == 0) { /* if the call failed (not busy or no answer)
                                            * update the cdr with the failed message */
                                cdr_res = ast_pbx_outgoing_cdr_failed();
                                            * update the cdr with the failed message */
                                cdr_res = ast_pbx_outgoing_cdr_failed();
-                               if(cdr_res != 0)
-                                       return cdr_res;
+                               if (cdr_res != 0) {
+                                       res = cdr_res;
+                                       goto outgoing_app_cleanup;
+                               }
                        }
                }
 
        } else {
                as = malloc(sizeof(struct async_stat));
                        }
                }
 
        } else {
                as = malloc(sizeof(struct async_stat));
-               if (!as)
-                       return -1;
+               if (!as) {
+                       res = -1;
+                       goto outgoing_app_cleanup;
+               }
                memset(as, 0, sizeof(struct async_stat));
                chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
                if (!chan) {
                        free(as);
                memset(as, 0, sizeof(struct async_stat));
                chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
                if (!chan) {
                        free(as);
-                       return -1;
+                       res = -1;
+                       goto outgoing_app_cleanup;
                }
                }
-               if (account)
-                       ast_cdr_setaccount(chan, account);
                as->chan = chan;
                ast_copy_string(as->app, app, sizeof(as->app));
                if (appdata)
                        ast_copy_string(as->appdata,  appdata, sizeof(as->appdata));
                as->timeout = timeout;
                as->chan = chan;
                ast_copy_string(as->app, app, sizeof(as->app));
                if (appdata)
                        ast_copy_string(as->appdata,  appdata, sizeof(as->appdata));
                as->timeout = timeout;
-               if (variable) {
-                       vartmp = ast_strdupa(variable);
-                       for (var = strtok_r(vartmp, "|", &vartmp); var; var = strtok_r(NULL, "|", &vartmp))
-                               pbx_builtin_setvar( chan, var );
-               }
+               ast_set_variables(chan, vars);
                /* Start a new thread, and get something handling this channel. */
                pthread_attr_init(&attr);
                pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
                /* Start a new thread, and get something handling this channel. */
                pthread_attr_init(&attr);
                pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -5036,13 +5024,16 @@ int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout,
                        if (locked_channel) 
                                ast_mutex_unlock(&chan->lock);
                        ast_hangup(chan);
                        if (locked_channel) 
                                ast_mutex_unlock(&chan->lock);
                        ast_hangup(chan);
-                       return -1;
+                       res = -1;
+                       goto outgoing_app_cleanup;
                } else {
                        if (locked_channel)
                                *locked_channel = chan;
                }
                res = 0;
        }
                } else {
                        if (locked_channel)
                                *locked_channel = chan;
                }
                res = 0;
        }
+outgoing_app_cleanup:
+       ast_variables_destroy(vars);
        return res;
 }
 
        return res;
 }
 
index 5276e18..a1887e1 100755 (executable)
@@ -75,10 +75,8 @@ struct outgoing {
        char cid_num[256];
        char cid_name[256];
 
        char cid_num[256];
        char cid_name[256];
 
-       /* Channel variables */
-       char variable[10*256];
-       /* Account code */
-       char account[256];
+       /* Variables and Functions */
+       struct ast_variable *vars;
        
        /* Maximum length of call */
        int maxlen;
        
        /* Maximum length of call */
        int maxlen;
@@ -98,6 +96,8 @@ static int apply_outgoing(struct outgoing *o, char *fn, FILE *f)
        char buf[256];
        char *c, *c2;
        int lineno = 0;
        char buf[256];
        char *c, *c2;
        int lineno = 0;
+       struct ast_variable *var;
+
        while(fgets(buf, sizeof(buf), f)) {
                lineno++;
                /* Trim comments */
        while(fgets(buf, sizeof(buf), f)) {
                lineno++;
                /* Trim comments */
@@ -176,12 +176,20 @@ static int apply_outgoing(struct outgoing *o, char *fn, FILE *f)
                                        o->callingpid = 0;
                                        o->retries++;
                                } else if (!strcasecmp(buf, "delayedretry")) {
                                        o->callingpid = 0;
                                        o->retries++;
                                } else if (!strcasecmp(buf, "delayedretry")) {
-                               } else if (!strcasecmp(buf, "setvar")) { /* JDG variable support */
-                                       strncat(o->variable, c, sizeof(o->variable) - strlen(o->variable) - 1);
-                                       strncat(o->variable, "|", sizeof(o->variable) - strlen(o->variable) - 1);
-
+                               } else if (!strcasecmp(buf, "setvar") || !strcasecmp(buf, "set")) {
+                                       c2 = c;
+                                       strsep(&c2, "=");
+                                       var = ast_variable_new(c, c2);
+                                       if (var) {
+                                               var->next = o->vars;
+                                               o->vars = var;
+                                       }
                                } else if (!strcasecmp(buf, "account")) {
                                } else if (!strcasecmp(buf, "account")) {
-                                       strncpy(o->account, c, sizeof(o->account) - 1);
+                                       var = ast_variable_new("CDR(accountcode|r)", c);
+                                       if (var) {      
+                                               var->next = o->vars;
+                                               o->vars = var;
+                                       }
                                } else {
                                        ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", buf, lineno, fn);
                                }
                                } else {
                                        ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", buf, lineno, fn);
                                }
@@ -225,11 +233,11 @@ static void *attempt_thread(void *data)
        if (!ast_strlen_zero(o->app)) {
                if (option_verbose > 2)
                        ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries);
        if (!ast_strlen_zero(o->app)) {
                if (option_verbose > 2)
                        ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries);
-               res = ast_pbx_outgoing_app(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->app, o->data, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->variable, o->account, NULL);
+               res = ast_pbx_outgoing_app(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->app, o->data, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, NULL);
        } else {
                if (option_verbose > 2)
                        ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for %s@%s:%d (Retry %d)\n", o->tech, o->dest, o->exten, o->context,o->priority, o->retries);
        } else {
                if (option_verbose > 2)
                        ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for %s@%s:%d (Retry %d)\n", o->tech, o->dest, o->exten, o->context,o->priority, o->retries);
-               res = ast_pbx_outgoing_exten(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->context, o->exten, o->priority, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->variable, o->account, NULL);
+               res = ast_pbx_outgoing_exten(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->context, o->exten, o->priority, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, NULL);
        }
        if (res) {
                ast_log(LOG_NOTICE, "Call failed to go through, reason %d\n", reason);
        }
        if (res) {
                ast_log(LOG_NOTICE, "Call failed to go through, reason %d\n", reason);
index 50b9fa8..38fae5f 100755 (executable)
@@ -37,13 +37,11 @@ Priority: 1
 #Callerid: Wakeup Call Service <(555) 555-5555>
 
 #
 #Callerid: Wakeup Call Service <(555) 555-5555>
 
 #
-# You can set channel variables that will be passed to the channel
-#
-#SetVar: file1=/tmp/to
-#SetVar: file2=/tmp/msg
-#SetVar: timestamp=20021023104500
-
-#
-# You may specify an account to be passed to CDRs
-#
-#Account: markster
+# You can set channel variables that will be passed to the channel.
+# This includes writable dialplan functions.
+#
+#Set: file1=/tmp/to
+#Set: file2=/tmp/msg
+#Set: timestamp=20021023104500
+#Set: CDR(accountcode|r)=blort
+#Set: CDR(userfield|r)=42