Add improved macro functionality (bug #2905)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4317 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.2-netsec
Mark Spencer 21 years ago
parent 4562f0632a
commit d7da317979

@ -68,7 +68,13 @@ static char *descrip =
" that are assigned to you.\n" " that are assigned to you.\n"
" 'r' -- indicate ringing to the calling party, pass no audio until answered.\n" " 'r' -- indicate ringing to the calling party, pass no audio until answered.\n"
" 'm' -- provide hold music to the calling party until answered.\n" " 'm' -- provide hold music to the calling party until answered.\n"
" 'M(x) -- Executes the macro (x) upon connect of the call\n" " 'M(x[^arg]) -- Executes the macro (x with ^ delim arg list) upon connect of the call.\n"
" Also, the macro can set the MACRO_RESULT variable to do the following:\n"
" -- ABORT - Hangup both legs of the call.\n"
" -- CONGESTION - Behave as if line congestion was encountered.\n"
" -- BUSY - Behave as if a busy signal was encountered. (n+101)\n"
" -- CONTINUE - Hangup the called party and continue on in the dialplan.\n"
" -- GOTO:<context>^<exten>^<priority> - Transfer the call.\n"
" 'h' -- allow callee to hang up by hitting *.\n" " 'h' -- allow callee to hang up by hitting *.\n"
" 'H' -- allow caller to hang up by hitting *.\n" " 'H' -- allow caller to hang up by hitting *.\n"
" 'C' -- reset call detail record for this call.\n" " 'C' -- reset call detail record for this call.\n"
@ -484,7 +490,7 @@ static int dial_exec(struct ast_channel *chan, void *data)
char *sdtmfptr; char *sdtmfptr;
char sdtmfdata[256] = ""; char sdtmfdata[256] = "";
char *stack,*var; char *stack,*var;
char *mac = NULL, macroname[256] = ""; char *mac = NULL, *macroname = NULL;
char status[256]=""; char status[256]="";
char toast[80]; char toast[80];
int play_to_caller=0,play_to_callee=0; int play_to_caller=0,play_to_callee=0;
@ -492,9 +498,10 @@ static int dial_exec(struct ast_channel *chan, void *data)
char *varname; char *varname;
int vartype; int vartype;
char *outbound_group = NULL; char *outbound_group = NULL;
char *macro_result = NULL, *macro_transfer_dest = NULL;
int digit = 0; int digit = 0;
time_t start_time, answer_time, end_time; time_t start_time, answer_time, end_time;
struct ast_app *app = NULL;
if (!data) { if (!data) {
ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout|options)\n"); ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout|options)\n");
@ -661,7 +668,7 @@ static int dial_exec(struct ast_channel *chan, void *data)
/* Get the macroname from the dial option string */ /* Get the macroname from the dial option string */
if ((mac = strstr(transfer, "M("))) { if ((mac = strstr(transfer, "M("))) {
hasmacro = 1; hasmacro = 1;
strncpy(macroname, mac + 2, sizeof(macroname) - 1); macroname = ast_strdupa(mac + 2);
while (*mac && (*mac != ')')) while (*mac && (*mac != ')'))
*(mac++) = 'X'; *(mac++) = 'X';
if (*mac) if (*mac)
@ -1001,8 +1008,6 @@ static int dial_exec(struct ast_channel *chan, void *data)
res = 0; res = 0;
if (hasmacro && macroname) { if (hasmacro && macroname) {
void *app = NULL;
res = ast_autoservice_start(chan); res = ast_autoservice_start(chan);
if (res) { if (res) {
ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
@ -1012,6 +1017,9 @@ static int dial_exec(struct ast_channel *chan, void *data)
app = pbx_findapp("Macro"); app = pbx_findapp("Macro");
if (app && !res) { if (app && !res) {
for(res=0;res<strlen(macroname);res++)
if(macroname[res] == '^')
macroname[res] = '|';
res = pbx_exec(peer, app, macroname, 1); res = pbx_exec(peer, app, macroname, 1);
ast_log(LOG_DEBUG, "Macro exited with status %d\n", res); ast_log(LOG_DEBUG, "Macro exited with status %d\n", res);
res = 0; res = 0;
@ -1024,6 +1032,47 @@ static int dial_exec(struct ast_channel *chan, void *data)
ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
res = -1; res = -1;
} }
if (!res) {
if ((macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
if (!strcasecmp(macro_result, "BUSY")) {
strncpy(status, macro_result, sizeof(status) - 1);
if (!ast_goto_if_exists(chan, NULL, NULL, chan->priority + 101)) {
go_on = 1;
}
res = -1;
}
else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
strncpy(status, macro_result, sizeof(status) - 1);
go_on = 1;
res = -1;
}
else if (!strcasecmp(macro_result, "CONTINUE")) {
/* hangup peer and keep chan alive assuming the macro has changed
the context / exten / priority or perhaps
the next priority in the current exten is desired.
*/
go_on = 1;
res = -1;
} else if (!strcasecmp(macro_result, "ABORT")) {
/* Hangup both ends unless the caller has the g flag */
res = -1;
} else if(!strncasecmp(macro_result, "GOTO:",5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) {
res = -1;
/* perform a transfer to a new extension */
if(strchr(macro_transfer_dest,'^')) { /* context^exten^priority*/
/* no brainer mode... substitute ^ with | and feed it to builtin goto */
for(res=0;res<strlen(macro_transfer_dest);res++)
if(macro_transfer_dest[res] == '^')
macro_transfer_dest[res] = '|';
if(!ast_parsable_goto(chan, macro_transfer_dest))
go_on = 1;
}
}
}
}
} }
if (!res) { if (!res) {

@ -578,7 +578,9 @@ int ast_extension_patmatch(const char *pattern, const char *data);
set to 1, sets to auto fall through. If newval set to 0, sets to no auto set to 1, sets to auto fall through. If newval set to 0, sets to no auto
fall through (reads extension instead). Returns previous value. */ fall through (reads extension instead). Returns previous value. */
extern int pbx_set_autofallthrough(int newval); extern int pbx_set_autofallthrough(int newval);
int ast_goto_if_exists(struct ast_channel *chan, char* context, char *exten, int priority);
/* I can find neither parsable nor parseable at dictionary.com, but google gives me 169000 hits for parseable and only 49,800 for parsable */
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string);
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
} }
#endif #endif

146
pbx.c

@ -4935,64 +4935,14 @@ static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
static int pbx_builtin_goto(struct ast_channel *chan, void *data) static int pbx_builtin_goto(struct ast_channel *chan, void *data)
{ {
char *s; int res;
char *exten, *pri, *context; res = ast_parseable_goto(chan, (const char *) data);
char *stringp=NULL; if (!res && (option_verbose > 2))
int ipri;
int mode = 0;
if (!data || ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
return -1;
}
s = ast_strdupa((void *) data);
stringp=s;
context = strsep(&stringp, "|");
exten = strsep(&stringp, "|");
if (!exten) {
/* Only a priority in this one */
pri = context;
exten = NULL;
context = NULL;
} else {
pri = strsep(&stringp, "|");
if (!pri) {
/* Only an extension and priority in this one */
pri = exten;
exten = context;
context = NULL;
}
}
if (*pri == '+') {
mode = 1;
pri++;
} else if (*pri == '-') {
mode = -1;
pri++;
}
if (sscanf(pri, "%i", &ipri) != 1) {
if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, (exten && strcasecmp(exten, "BYEXTENSION")) ? exten : chan->exten,
pri, chan->cid.cid_num)) < 1) {
ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
return -1;
} else
mode = 0;
}
/* At this point we have a priority and maybe an extension and a context */
if (mode)
chan->priority += mode * ipri - 1;
else
chan->priority = ipri - 1;
if (exten && strcasecmp(exten, "BYEXTENSION"))
strncpy(chan->exten, exten, sizeof(chan->exten)-1);
if (context)
strncpy(chan->context, context, sizeof(chan->context)-1);
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1); ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
ast_cdr_update(chan); return res;
return 0;
} }
int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size) int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
{ {
struct ast_var_t *variables; struct ast_var_t *variables;
@ -5469,3 +5419,89 @@ int ast_context_verify_includes(struct ast_context *con)
return res; return res;
} }
int ast_goto_if_exists(struct ast_channel *chan, char* context, char *exten, int priority)
{
if(chan) {
if(ast_exists_extension(chan,
context ? context : chan->context,
exten ? exten : chan->exten,
priority ? priority : chan->priority,
chan->cid.cid_num)) {
return ast_async_goto(chan,
context ? context : chan->context,
exten ? exten : chan->exten,
priority ? priority : chan->priority);
} else
return -3;
}
return -2;
}
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
{
char *s;
char *exten, *pri, *context;
char *stringp=NULL;
int ipri;
int mode = 0;
if (!goto_string || ast_strlen_zero(goto_string)) {
ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
return -1;
}
s = ast_strdupa(goto_string);
stringp=s;
context = strsep(&stringp, "|");
exten = strsep(&stringp, "|");
if (!exten) {
/* Only a priority in this one */
pri = context;
exten = NULL;
context = NULL;
} else {
pri = strsep(&stringp, "|");
if (!pri) {
/* Only an extension and priority in this one */
pri = exten;
exten = context;
context = NULL;
}
}
if (*pri == '+') {
mode = 1;
pri++;
} else if (*pri == '-') {
mode = -1;
pri++;
}
if (sscanf(pri, "%i", &ipri) != 1) {
if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, (exten && strcasecmp(exten, "BYEXTENSION")) ? exten : chan->exten,
pri, chan->cid.cid_num)) < 1) {
ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
return -1;
} else
mode = 0;
}
/* At this point we have a priority and maybe an extension and a context */
if (exten && !strcasecmp(exten, "BYEXTENSION"))
exten = NULL;
if (mode)
ipri = chan->priority + (ipri * mode);
/* This channel is currently in the PBX */
if (context && !ast_strlen_zero(context))
strncpy(chan->context, context, sizeof(chan->context) - 1);
if (exten && !ast_strlen_zero(exten))
strncpy(chan->exten, exten, sizeof(chan->context) - 1);
chan->priority = ipri - 1;
ast_cdr_update(chan);
return 0;
}

Loading…
Cancel
Save