summaryrefslogtreecommitdiff
path: root/apps/app_dial.c
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2012-05-24 23:52:40 +0000
committerRichard Mudgett <rmudgett@digium.com>2012-05-24 23:52:40 +0000
commite5185367735ee26b93cddc9d162d584f412456ad (patch)
treeeaff5e0394f58af50d844250a7500e48438a9f60 /apps/app_dial.c
parentbdaecbb66b1d6f92f32d14e34fb399634bb5079a (diff)
Fix Dial I option ignored if dial forked and one fork redirects.
The Dial and Queue I option is intended to block connected line updates and redirecting updates. However, it is a feature that when a call is locally redirected, the I option is disabled if the redirected call runs as a local channel so the administrator can have an opportunity to setup new connected line information. Unfortunately, the Dial and Queue I option is disabled for *all* forked calls if one of those calls is redirected. * Make the Dial and Queue I option apply to each outgoing call leg independently. Now if one outgoing call leg is locally redirected, the other outgoing calls are not affected. * Made Dial not pass any redirecting updates when forking calls. Redirecting updates do not make sense for this scenario. * Made Queue not pass any redirecting updates when using the ringall strategy. Redirecting updates do not make sense for this scenario. * Fixed deadlock potential with chan_local when Dial and Queue send redirecting updates for a local redirect. * Converted the Queue stillgoing flag to a boolean bitfield. (closes issue ASTERISK-19511) Reported by: rmudgett Tested by: rmudgett Review: https://reviewboard.asterisk.org/r/1920/ ........ Merged revisions 367678 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 367679 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@367693 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'apps/app_dial.c')
-rw-r--r--apps/app_dial.c167
1 files changed, 121 insertions, 46 deletions
diff --git a/apps/app_dial.c b/apps/app_dial.c
index e6d9c5448..e6eebbec7 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -859,7 +859,8 @@ static void senddialendevent(struct ast_channel *src, const char *dialstatus)
* \param o Outgoing call channel list.
* \param num Incoming call channel cause accumulation
* \param peerflags Dial option flags
- * \param single_caller_bored From wait_for_answer: single && !caller_entertained
+ * \param single TRUE if there is only one outgoing call.
+ * \param caller_entertained TRUE if the caller is being entertained by MOH or ringback.
* \param to Remaining call timeout time.
* \param forced_clid OPT_FORCECLID caller id to send
* \param stored_clid Caller id representing the called party if needed
@@ -869,8 +870,8 @@ static void senddialendevent(struct ast_channel *src, const char *dialstatus)
*
* \todo eventually this function should be intergrated into and replaced by ast_call_forward()
*/
-static void do_forward(struct chanlist *o,
- struct cause_args *num, struct ast_flags64 *peerflags, int single_caller_bored, int *to,
+static void do_forward(struct chanlist *o, struct cause_args *num,
+ struct ast_flags64 *peerflags, int single, int caller_entertained, int *to,
struct ast_party_id *forced_clid, struct ast_party_id *stored_clid)
{
char tmpchan[256];
@@ -898,6 +899,14 @@ static void do_forward(struct chanlist *o,
stuff = tmpchan;
tech = "Local";
}
+ if (!strcasecmp(tech, "Local")) {
+ /*
+ * Drop the connected line update block for local channels since
+ * this is going to run dialplan and the user can change his
+ * mind about what connected line information he wants to send.
+ */
+ ast_clear_flag64(o, OPT_IGNORE_CONNECTEDLINE);
+ }
ast_cel_report_event(in, AST_CEL_FORWARD, NULL, ast_channel_call_forward(c), NULL);
@@ -912,11 +921,14 @@ static void do_forward(struct chanlist *o,
/* Setup parameters */
c = o->chan = ast_request(tech, ast_channel_nativeformats(in), in, stuff, &cause);
if (c) {
- if (single_caller_bored) {
+ if (single && !caller_entertained) {
ast_channel_make_compatible(o->chan, in);
}
+ ast_channel_lock_both(in, o->chan);
ast_channel_inherit_variables(in, o->chan);
ast_channel_datastore_inherit(in, o->chan);
+ ast_channel_unlock(in);
+ ast_channel_unlock(o->chan);
/* When a call is forwarded, we don't want to track new interfaces
* dialed for CC purposes. Setting the done flag will ensure that
* any Dial operations that happen later won't record CC interfaces.
@@ -933,15 +945,18 @@ static void do_forward(struct chanlist *o,
handle_cause(cause, num);
ast_hangup(original);
} else {
- struct ast_party_redirecting redirecting;
+ ast_channel_lock_both(c, original);
+ ast_party_redirecting_copy(ast_channel_redirecting(c),
+ ast_channel_redirecting(original));
+ ast_channel_unlock(c);
+ ast_channel_unlock(original);
ast_channel_lock_both(c, in);
- if (single_caller_bored && CAN_EARLY_BRIDGE(peerflags, c, in)) {
+ if (single && !caller_entertained && CAN_EARLY_BRIDGE(peerflags, c, in)) {
ast_rtp_instance_early_bridge_make_compatible(c, in);
}
- ast_channel_set_redirecting(c, ast_channel_redirecting(original), NULL);
if (!ast_channel_redirecting(c)->from.number.valid
|| ast_strlen_zero(ast_channel_redirecting(c)->from.number.str)) {
/*
@@ -962,6 +977,7 @@ static void do_forward(struct chanlist *o,
if (ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) {
caller.id = *stored_clid;
ast_channel_set_caller_event(c, &caller, NULL);
+ ast_set_flag64(o, DIAL_CALLERID_ABSENT);
} else if (ast_strlen_zero(S_COR(ast_channel_caller(c)->id.number.valid,
ast_channel_caller(c)->id.number.str, NULL))) {
/*
@@ -970,6 +986,9 @@ static void do_forward(struct chanlist *o,
*/
caller.id = *stored_clid;
ast_channel_set_caller_event(c, &caller, NULL);
+ ast_set_flag64(o, DIAL_CALLERID_ABSENT);
+ } else {
+ ast_clear_flag64(o, DIAL_CALLERID_ABSENT);
}
/* Determine CallerID for outgoing channel to send. */
@@ -987,23 +1006,33 @@ static void do_forward(struct chanlist *o,
ast_channel_appl_set(c, "AppDial");
ast_channel_data_set(c, "(Outgoing Line)");
- /*
- * We must unlock c before calling ast_channel_redirecting_macro, because
- * we put c into autoservice there. That is pretty much a guaranteed
- * deadlock. This is why the handling of c's lock may seem a bit unusual
- * here.
- */
- ast_party_redirecting_init(&redirecting);
- ast_party_redirecting_copy(&redirecting, ast_channel_redirecting(c));
- ast_channel_unlock(c);
- if (ast_channel_redirecting_sub(c, in, &redirecting, 0) &&
- ast_channel_redirecting_macro(c, in, &redirecting, 1, 0)) {
- ast_channel_update_redirecting(in, &redirecting, NULL);
- }
- ast_party_redirecting_free(&redirecting);
+
ast_channel_unlock(in);
+ if (single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
+ struct ast_party_redirecting redirecting;
+
+ /*
+ * Redirecting updates to the caller make sense only on single
+ * calls.
+ *
+ * We must unlock c before calling
+ * ast_channel_redirecting_macro, because we put c into
+ * autoservice there. That is pretty much a guaranteed
+ * deadlock. This is why the handling of c's lock may seem a
+ * bit unusual here.
+ */
+ ast_party_redirecting_init(&redirecting);
+ ast_party_redirecting_copy(&redirecting, ast_channel_redirecting(c));
+ ast_channel_unlock(c);
+ if (ast_channel_redirecting_sub(c, in, &redirecting, 0) &&
+ ast_channel_redirecting_macro(c, in, &redirecting, 1, 0)) {
+ ast_channel_update_redirecting(in, &redirecting, NULL);
+ }
+ ast_party_redirecting_free(&redirecting);
+ } else {
+ ast_channel_unlock(c);
+ }
- ast_clear_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE);
if (ast_test_flag64(peerflags, OPT_CANCEL_TIMEOUT)) {
*to = -1;
}
@@ -1024,7 +1053,7 @@ static void do_forward(struct chanlist *o,
/* Hangup the original channel now, in case we needed it */
ast_hangup(original);
}
- if (single_caller_bored) {
+ if (single && !caller_entertained) {
ast_indicate(in, -1);
}
}
@@ -1085,7 +1114,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
}
}
- if (!ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE) && !ast_test_flag64(outgoing, DIAL_CALLERID_ABSENT)) {
+ if (!ast_test_flag64(outgoing, OPT_IGNORE_CONNECTEDLINE)
+ && !ast_test_flag64(outgoing, DIAL_CALLERID_ABSENT)) {
ast_channel_lock(outgoing->chan);
ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(outgoing->chan));
ast_channel_unlock(outgoing->chan);
@@ -1148,7 +1178,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
if (ast_test_flag64(o, DIAL_STILLGOING) && ast_channel_state(c) == AST_STATE_UP) {
if (!peer) {
ast_verb(3, "%s answered %s\n", ast_channel_name(c), ast_channel_name(in));
- if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+ if (!single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
if (o->pending_connected_update) {
if (ast_channel_connected_line_sub(c, in, &o->connected, 0) &&
ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) {
@@ -1201,8 +1231,37 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
}
ast_frfree(f);
}
- do_forward(o, &num, peerflags, single && !caller_entertained, to,
+
+ if (o->pending_connected_update) {
+ /*
+ * Re-seed the chanlist's connected line information with
+ * previously acquired connected line info from the incoming
+ * channel. The previously acquired connected line info could
+ * have been set through the CONNECTED_LINE dialplan function.
+ */
+ o->pending_connected_update = 0;
+ ast_channel_lock(in);
+ ast_party_connected_line_copy(&o->connected, ast_channel_connected(in));
+ ast_channel_unlock(in);
+ }
+
+ do_forward(o, &num, peerflags, single, caller_entertained, to,
forced_clid, stored_clid);
+
+ if (single && o->chan
+ && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)
+ && !ast_test_flag64(o, DIAL_CALLERID_ABSENT)) {
+ ast_channel_lock(o->chan);
+ ast_connected_line_copy_from_caller(&connected_caller,
+ ast_channel_caller(o->chan));
+ ast_channel_unlock(o->chan);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ if (ast_channel_connected_line_sub(o->chan, in, &connected_caller, 0) &&
+ ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) {
+ ast_channel_update_connected_line(in, &connected_caller, NULL);
+ }
+ ast_party_connected_line_free(&connected_caller);
+ }
continue;
}
f = ast_read(winner);
@@ -1224,7 +1283,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
/* This is our guy if someone answered. */
if (!peer) {
ast_verb(3, "%s answered %s\n", ast_channel_name(c), ast_channel_name(in));
- if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+ if (!single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
if (o->pending_connected_update) {
if (ast_channel_connected_line_sub(c, in, &o->connected, 0) &&
ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) {
@@ -1358,21 +1417,25 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
ast_indicate(in, f->subclass.integer);
break;
case AST_CONTROL_CONNECTED_LINE:
- if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+ if (ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(in));
- } else if (!single) {
+ break;
+ }
+ if (!single) {
struct ast_party_connected_line connected;
- ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ast_channel_name(c), ast_channel_name(in));
+
+ ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n",
+ ast_channel_name(c), ast_channel_name(in));
ast_party_connected_line_set_init(&connected, &o->connected);
ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
ast_party_connected_line_set(&o->connected, &connected, NULL);
ast_party_connected_line_free(&connected);
o->pending_connected_update = 1;
- } else {
- if (ast_channel_connected_line_sub(c, in, f, 1) &&
- ast_channel_connected_line_macro(c, in, f, 1, 1)) {
- ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
- }
+ break;
+ }
+ if (ast_channel_connected_line_sub(c, in, f, 1) &&
+ ast_channel_connected_line_macro(c, in, f, 1, 1)) {
+ ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
}
break;
case AST_CONTROL_AOC:
@@ -1387,16 +1450,24 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
}
break;
case AST_CONTROL_REDIRECTING:
- if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+ if (!single) {
+ /*
+ * Redirecting updates to the caller make sense only on single
+ * calls.
+ */
+ break;
+ }
+ if (ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(in));
- } else if (single) {
- ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ast_channel_name(c), ast_channel_name(in));
- if (ast_channel_redirecting_sub(c, in, f, 1) &&
- ast_channel_redirecting_macro(c, in, f, 1, 1)) {
- ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
- }
- pa->sentringing = 0;
+ break;
}
+ ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
+ ast_channel_name(c), ast_channel_name(in));
+ if (ast_channel_redirecting_sub(c, in, f, 1) &&
+ ast_channel_redirecting_macro(c, in, f, 1, 1)) {
+ ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
+ }
+ pa->sentringing = 0;
break;
case AST_CONTROL_PROCEEDING:
ast_verb(3, "%s is proceeding passing it to %s\n", ast_channel_name(c), ast_channel_name(in));
@@ -2202,8 +2273,11 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
outbound_group = ast_strdupa(outbound_group);
}
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);
+
+ /* Set per dial instance flags. These flags are also passed back to RetryDial. */
+ ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID
+ | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | 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)
@@ -2251,6 +2325,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
tmp->number = cur;
if (opts.flags) {
+ /* Set per outgoing call leg options. */
ast_copy_flags64(tmp, &opts,
OPT_CANCEL_ELSEWHERE |
OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
@@ -2258,7 +2333,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
OPT_CALLEE_PARK | OPT_CALLER_PARK |
OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
- OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
+ OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID | OPT_IGNORE_CONNECTEDLINE);
ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML);
}