PreDial - Ability to run dialplan on callee and caller channels before Dial.

Thanks to Mark Murawski for the initial patch and feature definition.

(closes issue ASTERISK-19548)
Reported by: Mark Murawski

Review: https://reviewboard.asterisk.org/r/1878/
Review: https://reviewboard.asterisk.org/r/1229/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@364436 65c4cc65-6c06-0410-ace0-fbb531ad65f3
certified/11.2
Richard Mudgett 15 years ago
parent f7c174ff84
commit e8a6e0ef0e

@ -141,6 +141,8 @@ Applications
be supplied with arguments indicating where the callee should go after the caller
is hung up, or without options specified, the priority after the Queue/Bridge
will be used.
* Added 'b' and 'B' options to Dial that execute a Gosub on callee and caller
channels respectively before the callee channels are called.
Parking
------------

@ -108,6 +108,27 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
channel before doing anything on the called channel. You will rarely need to use
this option, the default behavior is adequate in most cases.</para>
</option>
<option name="b" argsep="^">
<para>Before initiating the actual call, Gosub to the specified
location using the newly created channel(s). The Gosub will be
executed for each destination channel.</para>
<argument name="context" required="false" />
<argument name="exten" required="false" />
<argument name="priority" required="true" hasparams="optional" argsep="^">
<argument name="arg1" multiple="true" required="true" />
<argument name="argN" />
</argument>
</option>
<option name="B" argsep="^">
<para>Before initiating the actual call, Gosub to the specified
location using the current channel.</para>
<argument name="context" required="false" />
<argument name="exten" required="false" />
<argument name="priority" required="true" hasparams="optional" argsep="^">
<argument name="arg1" multiple="true" required="true" />
<argument name="argN" />
</argument>
</option>
<option name="C">
<para>Reset the call detail record (CDR) for this call.</para>
</option>
@ -587,6 +608,8 @@ enum {
#define OPT_FORCE_CID_TAG (1LLU << 38)
#define OPT_FORCE_CID_PRES (1LLU << 39)
#define OPT_CALLER_ANSWER (1LLU << 40)
#define OPT_PREDIAL_CALLEE (1LLU << 41)
#define OPT_PREDIAL_CALLER (1LLU << 42)
enum {
OPT_ARG_ANNOUNCE = 0,
@ -606,6 +629,8 @@ enum {
OPT_ARG_FORCECLID,
OPT_ARG_FORCE_CID_TAG,
OPT_ARG_FORCE_CID_PRES,
OPT_ARG_PREDIAL_CALLEE,
OPT_ARG_PREDIAL_CALLER,
/* note: this entry _MUST_ be the last one in the enum */
OPT_ARG_ARRAY_SIZE,
};
@ -613,6 +638,8 @@ enum {
AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE),
AST_APP_OPTION('a', OPT_CALLER_ANSWER),
AST_APP_OPTION_ARG('b', OPT_PREDIAL_CALLEE, OPT_ARG_PREDIAL_CALLEE),
AST_APP_OPTION_ARG('B', OPT_PREDIAL_CALLER, OPT_ARG_PREDIAL_CALLER),
AST_APP_OPTION('C', OPT_RESETCDR),
AST_APP_OPTION('c', OPT_CANCEL_ELSEWHERE),
AST_APP_OPTION('d', OPT_DTMF_EXIT),
@ -640,9 +667,9 @@ AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
AST_APP_OPTION_ARG('r', OPT_RINGBACK, OPT_ARG_RINGBACK),
AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
AST_APP_OPTION_ARG('s', OPT_FORCE_CID_TAG, OPT_ARG_FORCE_CID_TAG),
AST_APP_OPTION_ARG('u', OPT_FORCE_CID_PRES, OPT_ARG_FORCE_CID_PRES),
AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
AST_APP_OPTION_ARG('u', OPT_FORCE_CID_PRES, OPT_ARG_FORCE_CID_PRES),
AST_APP_OPTION_ARG('U', OPT_CALLEE_GOSUB, OPT_ARG_CALLEE_GOSUB),
AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
AST_APP_OPTION('W', OPT_CALLER_MONITOR),
@ -662,16 +689,26 @@ END_OPTIONS );
* The list of active channels
*/
struct chanlist {
struct chanlist *next;
AST_LIST_ENTRY(chanlist) node;
struct ast_channel *chan;
/*! Channel interface dialing string (is tech/number). (Stored in stuff[]) */
const char *interface;
/*! Channel technology name. (Stored in stuff[]) */
const char *tech;
/*! Channel device addressing. (Stored in stuff[]) */
const char *number;
uint64_t flags;
/*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
struct ast_party_connected_line connected;
/*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
unsigned int pending_connected_update:1;
struct ast_aoc_decoded *aoc_s_rate_list;
/*! The interface, tech, and number strings are stuffed here. */
char stuff[0];
};
AST_LIST_HEAD_NOLOCK(dial_head, chanlist);
static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str *featurecode);
static void chanlist_free(struct chanlist *outgoing)
@ -681,11 +718,12 @@ static void chanlist_free(struct chanlist *outgoing)
ast_free(outgoing);
}
static void hanguptree(struct chanlist *outgoing, struct ast_channel *exception, int answered_elsewhere)
static void hanguptree(struct dial_head *out_chans, struct ast_channel *exception, int answered_elsewhere)
{
/* Hang up a tree of stuff */
struct chanlist *oo;
while (outgoing) {
struct chanlist *outgoing;
while ((outgoing = AST_LIST_REMOVE_HEAD(out_chans, node))) {
/* Hangup any existing lines we have open */
if (outgoing->chan && (outgoing->chan != exception)) {
if (answered_elsewhere) {
@ -696,9 +734,7 @@ static void hanguptree(struct chanlist *outgoing, struct ast_channel *exception,
}
ast_hangup(outgoing->chan);
}
oo = outgoing;
outgoing = outgoing->next;
chanlist_free(oo);
chanlist_free(outgoing);
}
}
@ -1004,7 +1040,7 @@ struct privacy_args {
};
static struct ast_channel *wait_for_answer(struct ast_channel *in,
struct chanlist *outgoing, int *to, struct ast_flags64 *peerflags,
struct dial_head *out_chans, int *to, struct ast_flags64 *peerflags,
char *opt_args[],
struct privacy_args *pa,
const struct cause_args *num_in, int *result, char *dtmf_progress,
@ -1015,13 +1051,14 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
int prestart = num.busy + num.congestion + num.nochan;
int orig = *to;
struct ast_channel *peer = NULL;
/* single is set if only one destination is enabled */
int single = outgoing && !outgoing->next;
int caller_entertained = outgoing
&& ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
#ifdef HAVE_EPOLL
struct chanlist *epollo;
#endif
struct chanlist *outgoing = AST_LIST_FIRST(out_chans);
/* single is set if only one destination is enabled */
int single = outgoing && !AST_LIST_NEXT(outgoing, node);
int caller_entertained = outgoing
&& ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
struct ast_party_connected_line connected_caller;
struct ast_str *featurecode = ast_str_alloca(FEATURE_MAX_LEN + 1);
int cc_recall_core_id;
@ -1064,8 +1101,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
is_cc_recall = ast_cc_is_recall(in, &cc_recall_core_id, NULL);
#ifdef HAVE_EPOLL
for (epollo = outgoing; epollo; epollo = epollo->next)
AST_LIST_TRAVERSE(out_chans, epollo, node) {
ast_poll_channel_add(in, epollo->chan);
}
#endif
while (*to && !peer) {
@ -1076,7 +1114,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
struct ast_channel *watchers[AST_MAX_WATCHERS];
watchers[pos++] = in;
for (o = outgoing; o; o = o->next) {
AST_LIST_TRAVERSE(out_chans, o, node) {
/* Keep track of important channels */
if (ast_test_flag64(o, DIAL_STILLGOING) && o->chan)
watchers[pos++] = o->chan;
@ -1101,7 +1139,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
return NULL;
}
winner = ast_waitfor_n(watchers, pos, to);
for (o = outgoing; o; o = o->next) {
AST_LIST_TRAVERSE(out_chans, o, node) {
struct ast_frame *f;
struct ast_channel *c = o->chan;
@ -1486,7 +1524,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
}
/* Send the frame from the in channel to all outgoing channels. */
for (o = outgoing; o; o = o->next) {
AST_LIST_TRAVERSE(out_chans, o, node) {
if (!o->chan || !ast_test_flag64(o, DIAL_STILLGOING)) {
/* This outgoing channel has died so don't send the frame to it. */
continue;
@ -1575,7 +1613,7 @@ skip_frame:;
}
#ifdef HAVE_EPOLL
for (epollo = outgoing; epollo; epollo = epollo->next) {
AST_LIST_TRAVERSE(out_chans, epollo, node) {
if (epollo->chan)
ast_poll_channel_del(in, epollo->chan);
}
@ -1918,12 +1956,13 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
{
int res = -1; /* default: error */
char *rest, *cur; /* scan the list of destinations */
struct chanlist *outgoing = NULL; /* list of destinations */
struct dial_head out_chans = AST_LIST_HEAD_NOLOCK_INIT_VALUE; /* list of destinations */
struct chanlist *outgoing;
struct chanlist *tmp;
struct ast_channel *peer;
int to; /* timeout */
struct cause_args num = { chan, 0, 0, 0 };
int cause;
char numsubst[256];
struct ast_bridge_config config = { { 0, } };
struct timeval calldurationlimit = { 0, };
@ -1983,7 +2022,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
pbx_builtin_setvar_helper(chan, "DIALEDTIME", "");
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
ast_log(LOG_WARNING, "Dial requires an argument (technology/resource)\n");
pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
return -1;
}
@ -1999,7 +2038,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
}
if (ast_strlen_zero(args.peers)) {
ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
ast_log(LOG_WARNING, "Dial requires an argument (technology/resource)\n");
pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
goto done;
}
@ -2154,34 +2193,60 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
ast_channel_lock(chan);
if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP_ONCE"))) {
outbound_group = ast_strdupa(outbound_group);
outbound_group = ast_strdupa(outbound_group);
pbx_builtin_setvar_helper(chan, "OUTBOUND_GROUP_ONCE", NULL);
} else if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"))) {
outbound_group = ast_strdupa(outbound_group);
}
ast_channel_unlock(chan);
ast_channel_unlock(chan);
ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_IGNORE_CONNECTEDLINE |
OPT_CANCEL_TIMEOUT | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB | OPT_FORCECLID);
/* PREDIAL: Run gosub on the caller's channel */
if (ast_test_flag64(&opts, OPT_PREDIAL_CALLER)
&& !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) {
ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLER]);
ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER]);
}
/* loop through the list of dial destinations */
rest = args.peers;
while ((cur = strsep(&rest, "&")) ) {
struct chanlist *tmp;
struct ast_channel *tc; /* channel for this destination */
/* Get a technology/[device:]number pair */
/* Get a technology/resource pair */
char *number = cur;
char *interface = ast_strdupa(number);
char *tech = strsep(&number, "/");
size_t tech_len;
size_t number_len;
/* find if we already dialed this interface */
struct ast_dialed_interface *di;
AST_LIST_HEAD(,ast_dialed_interface) *dialed_interfaces;
num_dialed++;
if (ast_strlen_zero(number)) {
ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n");
ast_log(LOG_WARNING, "Dial argument takes format (technology/resource)\n");
goto out;
}
if (!(tmp = ast_calloc(1, sizeof(*tmp))))
tech_len = strlen(tech) + 1;
number_len = strlen(number) + 1;
tmp = ast_calloc(1, sizeof(*tmp) + (2 * tech_len) + number_len);
if (!tmp) {
goto out;
}
/* Save tech, number, and interface. */
cur = tmp->stuff;
strcpy(cur, tech);
tmp->tech = cur;
cur += tech_len;
strcpy(cur, tech);
cur[tech_len - 1] = '/';
tmp->interface = cur;
cur += tech_len;
strcpy(cur, number);
tmp->number = cur;
if (opts.flags) {
ast_copy_flags64(tmp, &opts,
OPT_CANCEL_ELSEWHERE |
@ -2193,7 +2258,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML);
}
ast_copy_string(numsubst, number, sizeof(numsubst));
/* Request the peer */
ast_channel_lock(chan);
@ -2215,7 +2280,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
chanlist_free(tmp);
goto out;
}
datastore->inheritance = DATASTORE_INHERIT_FOREVER;
if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
@ -2234,14 +2298,13 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
AST_LIST_LOCK(dialed_interfaces);
AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
if (!strcasecmp(di->interface, interface)) {
if (!strcasecmp(di->interface, tmp->interface)) {
ast_log(LOG_WARNING, "Skipping dialing interface '%s' again since it has already been dialed\n",
di->interface);
break;
}
}
AST_LIST_UNLOCK(dialed_interfaces);
if (di) {
fulldial++;
chanlist_free(tmp);
@ -2252,45 +2315,47 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
* which "real" interfaces have been dialed. The Local channel will
* inherit this list so that if it ends up dialing a real interface,
* it won't call one that has already been called. */
if (strcasecmp(tech, "Local")) {
if (!(di = ast_calloc(1, sizeof(*di) + strlen(interface)))) {
AST_LIST_UNLOCK(dialed_interfaces);
if (strcasecmp(tmp->tech, "Local")) {
if (!(di = ast_calloc(1, sizeof(*di) + strlen(tmp->interface)))) {
chanlist_free(tmp);
goto out;
}
strcpy(di->interface, interface);
strcpy(di->interface, tmp->interface);
AST_LIST_LOCK(dialed_interfaces);
AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
AST_LIST_UNLOCK(dialed_interfaces);
}
tc = ast_request(tech, ast_channel_nativeformats(chan), chan, numsubst, &cause);
tc = ast_request(tmp->tech, ast_channel_nativeformats(chan), chan, tmp->number, &cause);
if (!tc) {
/* If we can't, just go on to the next call */
ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n",
tech, cause, ast_cause2str(cause));
tmp->tech, cause, ast_cause2str(cause));
handle_cause(cause, &num);
if (!rest) /* we are on the last destination */
if (!rest) {
/* we are on the last destination */
ast_channel_hangupcause_set(chan, cause);
chanlist_free(tmp);
}
if (!ignore_cc && (cause == AST_CAUSE_BUSY || cause == AST_CAUSE_CONGESTION)) {
if (!ast_cc_callback(chan, tech, numsubst, ast_cc_busy_interface)) {
ast_cc_extension_monitor_add_dialstring(chan, interface, "");
if (!ast_cc_callback(chan, tmp->tech, tmp->number, ast_cc_busy_interface)) {
ast_cc_extension_monitor_add_dialstring(chan, tmp->interface, "");
}
}
chanlist_free(tmp);
continue;
}
ast_channel_get_device_name(tc, device_name, sizeof(device_name));
if (!ignore_cc) {
ast_cc_extension_monitor_add_dialstring(chan, interface, device_name);
ast_cc_extension_monitor_add_dialstring(chan, tmp->interface, device_name);
}
pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst);
pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", tmp->number);
ast_channel_lock_both(tc, chan);
/* Setup outgoing SDP to match incoming one */
if (!outgoing && !rest && CAN_EARLY_BRIDGE(peerflags, chan, tc)) {
if (!AST_LIST_FIRST(&out_chans) && !rest && CAN_EARLY_BRIDGE(peerflags, chan, tc)) {
/* We are on the only destination. */
ast_rtp_instance_early_bridge_make_compatible(tc, chan);
}
@ -2389,44 +2454,74 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
ast_channel_unlock(tc);
ast_channel_unlock(chan);
res = ast_call(tc, numsubst, 0); /* Place the call, but don't wait on the answer */
/* Put channel in the list of outgoing thingies. */
tmp->chan = tc;
AST_LIST_INSERT_TAIL(&out_chans, tmp, node);
}
/*
* PREDIAL: Run gosub on all of the callee channels
*
* We run the callee predial before ast_call() in case the user
* wishes to do something on the newly created channels before
* the channel does anything important.
*
* Inside the target gosub we will be able to do something with
* the newly created channel name ie: now the calling channel
* can know what channel will be used to call the destination
* ex: now we will know that SIP/abc-123 is calling SIP/def-124
*/
if (ast_test_flag64(&opts, OPT_PREDIAL_CALLEE)
&& !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLEE])
&& !AST_LIST_EMPTY(&out_chans)) {
ast_autoservice_start(chan);
ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLEE]);
AST_LIST_TRAVERSE(&out_chans, tmp, node) {
ast_app_exec_sub(NULL, tmp->chan, opt_args[OPT_ARG_PREDIAL_CALLEE]);
}
ast_autoservice_stop(chan);
}
/* Start all outgoing calls */
AST_LIST_TRAVERSE_SAFE_BEGIN(&out_chans, tmp, node) {
res = ast_call(tmp->chan, tmp->number, 0); /* Place the call, but don't wait on the answer */
ast_channel_lock(chan);
/* Save the info in cdr's that we called them */
if (ast_channel_cdr(chan))
ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(tc));
ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(tmp->chan));
/* check the results of ast_call */
if (res) {
/* Again, keep going even if there's an error */
ast_debug(1, "ast call on peer returned %d\n", res);
ast_verb(3, "Couldn't call %s/%s\n", tech, numsubst);
if (ast_channel_hangupcause(tc)) {
ast_channel_hangupcause_set(chan, ast_channel_hangupcause(tc));
ast_verb(3, "Couldn't call %s\n", tmp->interface);
if (ast_channel_hangupcause(tmp->chan)) {
ast_channel_hangupcause_set(chan, ast_channel_hangupcause(tmp->chan));
}
ast_channel_unlock(chan);
ast_cc_call_failed(chan, tc, interface);
ast_hangup(tc);
tc = NULL;
ast_cc_call_failed(chan, tmp->chan, tmp->interface);
ast_hangup(tmp->chan);
tmp->chan = NULL;
AST_LIST_REMOVE_CURRENT(node);
chanlist_free(tmp);
continue;
} else {
senddialevent(chan, tc, numsubst);
ast_verb(3, "Called %s/%s\n", tech, numsubst);
ast_channel_unlock(chan);
}
/* Put them in the list of outgoing thingies... We're ready now.
XXX If we're forcibly removed, these outgoing calls won't get
hung up XXX */
senddialevent(chan, tmp->chan, tmp->number);
ast_channel_unlock(chan);
ast_verb(3, "Called %s\n", tmp->interface);
ast_set_flag64(tmp, DIAL_STILLGOING);
tmp->chan = tc;
tmp->next = outgoing;
outgoing = tmp;
/* If this line is up, don't try anybody else */
if (ast_channel_state(outgoing->chan) == AST_STATE_UP)
if (ast_channel_state(tmp->chan) == AST_STATE_UP) {
break;
}
}
AST_LIST_TRAVERSE_SAFE_END;
if (ast_strlen_zero(args.timeout)) {
to = -1;
} else {
@ -2439,6 +2534,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
}
}
outgoing = AST_LIST_FIRST(&out_chans);
if (!outgoing) {
strcpy(pa.status, "CHANUNAVAIL");
if (fulldial == num_dialed) {
@ -2474,7 +2570,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
}
}
peer = wait_for_answer(chan, outgoing, &to, peerflags, opt_args, &pa, &num, &result,
peer = wait_for_answer(chan, &out_chans, &to, peerflags, opt_args, &pa, &num, &result,
dtmf_progress, ignore_cc, &forced_clid, &stored_clid);
/* The ast_channel_datastore_remove() function could fail here if the
@ -2508,8 +2604,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
/* Ah ha! Someone answered within the desired timeframe. Of course after this
we will always return with -1 so that it is hung up properly after the
conversation. */
hanguptree(outgoing, peer, 1);
outgoing = NULL;
hanguptree(&out_chans, peer, 1);
/* If appropriate, log that we have a destination channel and set the answer time */
if (ast_channel_cdr(chan)) {
ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(peer));
@ -2519,11 +2614,14 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", ast_channel_name(peer));
ast_channel_lock(peer);
number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER");
if (!number)
number = numsubst;
pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER");
if (ast_strlen_zero(number)) {
number = NULL;
} else {
number = ast_strdupa(number);
}
ast_channel_unlock(peer);
pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) {
ast_debug(1, "app_dial: sendurl=%s.\n", args.url);
@ -2618,7 +2716,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
ast_channel_exten_set(peer, ast_channel_exten(chan));
ast_channel_priority_set(peer, ast_channel_priority(chan) + 2);
ast_pbx_start(peer);
hanguptree(outgoing, NULL, ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0);
hanguptree(&out_chans, NULL, ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0);
if (continue_exec)
*continue_exec = 1;
res = 0;
@ -2903,7 +3001,7 @@ out:
}
ast_channel_early_bridge(chan, NULL);
hanguptree(outgoing, NULL, 0); /* In this case, there's no answer anywhere */
hanguptree(&out_chans, NULL, 0); /* In this case, there's no answer anywhere */
pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
senddialendevent(chan, pa.status);
ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status);

Loading…
Cancel
Save