Skip to content
Snippets Groups Projects
app_dial.c 127 KiB
Newer Older
  • Learn to ignore specific revisions
  • Mark Spencer's avatar
    Mark Spencer committed
    /*
    
     * Asterisk -- An open source telephony toolkit.
    
    Mark Spencer's avatar
    Mark Spencer committed
     *
    
    Andrew Latham's avatar
    Andrew Latham committed
     * Copyright (C) 1999 - 2012, Digium, Inc.
    
    Mark Spencer's avatar
    Mark Spencer committed
     *
    
     * Mark Spencer <markster@digium.com>
    
    Mark Spencer's avatar
    Mark Spencer committed
     *
    
     * 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.
     *
    
    Mark Spencer's avatar
    Mark Spencer committed
     * 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>
    
    Russell Bryant's avatar
    Russell Bryant committed
     * \ingroup applications
    
    /*** MODULEINFO
    
    	<support_level>core</support_level>
    
    #include <sys/time.h>
    
    Timo Teräs's avatar
    Timo Teräs committed
    #include <signal.h>
    
    #include <sys/stat.h>
    
    #include <netinet/in.h>
    
    
    Michiel van Baak's avatar
    Michiel van Baak committed
    #include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
    
    #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"
    
    #include "asterisk/rtp_engine.h"
    
    #include "asterisk/privacy.h"
    
    #include "asterisk/stringfields.h"
    
    #include "asterisk/aoc.h"
    
    #include "asterisk/ccss.h"
    
    #include "asterisk/framehook.h"
    
    #include "asterisk/dial.h"
    
    #include "asterisk/stasis_channels.h"
    
    #include "asterisk/bridge_after.h"
    
    #include "asterisk/features_config.h"
    
    #include "asterisk/max_forwards.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="&amp;">
    				<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&amp;Technology3/Resource3&amp;.....</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">
    
    				<optionlist>
    
    				<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>
    
    				<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
    
    					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>
    
    					<para>Before initiating an outgoing call, <literal>Gosub</literal> to the specified
    					location using the newly created channel.  The <literal>Gosub</literal> will be
    
    					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>
    
    					<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>
    
    					<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 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>
    
    					<para>Asterisk will ignore any connected line update requests or any redirecting party
    					update requests it may receive on this dial attempt.</para>
    
    				<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:[[&lt;context&gt;^]&lt;exten&gt;^]&lt;priority&gt;">
    
    								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 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>
    
    						<para>Indicate progress to calling party. Send audio 'tone' from the <filename>indications.conf</filename> tonezone currently in use.</para>
    
    				<option name="R">
    
    					<para>Default: Indicate ringing to the calling party, even if the called party isn't actually ringing.
    
    					Allow interruption of the ringback if early media is received on the channel.</para>
    
    				</option>
    
    				<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:[[&lt;context&gt;^]&lt;exten&gt;^]&lt;priority&gt;">
    								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&amp;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&amp;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">
    
    			exten => s,1,NoOp(ARG1=${ARG1} ARG2=${ARG2})
    
    			 same => n,Playback(hello)
    			 same => n,Return()
    
    
    			exten => _X.,1,NoOp()
    
    			 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>
    
    	</application>
     ***/
    
    static const char app[] = "Dial";
    static const char rapp[] = "RetryDial";
    
    enum {
    
    	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),
    
    	OPT_DURATION_LIMIT =    (1 << 9),
    	OPT_MUSICBACK =         (1 << 10),
    	OPT_CALLEE_MACRO =      (1 << 11),
    	OPT_SCREEN_NOINTRO =    (1 << 12),
    
    	OPT_SCREEN_NOCALLERID = (1 << 13),
    	OPT_IGNORE_CONNECTEDLINE = (1 << 14),
    
    	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_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)
    
    #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,
    	OPT_ARG_SENDDTMF,
    	OPT_ARG_GOTO,
    	OPT_ARG_DURATION_LIMIT,
    	OPT_ARG_MUSICBACK,
    	OPT_ARG_CALLEE_MACRO,
    
    	OPT_ARG_PRIVACY,
    	OPT_ARG_DURATION_STOP,
    
    	OPT_ARG_SCREEN_NOINTRO,
    
    	OPT_ARG_ORIGINAL_CLID,
    
    	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 */
    
    AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
    
    	AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE),
    
    	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('d', OPT_DTMF_EXIT),
    	AST_APP_OPTION_ARG('D', OPT_SENDDTMF, OPT_ARG_SENDDTMF),
    
    	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),
    
    	AST_APP_OPTION('I', OPT_IGNORE_CONNECTEDLINE),
    
    	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),
    
    	AST_APP_OPTION('N', OPT_SCREEN_NOCALLERID),
    
    	AST_APP_OPTION_ARG('o', OPT_ORIGINAL_CLID, OPT_ARG_ORIGINAL_CLID),
    
    	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),
    
    	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),
    
    	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),
    
    	AST_APP_OPTION('x', OPT_CALLEE_MIXMONITOR),
    	AST_APP_OPTION('X', OPT_CALLER_MIXMONITOR),
    
    	AST_APP_OPTION('z', OPT_CANCEL_TIMEOUT),
    
    #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 {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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;
    
    	/*! Original channel name.  Must be freed.  Could be NULL if allocation failed. */
    	char *orig_chan_name;
    
    	/*! 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];
    
    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);
    
    	ast_free(outgoing);
    }
    
    
    static void hanguptree(struct dial_head *out_chans, struct ast_channel *exception, int hangupcause)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	/* Hang up a tree of stuff */
    
    	struct chanlist *outgoing;
    
    	while ((outgoing = AST_LIST_REMOVE_HEAD(out_chans, node))) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		/* Hangup any existing lines we have open */
    
    		if (outgoing->chan && (outgoing->chan != exception)) {
    
    				ast_channel_hangupcause_set(outgoing->chan, hangupcause);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_hangup(outgoing->chan);
    
    /*
     * 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_NO_ANSWER:
    
    	case AST_CAUSE_NORMAL_CLEARING:
    		break;
    	default:
    		num->nochan++;
    		break;
    	}
    }
    
    Michiel van Baak's avatar
    Michiel van Baak committed
    static int onedigit_goto(struct ast_channel *chan, const char *context, char exten, int pri)
    
    		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))
    
    /* do not call with chan lock held */
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    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)));
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : "";
    
    /*!
     * helper function for wait_for_answer()
     *
    
     * \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.
    
     * \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.
    
     * \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 tmpchan[256];
    
    	char forwarder[AST_CHANNEL_NAME];
    
    	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));
    
    		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));
    
    		c = o->chan = NULL;
    
    		cause = AST_CAUSE_BUSY;
    	} else {
    
    		struct ast_stream_topology *topology;
    
    		topology = ast_stream_topology_clone(ast_channel_get_stream_topology(in));
    
    		/* Setup parameters */
    
    		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);
    
    			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);