From e8a6e0ef0e672ebe823500538d2c06e7bad591e0 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Sat, 28 Apr 2012 00:31:47 +0000 Subject: 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 --- CHANGES | 2 + apps/app_dial.c | 248 +++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 175 insertions(+), 75 deletions(-) diff --git a/CHANGES b/CHANGES index 1887148c3..42e2bac90 100644 --- a/CHANGES +++ b/CHANGES @@ -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 ------------ diff --git a/apps/app_dial.c b/apps/app_dial.c index 875e943e3..72a38ce9c 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -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. + + @@ -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); -- cgit v1.2.3