diff --git a/apps/app_dial.c b/apps/app_dial.c index 176fec54056497283590f3259a005a25df97e4c3..564ff868213979da56c2331167cbc3ef8cb205d1 100755 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -68,7 +68,13 @@ static char *descrip = " that are assigned to you.\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(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 caller to hang up by hitting *.\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 sdtmfdata[256] = ""; char *stack,*var; - char *mac = NULL, macroname[256] = ""; + char *mac = NULL, *macroname = NULL; char status[256]=""; char toast[80]; 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; int vartype; char *outbound_group = NULL; - + char *macro_result = NULL, *macro_transfer_dest = NULL; int digit = 0; time_t start_time, answer_time, end_time; + struct ast_app *app = NULL; if (!data) { 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 */ if ((mac = strstr(transfer, "M("))) { hasmacro = 1; - strncpy(macroname, mac + 2, sizeof(macroname) - 1); + macroname = ast_strdupa(mac + 2); while (*mac && (*mac != ')')) *(mac++) = 'X'; if (*mac) @@ -1001,8 +1008,6 @@ static int dial_exec(struct ast_channel *chan, void *data) res = 0; if (hasmacro && macroname) { - void *app = NULL; - res = ast_autoservice_start(chan); if (res) { 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"); if (app && !res) { + for(res=0;res<strlen(macroname);res++) + if(macroname[res] == '^') + macroname[res] = '|'; res = pbx_exec(peer, app, macroname, 1); ast_log(LOG_DEBUG, "Macro exited with status %d\n", res); 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"); 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) { diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 327a4eea9351695c01e6ccbe4bace6e352de3830..4343dc35cc53e58e3be9931c999ae945ff4c7cae 100755 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -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 fall through (reads extension instead). Returns previous value. */ 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) } #endif diff --git a/pbx.c b/pbx.c index 7141ad266cdb9d79ca4936365cbd94208effe6d6..14fcf26cbeaafcd8f4330b479e8ee9cc414d80ac 100755 --- a/pbx.c +++ b/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) { - char *s; - char *exten, *pri, *context; - char *stringp=NULL; - 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) + int res; + res = ast_parseable_goto(chan, (const char *) data); + if (!res && (option_verbose > 2)) ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1); - ast_cdr_update(chan); - return 0; + return res; } + int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size) { struct ast_var_t *variables; @@ -5469,3 +5419,89 @@ int ast_context_verify_includes(struct ast_context *con) 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; + +} + +