mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-09 11:28:25 +00:00
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/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@367678 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
143
apps/app_dial.c
143
apps/app_dial.c
@@ -823,7 +823,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
|
||||
@@ -833,8 +834,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];
|
||||
@@ -862,6 +863,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, c->call_forward, NULL);
|
||||
|
||||
@@ -876,11 +885,14 @@ static void do_forward(struct chanlist *o,
|
||||
/* Setup parameters */
|
||||
c = o->chan = ast_request(tech, in->nativeformats, 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.
|
||||
@@ -897,17 +909,17 @@ 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(&c->redirecting, &original->redirecting);
|
||||
ast_channel_unlock(c);
|
||||
ast_channel_unlock(original);
|
||||
|
||||
if (single_caller_bored && CAN_EARLY_BRIDGE(peerflags, c, in)) {
|
||||
ast_channel_lock_both(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, &original->redirecting, NULL);
|
||||
ast_channel_lock(c);
|
||||
while (ast_channel_trylock(in)) {
|
||||
CHANNEL_DEADLOCK_AVOIDANCE(c);
|
||||
}
|
||||
if (!c->redirecting.from.number.valid
|
||||
|| ast_strlen_zero(c->redirecting.from.number.str)) {
|
||||
/*
|
||||
@@ -928,6 +940,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(c->caller.id.number.valid,
|
||||
c->caller.id.number.str, NULL))) {
|
||||
/*
|
||||
@@ -936,6 +949,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. */
|
||||
@@ -953,11 +969,20 @@ static void do_forward(struct chanlist *o,
|
||||
|
||||
c->appl = "AppDial";
|
||||
c->data = "(Outgoing Line)";
|
||||
|
||||
ast_channel_unlock(in);
|
||||
if (single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
|
||||
struct ast_party_redirecting redirecting;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* 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, &c->redirecting);
|
||||
@@ -966,9 +991,10 @@ static void do_forward(struct chanlist *o,
|
||||
ast_channel_update_redirecting(in, &redirecting, NULL);
|
||||
}
|
||||
ast_party_redirecting_free(&redirecting);
|
||||
ast_channel_unlock(in);
|
||||
} else {
|
||||
ast_channel_unlock(c);
|
||||
}
|
||||
|
||||
ast_clear_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE);
|
||||
if (ast_test_flag64(peerflags, OPT_CANCEL_TIMEOUT)) {
|
||||
*to = -1;
|
||||
}
|
||||
@@ -982,17 +1008,14 @@ static void do_forward(struct chanlist *o,
|
||||
c = o->chan = NULL;
|
||||
num->nochan++;
|
||||
} else {
|
||||
ast_channel_lock(c);
|
||||
while (ast_channel_trylock(in)) {
|
||||
CHANNEL_DEADLOCK_AVOIDANCE(c);
|
||||
}
|
||||
ast_channel_lock_both(c, in);
|
||||
senddialevent(in, c, stuff);
|
||||
ast_channel_unlock(in);
|
||||
ast_channel_unlock(c);
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
@@ -1052,7 +1075,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, &outgoing->chan->caller);
|
||||
ast_channel_unlock(outgoing->chan);
|
||||
@@ -1113,7 +1137,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
||||
if (ast_test_flag64(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) {
|
||||
if (!peer) {
|
||||
ast_verb(3, "%s answered %s\n", c->name, in->name);
|
||||
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_macro(c, in, &o->connected, 1, 0)) {
|
||||
ast_channel_update_connected_line(in, &o->connected, NULL);
|
||||
@@ -1164,8 +1188,35 @@ 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, &in->connected);
|
||||
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, &o->chan->caller);
|
||||
ast_channel_unlock(o->chan);
|
||||
connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
|
||||
if (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);
|
||||
@@ -1187,7 +1238,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", c->name, in->name);
|
||||
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_macro(c, in, &o->connected, 1, 0)) {
|
||||
ast_channel_update_connected_line(in, &o->connected, NULL);
|
||||
@@ -1319,21 +1370,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", in->name);
|
||||
} 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", c->name, in->name);
|
||||
|
||||
ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n",
|
||||
c->name, in->name);
|
||||
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 {
|
||||
break;
|
||||
}
|
||||
if (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:
|
||||
{
|
||||
@@ -1347,15 +1402,23 @@ 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", in->name);
|
||||
} else if (single) {
|
||||
ast_verb(3, "%s redirecting info has changed, passing it to %s\n", c->name, in->name);
|
||||
break;
|
||||
}
|
||||
ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
|
||||
c->name, in->name);
|
||||
if (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", c->name, in->name);
|
||||
@@ -2163,8 +2226,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);
|
||||
|
||||
/* loop through the list of dial destinations */
|
||||
rest = args.peers;
|
||||
@@ -2186,6 +2252,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
||||
if (!(tmp = ast_calloc(1, sizeof(*tmp))))
|
||||
goto out;
|
||||
if (opts.flags) {
|
||||
/* Set per outgoing call leg options. */
|
||||
ast_copy_flags64(tmp, &opts,
|
||||
OPT_CANCEL_ELSEWHERE |
|
||||
OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
|
||||
@@ -2193,7 +2260,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);
|
||||
}
|
||||
ast_copy_string(numsubst, number, sizeof(numsubst));
|
||||
|
||||
123
apps/app_queue.c
123
apps/app_queue.c
@@ -983,7 +983,6 @@ struct callattempt {
|
||||
struct callattempt *call_next;
|
||||
struct ast_channel *chan;
|
||||
char interface[256];
|
||||
int stillgoing;
|
||||
int metric;
|
||||
time_t lastcall;
|
||||
struct call_queue *lastqueue;
|
||||
@@ -992,8 +991,12 @@ struct callattempt {
|
||||
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;
|
||||
/*! TRUE if the connected line update is blocked. */
|
||||
unsigned int block_connected_update:1;
|
||||
/*! TRUE if caller id is not available for connected line */
|
||||
unsigned int dial_callerid_absent:1;
|
||||
/*! TRUE if the call is still active */
|
||||
unsigned int stillgoing:1;
|
||||
struct ast_aoc_decoded *aoc_s_rate_list;
|
||||
};
|
||||
|
||||
@@ -3425,15 +3428,13 @@ static void rna(int rnatime, struct queue_ent *qe, char *interface, char *member
|
||||
* \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
|
||||
* \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
|
||||
* \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
|
||||
* \param[in] update_connectedline Allow connected line and redirecting updates to pass through.
|
||||
*
|
||||
* \todo eventually all call forward logic should be intergerated into and replaced by ast_call_forward()
|
||||
*/
|
||||
static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int update_connectedline)
|
||||
static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
|
||||
{
|
||||
const char *queue = qe->parent->name;
|
||||
struct callattempt *o, *start = NULL, *prev = NULL;
|
||||
int res;
|
||||
int status;
|
||||
int numbusies = prebusies;
|
||||
int numnochan = 0;
|
||||
@@ -3514,10 +3515,11 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
||||
|
||||
/* Service all of the outgoing channels */
|
||||
for (o = start; o; o = o->call_next) {
|
||||
/* We go with a static buffer here instead of using ast_strdupa. Using
|
||||
/* We go with a fixed buffer here instead of using ast_strdupa. Using
|
||||
* ast_strdupa in a loop like this one can cause a stack overflow
|
||||
*/
|
||||
char ochan_name[AST_CHANNEL_NAME];
|
||||
|
||||
if (o->chan) {
|
||||
ast_channel_lock(o->chan);
|
||||
ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name));
|
||||
@@ -3526,7 +3528,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
||||
if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
|
||||
if (!peer) {
|
||||
ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
|
||||
if (update_connectedline) {
|
||||
if (!o->block_connected_update) {
|
||||
if (o->pending_connected_update) {
|
||||
if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
|
||||
ast_channel_update_connected_line(in, &o->connected, NULL);
|
||||
@@ -3557,6 +3559,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
||||
ast_copy_string(on, o->member->interface, sizeof(on));
|
||||
ast_copy_string(membername, o->member->membername, sizeof(membername));
|
||||
|
||||
/* Before processing channel, go ahead and check for forwarding */
|
||||
if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
|
||||
ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward);
|
||||
numnochan++;
|
||||
@@ -3578,10 +3581,17 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
||||
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.
|
||||
*/
|
||||
o->block_connected_update = 0;
|
||||
}
|
||||
|
||||
ast_cel_report_event(in, AST_CEL_FORWARD, NULL, o->chan->call_forward, NULL);
|
||||
|
||||
/* Before processing channel, go ahead and check for forwarding */
|
||||
ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
|
||||
/* Setup parameters */
|
||||
o->chan = ast_request(tech, in->nativeformats, in, stuff, &status);
|
||||
@@ -3592,15 +3602,28 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
||||
o->stillgoing = 0;
|
||||
numnochan++;
|
||||
} else {
|
||||
struct ast_party_redirecting redirecting;
|
||||
ast_channel_lock_both(o->chan, original);
|
||||
ast_party_redirecting_copy(&o->chan->redirecting, &original->redirecting);
|
||||
ast_channel_unlock(o->chan);
|
||||
ast_channel_unlock(original);
|
||||
|
||||
ast_channel_lock_both(o->chan, in);
|
||||
ast_channel_inherit_variables(in, o->chan);
|
||||
ast_channel_datastore_inherit(in, o->chan);
|
||||
|
||||
if (o->pending_connected_update) {
|
||||
/*
|
||||
* Re-seed the callattempt's connected line information with
|
||||
* previously acquired connected line info from the queued
|
||||
* channel. The previously acquired connected line info could
|
||||
* have been set through the CONNECTED_LINE dialplan function.
|
||||
*/
|
||||
o->pending_connected_update = 0;
|
||||
ast_party_connected_line_copy(&o->connected, &in->connected);
|
||||
}
|
||||
|
||||
ast_string_field_set(o->chan, accountcode, in->accountcode);
|
||||
|
||||
ast_channel_set_redirecting(o->chan, &original->redirecting, NULL);
|
||||
if (!o->chan->redirecting.from.number.valid
|
||||
|| ast_strlen_zero(o->chan->redirecting.from.number.str)) {
|
||||
/*
|
||||
@@ -3616,10 +3639,19 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
||||
|
||||
o->chan->dialed.transit_network_select = in->dialed.transit_network_select;
|
||||
|
||||
ast_party_caller_copy(&o->chan->caller, &in->caller);
|
||||
ast_party_connected_line_copy(&o->chan->connected, &original->connected);
|
||||
o->dial_callerid_absent = !o->chan->caller.id.number.valid
|
||||
|| ast_strlen_zero(o->chan->caller.id.number.str);
|
||||
ast_connected_line_copy_from_caller(&o->chan->connected, &in->caller);
|
||||
|
||||
ast_channel_unlock(in);
|
||||
if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL
|
||||
&& !o->block_connected_update) {
|
||||
struct ast_party_redirecting redirecting;
|
||||
|
||||
/*
|
||||
* Redirecting updates to the caller make sense only on single
|
||||
* call at a time strategies.
|
||||
*
|
||||
* We must unlock o->chan before calling
|
||||
* ast_channel_redirecting_macro, because we put o->chan into
|
||||
* autoservice there. That is pretty much a guaranteed
|
||||
@@ -3629,14 +3661,13 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
||||
ast_party_redirecting_init(&redirecting);
|
||||
ast_party_redirecting_copy(&redirecting, &o->chan->redirecting);
|
||||
ast_channel_unlock(o->chan);
|
||||
res = ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0);
|
||||
if (res) {
|
||||
if (ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0)) {
|
||||
ast_channel_update_redirecting(in, &redirecting, NULL);
|
||||
}
|
||||
ast_party_redirecting_free(&redirecting);
|
||||
ast_channel_unlock(in);
|
||||
|
||||
update_connectedline = 1;
|
||||
} else {
|
||||
ast_channel_unlock(o->chan);
|
||||
}
|
||||
|
||||
if (ast_call(o->chan, stuff, 0)) {
|
||||
ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
|
||||
@@ -3657,7 +3688,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
||||
/* This is our guy if someone answered. */
|
||||
if (!peer) {
|
||||
ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
|
||||
if (update_connectedline) {
|
||||
if (!o->block_connected_update) {
|
||||
if (o->pending_connected_update) {
|
||||
if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
|
||||
ast_channel_update_connected_line(in, &o->connected, NULL);
|
||||
@@ -3734,21 +3765,31 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
||||
/* Ignore going off hook */
|
||||
break;
|
||||
case AST_CONTROL_CONNECTED_LINE:
|
||||
if (!update_connectedline) {
|
||||
if (o->block_connected_update) {
|
||||
ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
|
||||
} else if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
|
||||
break;
|
||||
}
|
||||
if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
|
||||
struct ast_party_connected_line connected;
|
||||
|
||||
ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
|
||||
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 {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent using the CallerID from the outgoing channel since we
|
||||
* got a connected line update from it.
|
||||
*/
|
||||
o->dial_callerid_absent = 1;
|
||||
|
||||
if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
|
||||
ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AST_CONTROL_AOC:
|
||||
{
|
||||
@@ -3762,14 +3803,23 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
||||
}
|
||||
break;
|
||||
case AST_CONTROL_REDIRECTING:
|
||||
if (!update_connectedline) {
|
||||
ast_verb(3, "Redirecting update to %s prevented\n", inchan_name);
|
||||
} else if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
|
||||
ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name);
|
||||
if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
|
||||
/*
|
||||
* Redirecting updates to the caller make sense only on single
|
||||
* call at a time strategies.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
if (o->block_connected_update) {
|
||||
ast_verb(3, "Redirecting update to %s prevented\n",
|
||||
inchan_name);
|
||||
break;
|
||||
}
|
||||
ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
|
||||
ochan_name, inchan_name);
|
||||
if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
|
||||
ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
|
||||
@@ -3807,6 +3857,14 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \todo
|
||||
* XXX Queue like Dial really should send any connected line
|
||||
* updates (AST_CONTROL_CONNECTED_LINE) from the caller to each
|
||||
* ringing queue member.
|
||||
*/
|
||||
|
||||
if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
|
||||
ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
|
||||
*to = 0;
|
||||
@@ -4345,7 +4403,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
||||
char *p;
|
||||
char vars[2048];
|
||||
int forwardsallowed = 1;
|
||||
int update_connectedline = 1;
|
||||
int block_connected_line = 0;
|
||||
int callcompletedinsl;
|
||||
struct ao2_iterator memi;
|
||||
struct ast_datastore *datastore, *transfer_ds;
|
||||
@@ -4412,7 +4470,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
||||
forwardsallowed = 0;
|
||||
break;
|
||||
case 'I':
|
||||
update_connectedline = 0;
|
||||
block_connected_line = 1;
|
||||
break;
|
||||
case 'x':
|
||||
ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
|
||||
@@ -4512,17 +4570,18 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
||||
AST_LIST_UNLOCK(dialed_interfaces);
|
||||
}
|
||||
|
||||
ast_channel_lock(qe->chan);
|
||||
/*
|
||||
* Seed the callattempt's connected line information with previously
|
||||
* acquired connected line info from the queued channel. The
|
||||
* previously acquired connected line info could have been set
|
||||
* through the CONNECTED_LINE dialplan function.
|
||||
*/
|
||||
ast_channel_lock(qe->chan);
|
||||
ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected);
|
||||
ast_channel_unlock(qe->chan);
|
||||
|
||||
tmp->stillgoing = -1;
|
||||
tmp->block_connected_update = block_connected_line;
|
||||
tmp->stillgoing = 1;
|
||||
tmp->member = cur;/* Place the reference for cur into callattempt. */
|
||||
tmp->lastcall = cur->lastcall;
|
||||
tmp->lastqueue = cur->lastqueue;
|
||||
@@ -4564,7 +4623,9 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
||||
++qe->pending;
|
||||
ao2_unlock(qe->parent);
|
||||
ring_one(qe, outgoing, &numbusies);
|
||||
lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline);
|
||||
lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
|
||||
ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT),
|
||||
forwardsallowed);
|
||||
/* The ast_channel_datastore_remove() function could fail here if the
|
||||
* datastore was moved to another channel during a masquerade. If this is
|
||||
* the case, don't free the datastore here because later, when the channel
|
||||
|
||||
Reference in New Issue
Block a user