app_dial: Add the "Q" option to set the cause on unanswered channels

The "Q" option will set the cause on the unanswered channels when
another channel answers.  It overrides the default of
ANSWERED_ELSEWHERE.

NOTE:  chan_sip does not support setting the cause on a CANCEL to
anything other than ANSWERED_ELSEWHERE.

ASTERISK-26446 #close

Change-Id: I71742e0919aaa16784c30a2b2e73fbeed7672e47
changes/35/4035/7
George Joseph 9 years ago
parent f22e36461f
commit 86e8716952

@ -103,6 +103,12 @@ app_confbridge
instance, allows a channel to immediately exit the ConfBridge without having
to wait for a leave announcement to play.
app_dial
------------------
* Added the "Q" option which sets the Q.850/Q.931 cause on unanswered channels
when another channel answers the call. The default of ANSWERED_ELSEWHERE
is unchanged.
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 13 to Asterisk 14 --------------------
------------------------------------------------------------------------------

@ -375,6 +375,25 @@ ASTERISK_REGISTER_FILE()
<para>Enable privacy mode. Use <replaceable>x</replaceable> as the family/key in the AstDB database if
it is provided. The current extension is used if a database family/key is not specified.</para>
</option>
<option name="Q">
<argument name="cause" required="true"/>
<para>Specify the Q.850/Q.931 <replaceable>cause</replaceable> to send on
unanswered channels when another channel answers the call.
As with <literal>Hangup()</literal>, <replaceable>cause</replaceable>
can be a numeric cause code or a name such as
<literal>NO_ANSWER</literal>,
<literal>USER_BUSY</literal>,
<literal>CALL_REJECTED</literal> or
<literal>ANSWERED_ELSEWHERE</literal> (the default if Q isn't specified).
You can also specify <literal>0</literal> or <literal>NONE</literal>
to send no cause. See the <filename>causes.h</filename> file for the
full list of valid causes and names.
</para>
<note>
<para>chan_sip does not support setting the cause on a CANCEL to anything
other than ANSWERED_ELSEWHERE.</para>
</note>
</option>
<option name="r">
<para>Default: Indicate ringing to the calling party, even if the called party isn't actually ringing. Pass no audio to the calling
party until the called channel has answered.</para>
@ -520,6 +539,9 @@ ASTERISK_REGISTER_FILE()
<example title="Dial with call length limit">
same => n,Dial(PJSIP/alice,,L(60000:30000:10000))
</example>
<example title="Dial alice and bob and send NO_ANSWER to bob instead of ANSWERED_ELSEWHERE when alice answers">
same => n,Dial(PJSIP/alice&amp;PJSIP/bob,,Q(NO_ANSWER))
</example>
<example title="Dial with pre-dial subroutines">
[default]
@ -684,6 +706,7 @@ enum {
#define OPT_PREDIAL_CALLEE (1LLU << 41)
#define OPT_PREDIAL_CALLER (1LLU << 42)
#define OPT_RING_WITH_EARLY_MEDIA (1LLU << 43)
#define OPT_HANGUPCAUSE (1LLU << 44)
enum {
OPT_ARG_ANNOUNCE = 0,
@ -705,6 +728,7 @@ enum {
OPT_ARG_FORCE_CID_PRES,
OPT_ARG_PREDIAL_CALLEE,
OPT_ARG_PREDIAL_CALLER,
OPT_ARG_HANGUPCAUSE,
/* note: this entry _MUST_ be the last one in the enum */
OPT_ARG_ARRAY_SIZE
};
@ -738,6 +762,7 @@ AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
AST_APP_OPTION_ARG('O', OPT_OPERMODE, OPT_ARG_OPERMODE),
AST_APP_OPTION('p', OPT_SCREENING),
AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
AST_APP_OPTION_ARG('Q', OPT_HANGUPCAUSE, OPT_ARG_HANGUPCAUSE),
AST_APP_OPTION_ARG('r', OPT_RINGBACK, OPT_ARG_RINGBACK),
AST_APP_OPTION('R', OPT_RING_WITH_EARLY_MEDIA),
AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
@ -796,7 +821,7 @@ static void chanlist_free(struct chanlist *outgoing)
ast_free(outgoing);
}
static void hanguptree(struct dial_head *out_chans, struct ast_channel *exception, int answered_elsewhere)
static void hanguptree(struct dial_head *out_chans, struct ast_channel *exception, int hangupcause)
{
/* Hang up a tree of stuff */
struct chanlist *outgoing;
@ -804,9 +829,9 @@ static void hanguptree(struct dial_head *out_chans, struct ast_channel *exceptio
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) {
if (hangupcause >= 0) {
/* This is for the channel drivers */
ast_channel_hangupcause_set(outgoing->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
ast_channel_hangupcause_set(outgoing->chan, hangupcause);
}
ast_hangup(outgoing->chan);
}
@ -2768,6 +2793,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
} else {
const char *number;
int dial_end_raised = 0;
int cause = -1;
if (ast_test_flag64(&opts, OPT_CALLER_ANSWER))
ast_answer(chan);
@ -2778,7 +2804,23 @@ 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(&out_chans, peer, 1);
if (ast_test_flag64(&opts, OPT_HANGUPCAUSE)
&& !ast_strlen_zero(opt_args[OPT_ARG_HANGUPCAUSE])) {
cause = ast_str2cause(opt_args[OPT_ARG_HANGUPCAUSE]);
if (cause <= 0) {
if (!strcasecmp(opt_args[OPT_ARG_HANGUPCAUSE], "NONE")) {
cause = 0;
} else if (sscanf(opt_args[OPT_ARG_HANGUPCAUSE], "%30d", &cause) != 1
|| cause < 0) {
ast_log(LOG_WARNING, "Invalid cause given to Dial(...Q(<cause>)): \"%s\"\n",
opt_args[OPT_ARG_HANGUPCAUSE]);
cause = -1;
}
}
}
hanguptree(&out_chans, peer, cause >= 0 ? cause : AST_CAUSE_ANSWERED_ELSEWHERE);
/* If appropriate, log that we have a destination channel and set the answer time */
if (ast_channel_name(peer))
pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", ast_channel_name(peer));
@ -3182,7 +3224,11 @@ out:
}
ast_channel_early_bridge(chan, NULL);
hanguptree(&out_chans, NULL, ast_channel_hangupcause(chan)==AST_CAUSE_ANSWERED_ELSEWHERE || ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0 ); /* forward 'answered elsewhere' if we received it */
/* forward 'answered elsewhere' if we received it */
hanguptree(&out_chans, NULL,
ast_channel_hangupcause(chan) == AST_CAUSE_ANSWERED_ELSEWHERE
|| ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE)
? AST_CAUSE_ANSWERED_ELSEWHERE : -1);
pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status);

Loading…
Cancel
Save