Newer
Older
* Asterisk -- An open source telephony toolkit.
* Mark Spencer <markster@digium.com>
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
*
* \brief dial() & retrydial() - Trivial application to dial a channel and send an URL on answer
*
* \author Mark Spencer <markster@digium.com>
<support_level>core</support_level>
Kevin P. Fleming
committed
#include "asterisk.h"
#include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
Kevin P. Fleming
committed
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/config.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/callerid.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#include "asterisk/causes.h"
Kevin P. Fleming
committed
#include "asterisk/manager.h"
#include "asterisk/privacy.h"
#include "asterisk/stringfields.h"
#include "asterisk/dsp.h"
Alec L Davis
committed
#include "asterisk/indications.h"
#include "asterisk/framehook.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/features_config.h"
#include "asterisk/max_forwards.h"
#include "asterisk/stream.h"
/*** DOCUMENTATION
<application name="Dial" language="en_US">
<synopsis>
Attempt to connect to another device or endpoint and bridge the call.
</synopsis>
<syntax>
<parameter name="Technology/Resource" required="true" argsep="&">
<argument name="Technology/Resource" required="true">
<para>Specification of the device(s) to dial. These must be in the format of
<literal>Technology/Resource</literal>, where <replaceable>Technology</replaceable>
represents a particular channel driver, and <replaceable>Resource</replaceable>
represents a resource available to that particular channel driver.</para>
</argument>
<argument name="Technology2/Resource2" required="false" multiple="true">
<para>Optional extra devices to dial in parallel</para>
<para>If you need more than one enter them as
Technology2/Resource2&Technology3/Resource3&.....</para>
</argument>
</parameter>
<parameter name="timeout" required="false">
<para>Specifies the number of seconds we attempt to dial the specified devices.</para>
<para>If not specified, this defaults to 136 years.</para>
</parameter>
<parameter name="options" required="false">
<option name="A">
<argument name="x" required="true">
<para>The file to play to the called party</para>
</argument>
<para>Play an announcement to the called party, where <replaceable>x</replaceable> is the prompt to be played</para>
</option>
Matthew Nicholson
committed
<option name="a">
<para>Immediately answer the calling channel when the called channel answers in
all cases. Normally, the calling channel is answered when the called channel
answers, but when options such as <literal>A()</literal> and
<literal>M()</literal> are used, the calling channel is
Matthew Nicholson
committed
not answered until all actions on the called channel (such as playing an
announcement) are completed. This option can be used to answer the calling
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>
Richard Mudgett
committed
<option name="b" argsep="^">
<para>Before initiating an outgoing call, <literal>Gosub</literal> to the specified
location using the newly created channel. The <literal>Gosub</literal> will be
Richard Mudgett
committed
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 outgoing call(s), <literal>Gosub</literal> to the
specified location using the current channel.</para>
Richard Mudgett
committed
<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>
<option name="c">
<para>If the Dial() application cancels this call, always set
<variable>HANGUPCAUSE</variable> to 'answered elsewhere'</para>
</option>
<option name="d">
<para>Allow the calling user to dial a 1 digit extension while waiting for
a call to be answered. Exit to that extension if it exists in the
current context, or the context defined in the <variable>EXITCONTEXT</variable> variable,
if it exists.</para>
<para>NOTE: Many SIP and ISDN phones cannot send DTMF digits until the call is
connected. If you wish to use this option with these phones, you
can use the <literal>Answer</literal> application before dialing.</para>
</option>
<option name="D" argsep=":">
<argument name="called" />
<argument name="calling" />
<argument name="progress" />
<para>Send the specified DTMF strings <emphasis>after</emphasis> the called
party has answered, but before the call gets bridged. The
<replaceable>called</replaceable> DTMF string is sent to the called party, and the
<replaceable>calling</replaceable> DTMF string is sent to the calling party. Both arguments
can be used alone. If <replaceable>progress</replaceable> is specified, its DTMF is sent
to the called party immediately after receiving a <literal>PROGRESS</literal> message.</para>
<para>See <literal>SendDTMF</literal> for valid digits.</para>
</option>
<option name="e">
<para>Execute the <literal>h</literal> extension for peer after the call ends</para>
</option>
<option name="f">
<argument name="x" required="false" />
<para>If <replaceable>x</replaceable> is not provided, force the CallerID sent on a call-forward or
deflection to the dialplan extension of this <literal>Dial()</literal> using a dialplan <literal>hint</literal>.
For example, some PSTNs do not allow CallerID to be set to anything
other than the numbers assigned to you.
If <replaceable>x</replaceable> is provided, force the CallerID sent to <replaceable>x</replaceable>.</para>
</option>
<option name="F" argsep="^">
<argument name="context" required="false" />
<argument name="exten" required="false" />
<argument name="priority" required="true" />
<para>When the caller hangs up, transfer the <emphasis>called</emphasis> party
to the specified destination and <emphasis>start</emphasis> execution at that location.</para>
<para>NOTE: Any channel variables you want the called channel to inherit from the caller channel must be
prefixed with one or two underbars ('_').</para>
<option name="F">
<para>When the caller hangs up, transfer the <emphasis>called</emphasis> party to the next priority of the current extension
and <emphasis>start</emphasis> execution at that location.</para>
<para>NOTE: Any channel variables you want the called channel to inherit from the caller channel must be
prefixed with one or two underbars ('_').</para>
<para>NOTE: Using this option from a Macro() or GoSub() might not make sense as there would be no return points.</para>
</option>
<option name="g">
<para>Proceed with dialplan execution at the next priority in the current extension if the
destination channel hangs up.</para>
</option>
<option name="G" argsep="^">
<argument name="context" required="false" />
<argument name="exten" required="false" />
<argument name="priority" required="true" />
<para>If the call is answered, transfer the calling party to
the specified <replaceable>priority</replaceable> and the called party to the specified
<replaceable>priority</replaceable> plus one.</para>
<para>NOTE: You cannot use any additional action post answer options in conjunction with this option.</para>
</option>
<option name="h">
<para>Allow the called party to hang up by sending the DTMF sequence
defined for disconnect in <filename>features.conf</filename>.</para>
</option>
<option name="H">
<para>Allow the calling party to hang up by sending the DTMF sequence
defined for disconnect in <filename>features.conf</filename>.</para>
<para>NOTE: Many SIP and ISDN phones cannot send DTMF digits until the call is
connected. If you wish to allow DTMF disconnect before the dialed
party answers with these phones, you can use the <literal>Answer</literal>
application before dialing.</para>
</option>
<option name="i">
<para>Asterisk will ignore any forwarding requests it may receive on this dial attempt.</para>
</option>
Mark Michelson
committed
<option name="I">
Richard Mudgett
committed
<para>Asterisk will ignore any connected line update requests or any redirecting party
update requests it may receive on this dial attempt.</para>
Mark Michelson
committed
</option>
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
<option name="k">
<para>Allow the called party to enable parking of the call by sending
the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
</option>
<option name="K">
<para>Allow the calling party to enable parking of the call by sending
the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
</option>
<option name="L" argsep=":">
<argument name="x" required="true">
<para>Maximum call time, in milliseconds</para>
</argument>
<argument name="y">
<para>Warning time, in milliseconds</para>
</argument>
<argument name="z">
<para>Repeat time, in milliseconds</para>
</argument>
<para>Limit the call to <replaceable>x</replaceable> milliseconds. Play a warning when <replaceable>y</replaceable> milliseconds are
left. Repeat the warning every <replaceable>z</replaceable> milliseconds until time expires.</para>
<para>This option is affected by the following variables:</para>
<variablelist>
<variable name="LIMIT_PLAYAUDIO_CALLER">
<value name="yes" default="true" />
<value name="no" />
<para>If set, this variable causes Asterisk to play the prompts to the caller.</para>
</variable>
<variable name="LIMIT_PLAYAUDIO_CALLEE">
<value name="yes" />
<value name="no" default="true"/>
<para>If set, this variable causes Asterisk to play the prompts to the callee.</para>
</variable>
<variable name="LIMIT_TIMEOUT_FILE">
<value name="filename"/>
<para>If specified, <replaceable>filename</replaceable> specifies the sound prompt to play when the timeout is reached.
If not set, the time remaining will be announced.</para>
</variable>
<variable name="LIMIT_CONNECT_FILE">
<value name="filename"/>
<para>If specified, <replaceable>filename</replaceable> specifies the sound prompt to play when the call begins.
If not set, the time remaining will be announced.</para>
</variable>
<variable name="LIMIT_WARNING_FILE">
<value name="filename"/>
<para>If specified, <replaceable>filename</replaceable> specifies the sound prompt to play as
a warning when time <replaceable>x</replaceable> is reached. If not set, the time remaining will be announced.</para>
</variable>
</variablelist>
</option>
<option name="m">
<argument name="class" required="false"/>
<para>Provide hold music to the calling party until a requested
channel answers. A specific music on hold <replaceable>class</replaceable>
(as defined in <filename>musiconhold.conf</filename>) can be specified.</para>
</option>
<option name="M" argsep="^">
<argument name="macro" required="true">
<para>Name of the macro that should be executed.</para>
</argument>
<argument name="arg" multiple="true">
<para>Macro arguments</para>
</argument>
<para>Execute the specified <replaceable>macro</replaceable> for the <emphasis>called</emphasis> channel
before connecting to the calling channel. Arguments can be specified to the Macro
using <literal>^</literal> as a delimiter. The macro can set the variable
<variable>MACRO_RESULT</variable> to specify the following actions after the macro is
finished executing:</para>
<variablelist>
<variable name="MACRO_RESULT">
<para>If set, this action will be taken after the macro finished executing.</para>
<value name="ABORT">
Hangup both legs of the call
</value>
<value name="CONGESTION">
Behave as if line congestion was encountered
</value>
<value name="BUSY">
Behave as if a busy signal was encountered
</value>
<value name="CONTINUE">
Hangup the called party and allow the calling party to continue dialplan execution at the next priority
</value>
<value name="GOTO:[[<context>^]<exten>^]<priority>">
Transfer the call to the specified destination.
</value>
</variable>
</variablelist>
<para>NOTE: You cannot use any additional action post answer options in conjunction
with this option. Also, pbx services are run on the peer (called) channel,
so you will not be able to set timeouts via the <literal>TIMEOUT()</literal> function in this macro.</para>
<para>WARNING: Be aware of the limitations that macros have, specifically with regards to use of
the <literal>WaitExten</literal> application. For more information, see the documentation for
<literal>Macro()</literal>.</para>
<para>NOTE: Macros are deprecated, GoSub should be used instead,
see the <literal>U</literal> option.</para>
</option>
<option name="n">
<argument name="delete">
<para>With <replaceable>delete</replaceable> either not specified or set to <literal>0</literal>,
the recorded introduction will not be deleted if the caller hangs up while the remote party has not
yet answered.</para>
<para>With <replaceable>delete</replaceable> set to <literal>1</literal>, the introduction will
always be deleted.</para>
</argument>
<para>This option is a modifier for the call screening/privacy mode. (See the
<literal>p</literal> and <literal>P</literal> options.) It specifies
that no introductions are to be saved in the <directory>priv-callerintros</directory>
directory.</para>
</option>
<option name="N">
<para>This option is a modifier for the call screening/privacy mode. It specifies
that if CallerID is present, do not screen the call.</para>
</option>
<option name="o">
<argument name="x" required="false" />
<para>If <replaceable>x</replaceable> is not provided, specify that the CallerID that was present on the
<emphasis>calling</emphasis> channel be stored as the CallerID on the <emphasis>called</emphasis> channel.
This was the behavior of Asterisk 1.0 and earlier.
If <replaceable>x</replaceable> is provided, specify the CallerID stored on the <emphasis>called</emphasis> channel.
Note that <literal>o(${CALLERID(all)})</literal> is similar to option <literal>o</literal> without the parameter.</para>
</option>
<option name="O">
<argument name="mode">
<para>With <replaceable>mode</replaceable> either not specified or set to <literal>1</literal>,
the originator hanging up will cause the phone to ring back immediately.</para>
<para>With <replaceable>mode</replaceable> set to <literal>2</literal>, when the operator
flashes the trunk, it will ring their phone back.</para>
</argument>
<para>Enables <emphasis>operator services</emphasis> mode. This option only
works when bridging a DAHDI channel to another DAHDI channel
only. if specified on non-DAHDI interfaces, it will be ignored.
When the destination answers (presumably an operator services
station), the originator no longer has control of their line.
They may hang up, but the switch will not release their line
until the destination party (the operator) hangs up.</para>
</option>
<option name="p">
<para>This option enables screening mode. This is basically Privacy mode
without memory.</para>
</option>
<option name="P">
<argument name="x" />
<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>
<para>NOTE: chan_sip does not support setting the cause on a CANCEL to anything
other than ANSWERED_ELSEWHERE.</para>
</option>
Alec L Davis
committed
<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>
Alec L Davis
committed
<argument name="tone" required="false">
<para>Indicate progress to calling party. Send audio 'tone' from the <filename>indications.conf</filename> tonezone currently in use.</para>
Alec L Davis
committed
</argument>
<para>Default: Indicate ringing to the calling party, even if the called party isn't actually ringing.
Joshua Colp
committed
Allow interruption of the ringback if early media is received on the channel.</para>
<option name="S">
<argument name="x" required="true" />
<para>Hang up the call <replaceable>x</replaceable> seconds <emphasis>after</emphasis> the called party has
answered the call.</para>
</option>
<option name="s">
<argument name="x" required="true" />
<para>Force the outgoing CallerID tag parameter to be set to the string <replaceable>x</replaceable>.</para>
<para>Works with the <literal>f</literal> option.</para>
<option name="t">
<para>Allow the called party to transfer the calling party by sending the
DTMF sequence defined in <filename>features.conf</filename>. This setting does not perform policy enforcement on
transfers initiated by other methods.</para>
</option>
<option name="T">
<para>Allow the calling party to transfer the called party by sending the
DTMF sequence defined in <filename>features.conf</filename>. This setting does not perform policy enforcement on
transfers initiated by other methods.</para>
</option>
<option name="U" argsep="^">
<argument name="x" required="true">
<para>Name of the subroutine context to execute via <literal>Gosub</literal>.
The subroutine execution starts in the named context at the s exten and priority 1.</para>
</argument>
<argument name="arg" multiple="true" required="false">
<para>Arguments for the <literal>Gosub</literal> routine</para>
<para>Execute via <literal>Gosub</literal> the routine <replaceable>x</replaceable> for the <emphasis>called</emphasis> channel before connecting
to the calling channel. Arguments can be specified to the <literal>Gosub</literal>
using <literal>^</literal> as a delimiter. The <literal>Gosub</literal> routine can set the variable
<variable>GOSUB_RESULT</variable> to specify the following actions after the <literal>Gosub</literal> returns.</para>
<variablelist>
<variable name="GOSUB_RESULT">
<value name="ABORT">
Hangup both legs of the call.
</value>
<value name="CONGESTION">
Behave as if line congestion was encountered.
</value>
<value name="BUSY">
Behave as if a busy signal was encountered.
</value>
<value name="CONTINUE">
Hangup the called party and allow the calling party
to continue dialplan execution at the next priority.
</value>
<value name="GOTO:[[<context>^]<exten>^]<priority>">
Transfer the call to the specified destination.
</value>
</variable>
</variablelist>
<para>NOTE: You cannot use any additional action post answer options in conjunction
with this option. Also, pbx services are run on the <emphasis>called</emphasis> channel,
so you will not be able to set timeouts via the <literal>TIMEOUT()</literal> function in this routine.</para>
<option name="u">
<argument name = "x" required="true">
<para>Force the outgoing callerid presentation indicator parameter to be set
to one of the values passed in <replaceable>x</replaceable>:
<literal>allowed_not_screened</literal>
<literal>allowed_passed_screen</literal>
<literal>allowed_failed_screen</literal>
<literal>allowed</literal>
<literal>prohib_not_screened</literal>
<literal>prohib_passed_screen</literal>
<literal>prohib_failed_screen</literal>
<literal>prohib</literal>
<literal>unavailable</literal></para>
</argument>
<para>Works with the <literal>f</literal> option.</para>
<option name="w">
<para>Allow the called party to enable recording of the call by sending
the DTMF sequence defined for one-touch recording in <filename>features.conf</filename>.</para>
</option>
<option name="W">
<para>Allow the calling party to enable recording of the call by sending
the DTMF sequence defined for one-touch recording in <filename>features.conf</filename>.</para>
</option>
<option name="x">
<para>Allow the called party to enable recording of the call by sending
the DTMF sequence defined for one-touch automixmonitor in <filename>features.conf</filename>.</para>
</option>
<option name="X">
<para>Allow the calling party to enable recording of the call by sending
the DTMF sequence defined for one-touch automixmonitor in <filename>features.conf</filename>.</para>
</option>
<option name="z">
<para>On a call forward, cancel any dial timeout which has been set for this call.</para>
</option>
</optionlist>
</parameter>
<parameter name="URL">
<para>The optional URL will be sent to the called party if the channel driver supports it.</para>
</parameter>
</syntax>
<description>
<para>This application will place calls to one or more specified channels. As soon
as one of the requested channels answers, the originating channel will be
answered, if it has not already been answered. These two channels will then
be active in a bridged call. All other channels that were requested will then
be hung up.</para>
<para>Unless there is a timeout specified, the Dial application will wait
indefinitely until one of the called channels answers, the user hangs up, or
if all of the called channels are busy or unavailable. Dialplan execution will
continue if no requested channels can be called, or if the timeout expires.
This application will report normal termination if the originating channel
hangs up, or if the call is bridged and either of the parties in the bridge
ends the call.</para>
<para>If the <variable>OUTBOUND_GROUP</variable> variable is set, all peer channels created by this
application will be put into that group (as in <literal>Set(GROUP()=...</literal>).
If the <variable>OUTBOUND_GROUP_ONCE</variable> variable is set, all peer channels created by this
application will be put into that group (as in <literal>Set(GROUP()=...</literal>). Unlike <variable>OUTBOUND_GROUP</variable>,
however, the variable will be unset after use.</para>
<example title="Dial with 30 second timeout">
same => n,Dial(PJSIP/alice,30)
</example>
<example title="Parallel dial with 45 second timeout">
same => n,Dial(PJSIP/alice&PJIP/bob,45)
</example>
<example title="Dial with 'g' continuation option">
same => n,Dial(PJSIP/alice,,g)
same => n,Log(NOTICE, Alice call result: ${DIALSTATUS})
</example>
<example title="Dial with transfer/recording features for calling party">
same => n,Dial(PJSIP/alice,,TX)
</example>
<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&PJSIP/bob,,Q(NO_ANSWER))
</example>
<example title="Dial with pre-dial subroutines">
[default]
exten => callee_channel,1,NoOp(ARG1=${ARG1} ARG2=${ARG2})
same => n,Log(NOTICE, I'm called on channel ${CHANNEL} prior to it starting the dial attempt)
same => n,Return()
exten => called_channel,1,NoOp(ARG1=${ARG1} ARG2=${ARG2})
same => n,Log(NOTICE, I'm called on outbound channel ${CHANNEL} prior to it being used to dial someone)
same => n,Return()
exten => _X.,1,NoOp()
same => n,Dial(PJSIP/alice,,b(default^called_channel^1(my_gosub_arg1^my_gosub_arg2))B(default^callee_channel^1(my_gosub_arg1^my_gosub_arg2)))
same => n,Hangup()
</example>
<example title="Dial with post-answer subroutine executed on outbound channel">
[my_gosub_routine]
exten => s,1,NoOp(ARG1=${ARG1} ARG2=${ARG2})
same => n,Playback(hello)
same => n,Return()
[default]
same => n,Dial(PJSIP/alice,,U(my_gosub_routine^my_gosub_arg1^my_gosub_arg2))
same => n,Hangup()
</example>
<example title="Dial into ConfBridge using 'G' option">
same => n,Dial(PJSIP/alice,,G(jump_to_here))
same => n(jump_to_here),Goto(confbridge)
same => n,Goto(confbridge)
same => n(confbridge),ConfBridge(${EXTEN})
</example>
<para>This application sets the following channel variables:</para>
<variablelist>
<variable name="DIALEDTIME">
<para>This is the time from dialing a channel until when it is disconnected.</para>
</variable>
<variable name="DIALEDTIME_MS">
<para>This is the milliseconds version of the DIALEDTIME variable.</para>
</variable>
<variable name="ANSWEREDTIME">
<para>This is the amount of time for actual call.</para>
</variable>
<variable name="ANSWEREDTIME_MS">
<para>This is the milliseconds version of the ANSWEREDTIME variable.</para>
</variable>
<variable name="RINGTIME">
<para>This is the time from creating the channel to the first RINGING event received. Empty if there was no ring.</para>
</variable>
<variable name="RINGTIME_MS">
<para>This is the milliseconds version of the RINGTIME variable.</para>
</variable>
<variable name="PROGRESSTIME">
<para>This is the time from creating the channel to the first PROGRESS event received. Empty if there was no such event.</para>
</variable>
<variable name="PROGRESSTIME_MS">
<para>This is the milliseconds version of the PROGRESSTIME variable.</para>
</variable>
<variable name="DIALEDPEERNAME">
<para>The name of the outbound channel that answered the call.</para>
</variable>
<variable name="DIALEDPEERNUMBER">
<para>The number that was dialed for the answered outbound channel.</para>
</variable>
<variable name="FORWARDERNAME">
<para>If a call forward occurred, the name of the forwarded channel.</para>
</variable>
<variable name="DIALSTATUS">
<para>This is the status of the call</para>
<value name="CHANUNAVAIL" />
<value name="CONGESTION" />
<value name="NOANSWER" />
<value name="BUSY" />
<value name="ANSWER" />
<value name="CANCEL" />
<value name="DONTCALL">
For the Privacy and Screening Modes.
Will be set if the called party chooses to send the calling party to the 'Go Away' script.
</value>
<value name="TORTURE">
For the Privacy and Screening Modes.
Will be set if the called party chooses to send the calling party to the 'torture' script.
</value>
<value name="INVALIDARGS" />
</variable>
</variablelist>
</description>
<see-also>
<ref type="application">RetryDial</ref>
<ref type="application">SendDTMF</ref>
<ref type="application">Gosub</ref>
<ref type="application">Macro</ref>
</see-also>
</application>
<application name="RetryDial" language="en_US">
<synopsis>
Place a call, retrying on failure allowing an optional exit extension.
</synopsis>
<syntax>
<parameter name="announce" required="true">
<para>Filename of sound that will be played when no channel can be reached</para>
</parameter>
<parameter name="sleep" required="true">
<para>Number of seconds to wait after a dial attempt failed before a new attempt is made</para>
</parameter>
<parameter name="retries" required="true">
<para>Number of retries</para>
<para>When this is reached flow will continue at the next priority in the dialplan</para>
</parameter>
<parameter name="dialargs" required="true">
<para>Same format as arguments provided to the Dial application</para>
</parameter>
</syntax>
<description>
<para>This application will attempt to place a call using the normal Dial application.
If no channel can be reached, the <replaceable>announce</replaceable> file will be played.
Then, it will wait <replaceable>sleep</replaceable> number of seconds before retrying the call.
After <replaceable>retries</replaceable> number of attempts, the calling channel will continue at the next priority in the dialplan.
If the <replaceable>retries</replaceable> setting is set to 0, this application will retry endlessly.
While waiting to retry a call, a 1 digit extension may be dialed. If that
extension exists in either the context defined in <variable>EXITCONTEXT</variable> or the current
one, The call will jump to that extension immediately.
The <replaceable>dialargs</replaceable> are specified in the same format that arguments are provided
to the Dial application.</para>
</description>
<see-also>
<ref type="application">Dial</ref>
</see-also>
static const char app[] = "Dial";
static const char rapp[] = "RetryDial";
Tilghman Lesher
committed
OPT_ANNOUNCE = (1 << 0),
OPT_RESETCDR = (1 << 1),
OPT_DTMF_EXIT = (1 << 2),
OPT_SENDDTMF = (1 << 3),
OPT_FORCECLID = (1 << 4),
OPT_GO_ON = (1 << 5),
OPT_CALLEE_HANGUP = (1 << 6),
OPT_CALLER_HANGUP = (1 << 7),
Mark Michelson
committed
OPT_ORIGINAL_CLID = (1 << 8),
Tilghman Lesher
committed
OPT_DURATION_LIMIT = (1 << 9),
OPT_MUSICBACK = (1 << 10),
OPT_CALLEE_MACRO = (1 << 11),
OPT_SCREEN_NOINTRO = (1 << 12),
Mark Michelson
committed
OPT_SCREEN_NOCALLERID = (1 << 13),
OPT_IGNORE_CONNECTEDLINE = (1 << 14),
Tilghman Lesher
committed
OPT_SCREENING = (1 << 15),
OPT_PRIVACY = (1 << 16),
OPT_RINGBACK = (1 << 17),
OPT_DURATION_STOP = (1 << 18),
OPT_CALLEE_TRANSFER = (1 << 19),
OPT_CALLER_TRANSFER = (1 << 20),
OPT_CALLEE_MONITOR = (1 << 21),
OPT_CALLER_MONITOR = (1 << 22),
OPT_GOTO = (1 << 23),
OPT_OPERMODE = (1 << 24),
OPT_CALLEE_PARK = (1 << 25),
OPT_CALLER_PARK = (1 << 26),
OPT_IGNORE_FORWARDING = (1 << 27),
Tilghman Lesher
committed
OPT_CALLEE_GOSUB = (1 << 28),
OPT_CALLEE_MIXMONITOR = (1 << 29),
OPT_CALLER_MIXMONITOR = (1 << 30),
/* flags are now 64 bits, so keep it up! */
#define DIAL_STILLGOING (1LLU << 31)
#define DIAL_NOFORWARDHTML (1LLU << 32)
#define DIAL_CALLERID_ABSENT (1LLU << 33) /* TRUE if caller id is not available for connected line. */
#define OPT_CANCEL_ELSEWHERE (1LLU << 34)
#define OPT_PEER_H (1LLU << 35)
#define OPT_CALLEE_GO_ON (1LLU << 36)
#define OPT_CANCEL_TIMEOUT (1LLU << 37)
#define OPT_FORCE_CID_TAG (1LLU << 38)
#define OPT_FORCE_CID_PRES (1LLU << 39)
#define OPT_CALLER_ANSWER (1LLU << 40)
Richard Mudgett
committed
#define OPT_PREDIAL_CALLEE (1LLU << 41)
#define OPT_PREDIAL_CALLER (1LLU << 42)
Joshua Colp
committed
#define OPT_RING_WITH_EARLY_MEDIA (1LLU << 43)
#define OPT_HANGUPCAUSE (1LLU << 44)
enum {
OPT_ARG_ANNOUNCE = 0,
OPT_ARG_SENDDTMF,
OPT_ARG_GOTO,
OPT_ARG_DURATION_LIMIT,
OPT_ARG_MUSICBACK,
OPT_ARG_CALLEE_MACRO,
Alec L Davis
committed
OPT_ARG_RINGBACK,
Steve Murphy
committed
OPT_ARG_CALLEE_GOSUB,
OPT_ARG_CALLEE_GO_ON,
OPT_ARG_PRIVACY,
OPT_ARG_DURATION_STOP,
OPT_ARG_OPERMODE,
OPT_ARG_FORCECLID,
OPT_ARG_FORCE_CID_TAG,
OPT_ARG_FORCE_CID_PRES,
Richard Mudgett
committed
OPT_ARG_PREDIAL_CALLEE,
OPT_ARG_PREDIAL_CALLER,
OPT_ARG_HANGUPCAUSE,
/* note: this entry _MUST_ be the last one in the enum */
Joshua Colp
committed
OPT_ARG_ARRAY_SIZE
Russell Bryant
committed
AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE),
Matthew Nicholson
committed
AST_APP_OPTION('a', OPT_CALLER_ANSWER),
Richard Mudgett
committed
AST_APP_OPTION_ARG('b', OPT_PREDIAL_CALLEE, OPT_ARG_PREDIAL_CALLEE),
AST_APP_OPTION_ARG('B', OPT_PREDIAL_CALLER, OPT_ARG_PREDIAL_CALLER),
Olle Johansson
committed
AST_APP_OPTION('c', OPT_CANCEL_ELSEWHERE),
AST_APP_OPTION('d', OPT_DTMF_EXIT),
AST_APP_OPTION_ARG('D', OPT_SENDDTMF, OPT_ARG_SENDDTMF),
Steve Murphy
committed
AST_APP_OPTION('e', OPT_PEER_H),
AST_APP_OPTION_ARG('f', OPT_FORCECLID, OPT_ARG_FORCECLID),
AST_APP_OPTION_ARG('F', OPT_CALLEE_GO_ON, OPT_ARG_CALLEE_GO_ON),
AST_APP_OPTION('g', OPT_GO_ON),
AST_APP_OPTION_ARG('G', OPT_GOTO, OPT_ARG_GOTO),
AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
AST_APP_OPTION('H', OPT_CALLER_HANGUP),
AST_APP_OPTION('i', OPT_IGNORE_FORWARDING),
Mark Michelson
committed
AST_APP_OPTION('I', OPT_IGNORE_CONNECTEDLINE),
Steve Murphy
committed
AST_APP_OPTION('k', OPT_CALLEE_PARK),
AST_APP_OPTION('K', OPT_CALLER_PARK),
AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
AST_APP_OPTION_ARG('m', OPT_MUSICBACK, OPT_ARG_MUSICBACK),
AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO),
AST_APP_OPTION_ARG('n', OPT_SCREEN_NOINTRO, OPT_ARG_SCREEN_NOINTRO),
Mark Michelson
committed
AST_APP_OPTION('N', OPT_SCREEN_NOCALLERID),
AST_APP_OPTION_ARG('o', OPT_ORIGINAL_CLID, OPT_ARG_ORIGINAL_CLID),
Tilghman Lesher
committed
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),
Alec L Davis
committed
AST_APP_OPTION_ARG('r', OPT_RINGBACK, OPT_ARG_RINGBACK),
Joshua Colp
committed
AST_APP_OPTION('R', OPT_RING_WITH_EARLY_MEDIA),
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('t', OPT_CALLEE_TRANSFER),
AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
Richard Mudgett
committed
AST_APP_OPTION_ARG('u', OPT_FORCE_CID_PRES, OPT_ARG_FORCE_CID_PRES),
Steve Murphy
committed
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),
AST_APP_OPTION('x', OPT_CALLEE_MIXMONITOR),
AST_APP_OPTION('X', OPT_CALLER_MIXMONITOR),
AST_APP_OPTION('z', OPT_CANCEL_TIMEOUT),
Russell Bryant
committed
END_OPTIONS );
#define CAN_EARLY_BRIDGE(flags,chan,peer) (!ast_test_flag64(flags, OPT_CALLEE_HANGUP | \
OPT_CALLER_HANGUP | OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | \
OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | OPT_CALLEE_PARK | \
OPT_CALLER_PARK | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB) && \
!ast_channel_audiohooks(chan) && !ast_channel_audiohooks(peer) && \
ast_framehook_list_is_empty(ast_channel_framehooks(chan)) && ast_framehook_list_is_empty(ast_channel_framehooks(peer)))
/*
* The list of active channels
*/
struct chanlist {
Richard Mudgett
committed
AST_LIST_ENTRY(chanlist) node;
Richard Mudgett
committed
/*! 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;
/*! Original channel name. Must be freed. Could be NULL if allocation failed. */
char *orig_chan_name;
Steve Murphy
committed
uint64_t flags;
/*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
Mark Michelson
committed
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;
Richard Mudgett
committed
/*! The interface, tech, and number strings are stuffed here. */
char stuff[0];
Richard Mudgett
committed
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)
{
ast_party_connected_line_free(&outgoing->connected);
ast_aoc_destroy_decoded(outgoing->aoc_s_rate_list);
ast_free(outgoing->orig_chan_name);
static void hanguptree(struct dial_head *out_chans, struct ast_channel *exception, int hangupcause)
Richard Mudgett
committed
struct chanlist *outgoing;
while ((outgoing = AST_LIST_REMOVE_HEAD(out_chans, node))) {
Olle Johansson
committed
if (outgoing->chan && (outgoing->chan != exception)) {
if (hangupcause >= 0) {
Olle Johansson
committed
/* This is for the channel drivers */
ast_channel_hangupcause_set(outgoing->chan, hangupcause);
Olle Johansson
committed
}
Olle Johansson
committed
}
Richard Mudgett
committed
chanlist_free(outgoing);
Mark Spencer
committed
#define AST_MAX_WATCHERS 256
/*
* argument to handle_cause() and other functions.
*/
struct cause_args {
struct ast_channel *chan;
int busy;
int congestion;
int nochan;
};
static void handle_cause(int cause, struct cause_args *num)
{
switch(cause) {
case AST_CAUSE_BUSY:
num->busy++;
break;
case AST_CAUSE_CONGESTION:
num->congestion++;
break;
case AST_CAUSE_NO_ROUTE_DESTINATION:
case AST_CAUSE_UNREGISTERED:
num->nochan++;
break;
case AST_CAUSE_NORMAL_CLEARING:
break;
default:
num->nochan++;
break;
}
}
static int onedigit_goto(struct ast_channel *chan, const char *context, char exten, int pri)
Kevin P. Fleming
committed
char rexten[2] = { exten, '\0' };
if (!ast_goto_if_exists(chan, context, rexten, pri))
if (!ast_goto_if_exists(chan, ast_channel_context(chan), rexten, pri))
else if (!ast_strlen_zero(ast_channel_macrocontext(chan))) {
if (!ast_goto_if_exists(chan, ast_channel_macrocontext(chan), rexten, pri))
return 1;
}
}
return 0;
}
Mark Spencer
committed
/* do not call with chan lock held */
static const char *get_cid_name(char *name, int namelen, struct ast_channel *chan)
const char *context;
const char *exten;
ast_channel_lock(chan);
context = ast_strdupa(S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)));
exten = ast_strdupa(S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)));
ast_channel_unlock(chan);
return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : "";
/*!
* helper function for wait_for_answer()
*
Richard Mudgett
committed
* \param o Outgoing call channel list.
* \param num Incoming call channel cause accumulation
* \param peerflags Dial option flags
* \param single TRUE if there is only one outgoing call.
* \param caller_entertained TRUE if the caller is being entertained by MOH or ringback.
Richard Mudgett
committed
* \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
*
* XXX this code is highly suspicious, as it essentially overwrites
* the outgoing channel without properly deleting it.
Richard Mudgett
committed
* \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, int caller_entertained, int *to,
struct ast_party_id *forced_clid, struct ast_party_id *stored_clid)
char forwarder[AST_CHANNEL_NAME];
Joshua Colp
committed
struct ast_channel *original = o->chan;
struct ast_channel *c = o->chan; /* the winner */
struct ast_channel *in = num->chan; /* the input channel */
char *stuff;
char *tech;
int cause;
struct ast_party_caller caller;
ast_copy_string(forwarder, ast_channel_name(c), sizeof(forwarder));
ast_copy_string(tmpchan, ast_channel_call_forward(c), sizeof(tmpchan));
if ((stuff = strchr(tmpchan, '/'))) {
*stuff++ = '\0';
tech = tmpchan;
} else {
const char *forward_context;
ast_channel_lock(c);
forward_context = pbx_builtin_getvar_helper(c, "FORWARD_CONTEXT");
if (ast_strlen_zero(forward_context)) {
forward_context = NULL;
}
snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(c), forward_context ? forward_context : ast_channel_context(c));
ast_channel_unlock(c);
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);
}
/* Before processing channel, go ahead and check for forwarding */
ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", ast_channel_name(in), tech, stuff, ast_channel_name(c));
/* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */
if (ast_test_flag64(peerflags, OPT_IGNORE_FORWARDING)) {
ast_verb(3, "Forwarding %s to '%s/%s' prevented.\n", ast_channel_name(in), tech, stuff);
ast_channel_publish_dial_forward(in, original, NULL, NULL, "CANCEL",
ast_channel_call_forward(original));
cause = AST_CAUSE_BUSY;
} else {
struct ast_stream_topology *topology;
ast_channel_lock(in);
topology = ast_stream_topology_clone(ast_channel_get_stream_topology(in));
ast_channel_unlock(in);
c = o->chan = ast_request_with_stream_topology(tech, topology, NULL, in, stuff, &cause);
ast_stream_topology_free(topology);
if (single && !caller_entertained) {
ast_channel_make_compatible(in, o->chan);
Richard Mudgett
committed
}
ast_channel_lock_both(in, o->chan);
ast_channel_inherit_variables(in, o->chan);
ast_channel_datastore_inherit(in, o->chan);
pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder);
ast_max_forwards_decrement(o->chan);
ast_channel_unlock(in);
ast_channel_unlock(o->chan);