main/pbx: Move pbx_builtin dialplan applications to pbx_builtins.c
authorGeorge Joseph <george.joseph@fairview5.com>
Tue, 29 Dec 2015 01:18:01 +0000 (18:18 -0700)
committerGeorge Joseph <george.joseph@fairview5.com>
Thu, 31 Dec 2015 03:24:02 +0000 (20:24 -0700)
We joked about splitting pbx.c into multiple files but this first step was
fairly easy.  All of the pbx_builtin dialplan applications have been moved
into pbx_builtins.c and a new pbx_private.h file was added. load_pbx_builtins()
is called by asterisk.c just after load_pbx().

A few functions were renamed and are cross-exposed between the 2 source files.

Change-Id: I87066be3dbf7f5822942ac1449d98cc43fc7561a

include/asterisk/_private.h
main/asterisk.c
main/pbx.c
main/pbx_builtins.c [new file with mode: 0644]
main/pbx_private.h [new file with mode: 0644]

index 2966f87..e58828c 100644 (file)
@@ -17,6 +17,7 @@
 
 int load_modules(unsigned int);                /*!< Provided by loader.c */
 int load_pbx(void);                    /*!< Provided by pbx.c */
+int load_pbx_builtins(void);   /*!< Provided by pbx_builtins.c */
 int init_logger(void);                 /*!< Provided by logger.c */
 void close_logger(void);               /*!< Provided by logger.c */
 void logger_queue_start(void);         /*!< Provided by logger.c */
index 93937af..a72e249 100644 (file)
@@ -4595,6 +4595,11 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
                exit(1);
        }
 
+       if (load_pbx_builtins()) {
+               printf("Failed: load_pbx_builtins\n%s", term_quit());
+               exit(1);
+       }
+
        if (ast_local_init()) {
                printf("Failed: ast_local_init\n%s", term_quit());
                exit(1);
index 202940e..c54eca8 100644 (file)
@@ -73,6 +73,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/stasis_channels.h"
 #include "asterisk/dial.h"
 #include "asterisk/vector.h"
+#include "pbx_private.h"
 
 /*!
  * \note I M P O R T A N T :
@@ -96,637 +97,6 @@ ASTERISK_REGISTER_FILE()
  */
 
 /*** DOCUMENTATION
-       <application name="Answer" language="en_US">
-               <synopsis>
-                       Answer a channel if ringing.
-               </synopsis>
-               <syntax>
-                       <parameter name="delay">
-                               <para>Asterisk will wait this number of milliseconds before returning to
-                               the dialplan after answering the call.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>If the call has not been answered, this application will
-                       answer it. Otherwise, it has no effect on the call.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Hangup</ref>
-               </see-also>
-       </application>
-       <application name="BackGround" language="en_US">
-               <synopsis>
-                       Play an audio file while waiting for digits of an extension to go to.
-               </synopsis>
-               <syntax>
-                       <parameter name="filenames" required="true" argsep="&amp;">
-                               <argument name="filename1" required="true" />
-                               <argument name="filename2" multiple="true" />
-                       </parameter>
-                       <parameter name="options">
-                               <optionlist>
-                                       <option name="s">
-                                               <para>Causes the playback of the message to be skipped
-                                               if the channel is not in the <literal>up</literal> state (i.e. it
-                                               hasn't been answered yet). If this happens, the
-                                               application will return immediately.</para>
-                                       </option>
-                                       <option name="n">
-                                               <para>Don't answer the channel before playing the files.</para>
-                                       </option>
-                                       <option name="m">
-                                               <para>Only break if a digit hit matches a one digit
-                                               extension in the destination context.</para>
-                                       </option>
-                               </optionlist>
-                       </parameter>
-                       <parameter name="langoverride">
-                               <para>Explicitly specifies which language to attempt to use for the requested sound files.</para>
-                       </parameter>
-                       <parameter name="context">
-                               <para>This is the dialplan context that this application will use when exiting
-                               to a dialed extension.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will play the given list of files <emphasis>(do not put extension)</emphasis>
-                       while waiting for an extension to be dialed by the calling channel. To continue waiting
-                       for digits after this application has finished playing files, the <literal>WaitExten</literal>
-                       application should be used.</para>
-                       <para>If one of the requested sound files does not exist, call processing will be terminated.</para>
-                       <para>This application sets the following channel variable upon completion:</para>
-                       <variablelist>
-                               <variable name="BACKGROUNDSTATUS">
-                                       <para>The status of the background attempt as a text string.</para>
-                                       <value name="SUCCESS" />
-                                       <value name="FAILED" />
-                               </variable>
-                       </variablelist>
-               </description>
-               <see-also>
-                       <ref type="application">ControlPlayback</ref>
-                       <ref type="application">WaitExten</ref>
-                       <ref type="application">BackgroundDetect</ref>
-                       <ref type="function">TIMEOUT</ref>
-               </see-also>
-       </application>
-       <application name="Busy" language="en_US">
-               <synopsis>
-                       Indicate the Busy condition.
-               </synopsis>
-               <syntax>
-                       <parameter name="timeout">
-                               <para>If specified, the calling channel will be hung up after the specified number of seconds.
-                               Otherwise, this application will wait until the calling channel hangs up.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will indicate the busy condition to the calling channel.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Congestion</ref>
-                       <ref type="application">Progress</ref>
-                       <ref type="application">Playtones</ref>
-                       <ref type="application">Hangup</ref>
-               </see-also>
-       </application>
-       <application name="Congestion" language="en_US">
-               <synopsis>
-                       Indicate the Congestion condition.
-               </synopsis>
-               <syntax>
-                       <parameter name="timeout">
-                               <para>If specified, the calling channel will be hung up after the specified number of seconds.
-                               Otherwise, this application will wait until the calling channel hangs up.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will indicate the congestion condition to the calling channel.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Busy</ref>
-                       <ref type="application">Progress</ref>
-                       <ref type="application">Playtones</ref>
-                       <ref type="application">Hangup</ref>
-               </see-also>
-       </application>
-       <application name="ExecIfTime" language="en_US">
-               <synopsis>
-                       Conditional application execution based on the current time.
-               </synopsis>
-               <syntax argsep="?">
-                       <parameter name="day_condition" required="true">
-                               <argument name="times" required="true" />
-                               <argument name="weekdays" required="true" />
-                               <argument name="mdays" required="true" />
-                               <argument name="months" required="true" />
-                               <argument name="timezone" required="false" />
-                       </parameter>
-                       <parameter name="appname" required="true" hasparams="optional">
-                               <argument name="appargs" required="true" />
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will execute the specified dialplan application, with optional
-                       arguments, if the current time matches the given time specification.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Exec</ref>
-                       <ref type="application">ExecIf</ref>
-                       <ref type="application">TryExec</ref>
-                       <ref type="application">GotoIfTime</ref>
-               </see-also>
-       </application>
-       <application name="Goto" language="en_US">
-               <synopsis>
-                       Jump to a particular priority, extension, or context.
-               </synopsis>
-               <syntax>
-                       <parameter name="context" />
-                       <parameter name="extensions" />
-                       <parameter name="priority" required="true" />
-               </syntax>
-               <description>
-                       <para>This application will set the current context, extension, and priority in the channel structure.
-                       After it completes, the pbx engine will continue dialplan execution at the specified location.
-                       If no specific <replaceable>extension</replaceable>, or <replaceable>extension</replaceable> and
-                       <replaceable>context</replaceable>, are specified, then this application will
-                       just set the specified <replaceable>priority</replaceable> of the current extension.</para>
-                       <para>At least a <replaceable>priority</replaceable> is required as an argument, or the goto will
-                       return a <literal>-1</literal>, and the channel and call will be terminated.</para>
-                       <para>If the location that is put into the channel information is bogus, and asterisk cannot
-                       find that location in the dialplan, then the execution engine will try to find and execute the code in
-                       the <literal>i</literal> (invalid) extension in the current context. If that does not exist, it will try to execute the
-                       <literal>h</literal> extension. If neither the <literal>h</literal> nor <literal>i</literal> extensions
-                       have been defined, the channel is hung up, and the execution of instructions on the channel is terminated.
-                       What this means is that, for example, you specify a context that does not exist, then
-                       it will not be possible to find the <literal>h</literal> or <literal>i</literal> extensions,
-                       and the call will terminate!</para>
-               </description>
-               <see-also>
-                       <ref type="application">GotoIf</ref>
-                       <ref type="application">GotoIfTime</ref>
-                       <ref type="application">Gosub</ref>
-                       <ref type="application">Macro</ref>
-               </see-also>
-       </application>
-       <application name="GotoIf" language="en_US">
-               <synopsis>
-                       Conditional goto.
-               </synopsis>
-               <syntax argsep="?">
-                       <parameter name="condition" required="true" />
-                       <parameter name="destination" required="true" argsep=":">
-                               <argument name="labeliftrue">
-                                       <para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.
-                                       Takes the form similar to Goto() of [[context,]extension,]priority.</para>
-                               </argument>
-                               <argument name="labeliffalse">
-                                       <para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.
-                                       Takes the form similar to Goto() of [[context,]extension,]priority.</para>
-                               </argument>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will set the current context, extension, and priority in the channel structure
-                       based on the evaluation of the given condition. After this application completes, the
-                       pbx engine will continue dialplan execution at the specified location in the dialplan.
-                       The labels are specified with the same syntax as used within the Goto application.
-                       If the label chosen by the condition is omitted, no jump is performed, and the execution passes to the
-                       next instruction. If the target location is bogus, and does not exist, the execution engine will try
-                       to find and execute the code in the <literal>i</literal> (invalid) extension in the current context.
-                       If that does not exist, it will try to execute the <literal>h</literal> extension.
-                       If neither the <literal>h</literal> nor <literal>i</literal> extensions have been defined,
-                       the channel is hung up, and the execution of instructions on the channel is terminated.
-                       Remember that this command can set the current context, and if the context specified
-                       does not exist, then it will not be able to find any 'h' or 'i' extensions there, and
-                       the channel and call will both be terminated!.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Goto</ref>
-                       <ref type="application">GotoIfTime</ref>
-                       <ref type="application">GosubIf</ref>
-                       <ref type="application">MacroIf</ref>
-               </see-also>
-       </application>
-       <application name="GotoIfTime" language="en_US">
-               <synopsis>
-                       Conditional Goto based on the current time.
-               </synopsis>
-               <syntax argsep="?">
-                       <parameter name="condition" required="true">
-                               <argument name="times" required="true" />
-                               <argument name="weekdays" required="true" />
-                               <argument name="mdays" required="true" />
-                               <argument name="months" required="true" />
-                               <argument name="timezone" required="false" />
-                       </parameter>
-                       <parameter name="destination" required="true" argsep=":">
-                               <argument name="labeliftrue">
-                                       <para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.
-                                       Takes the form similar to Goto() of [[context,]extension,]priority.</para>
-                               </argument>
-                               <argument name="labeliffalse">
-                                       <para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.
-                                       Takes the form similar to Goto() of [[context,]extension,]priority.</para>
-                               </argument>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will set the context, extension, and priority in the channel structure
-                       based on the evaluation of the given time specification. After this application completes,
-                       the pbx engine will continue dialplan execution at the specified location in the dialplan.
-                       If the current time is within the given time specification, the channel will continue at
-                       <replaceable>labeliftrue</replaceable>. Otherwise the channel will continue at <replaceable>labeliffalse</replaceable>.
-                       If the label chosen by the condition is omitted, no jump is performed, and execution passes to the next
-                       instruction. If the target jump location is bogus, the same actions would be taken as for <literal>Goto</literal>.
-                       Further information on the time specification can be found in examples
-                       illustrating how to do time-based context includes in the dialplan.</para>
-               </description>
-               <see-also>
-                       <ref type="application">GotoIf</ref>
-                       <ref type="application">Goto</ref>
-                       <ref type="function">IFTIME</ref>
-                       <ref type="function">TESTTIME</ref>
-               </see-also>
-       </application>
-       <application name="ImportVar" language="en_US">
-               <synopsis>
-                       Import a variable from a channel into a new variable.
-               </synopsis>
-               <syntax argsep="=">
-                       <parameter name="newvar" required="true" />
-                       <parameter name="vardata" required="true">
-                               <argument name="channelname" required="true" />
-                               <argument name="variable" required="true" />
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application imports a <replaceable>variable</replaceable> from the specified
-                       <replaceable>channel</replaceable> (as opposed to the current one) and stores it as a variable
-                       (<replaceable>newvar</replaceable>) in the current channel (the channel that is calling this
-                       application). Variables created by this application have the same inheritance properties as those
-                       created with the <literal>Set</literal> application.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Set</ref>
-               </see-also>
-       </application>
-       <application name="Hangup" language="en_US">
-               <synopsis>
-                       Hang up the calling channel.
-               </synopsis>
-               <syntax>
-                       <parameter name="causecode">
-                               <para>If a <replaceable>causecode</replaceable> is given the channel's
-                               hangup cause will be set to the given value.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will hang up the calling channel.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Answer</ref>
-                       <ref type="application">Busy</ref>
-                       <ref type="application">Congestion</ref>
-               </see-also>
-       </application>
-       <application name="Incomplete" language="en_US">
-               <synopsis>
-                       Returns AST_PBX_INCOMPLETE value.
-               </synopsis>
-               <syntax>
-                       <parameter name="n">
-                               <para>If specified, then Incomplete will not attempt to answer the channel first.</para>
-                               <note><para>Most channel types need to be in Answer state in order to receive DTMF.</para></note>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>Signals the PBX routines that the previous matched extension is incomplete
-                       and that further input should be allowed before matching can be considered
-                       to be complete.  Can be used within a pattern match when certain criteria warrants
-                       a longer match.</para>
-               </description>
-       </application>
-       <application name="NoOp" language="en_US">
-               <synopsis>
-                       Do Nothing (No Operation).
-               </synopsis>
-               <syntax>
-                       <parameter name="text">
-                               <para>Any text provided can be viewed at the Asterisk CLI.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application does nothing. However, it is useful for debugging purposes.</para>
-                       <para>This method can be used to see the evaluations of variables or functions without having any effect.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Verbose</ref>
-                       <ref type="application">Log</ref>
-               </see-also>
-       </application>
-       <application name="Proceeding" language="en_US">
-               <synopsis>
-                       Indicate proceeding.
-               </synopsis>
-               <syntax />
-               <description>
-                       <para>This application will request that a proceeding message be provided to the calling channel.</para>
-               </description>
-       </application>
-       <application name="Progress" language="en_US">
-               <synopsis>
-                       Indicate progress.
-               </synopsis>
-               <syntax />
-               <description>
-                       <para>This application will request that in-band progress information be provided to the calling channel.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Busy</ref>
-                       <ref type="application">Congestion</ref>
-                       <ref type="application">Ringing</ref>
-                       <ref type="application">Playtones</ref>
-               </see-also>
-       </application>
-       <application name="RaiseException" language="en_US">
-               <synopsis>
-                       Handle an exceptional condition.
-               </synopsis>
-               <syntax>
-                       <parameter name="reason" required="true" />
-               </syntax>
-               <description>
-                       <para>This application will jump to the <literal>e</literal> extension in the current context, setting the
-                       dialplan function EXCEPTION(). If the <literal>e</literal> extension does not exist, the call will hangup.</para>
-               </description>
-               <see-also>
-                       <ref type="function">Exception</ref>
-               </see-also>
-       </application>
-       <application name="Ringing" language="en_US">
-               <synopsis>
-                       Indicate ringing tone.
-               </synopsis>
-               <syntax />
-               <description>
-                       <para>This application will request that the channel indicate a ringing tone to the user.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Busy</ref>
-                       <ref type="application">Congestion</ref>
-                       <ref type="application">Progress</ref>
-                       <ref type="application">Playtones</ref>
-               </see-also>
-       </application>
-       <application name="SayAlpha" language="en_US">
-               <synopsis>
-                       Say Alpha.
-               </synopsis>
-               <syntax>
-                       <parameter name="string" required="true" />
-               </syntax>
-               <description>
-                       <para>This application will play the sounds that correspond to the letters
-                       of the given <replaceable>string</replaceable>. If the channel variable
-                       <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive),
-                       then this application will react to DTMF in the same way as
-                       <literal>Background</literal>.</para>
-               </description>
-               <see-also>
-                       <ref type="application">SayDigits</ref>
-                       <ref type="application">SayNumber</ref>
-                       <ref type="application">SayPhonetic</ref>
-                       <ref type="function">CHANNEL</ref>
-               </see-also>
-       </application>
-       <application name="SayAlphaCase" language="en_US">
-               <synopsis>
-                       Say Alpha.
-               </synopsis>
-               <syntax>
-                       <parameter name="casetype" required="true" >
-                               <enumlist>
-                                       <enum name="a">
-                                               <para>Case sensitive (all) pronunciation.
-                                               (Ex: SayAlphaCase(a,aBc); - lowercase a uppercase b lowercase c).</para>
-                                       </enum>
-                                       <enum name="l">
-                                               <para>Case sensitive (lower) pronunciation.
-                                               (Ex: SayAlphaCase(l,aBc); - lowercase a b lowercase c).</para>
-                                       </enum>
-                                       <enum name="n">
-                                               <para>Case insensitive pronunciation. Equivalent to SayAlpha.
-                                               (Ex: SayAlphaCase(n,aBc) - a b c).</para>
-                                       </enum>
-                                       <enum name="u">
-                                               <para>Case sensitive (upper) pronunciation.
-                                               (Ex: SayAlphaCase(u,aBc); - a uppercase b c).</para>
-                                       </enum>
-                               </enumlist>
-                       </parameter>
-                       <parameter name="string" required="true" />
-               </syntax>
-               <description>
-                       <para>This application will play the sounds that correspond to the letters of the
-                       given <replaceable>string</replaceable>.  Optionally, a <replaceable>casetype</replaceable> may be
-                       specified.  This will be used for case-insensitive or case-sensitive pronunciations. If the channel
-                       variable <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
-                       application will react to DTMF in the same way as <literal>Background</literal>.</para>
-               </description>
-               <see-also>
-                       <ref type="application">SayDigits</ref>
-                       <ref type="application">SayNumber</ref>
-                       <ref type="application">SayPhonetic</ref>
-                       <ref type="application">SayAlpha</ref>
-                       <ref type="function">CHANNEL</ref>
-               </see-also>
-       </application>
-       <application name="SayDigits" language="en_US">
-               <synopsis>
-                       Say Digits.
-               </synopsis>
-               <syntax>
-                       <parameter name="digits" required="true" />
-               </syntax>
-               <description>
-                       <para>This application will play the sounds that correspond to the digits of
-                       the given number. This will use the language that is currently set for the channel.
-                       If the channel variable <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true'
-                       (case insensitive), then this application will react to DTMF in the same way as
-                       <literal>Background</literal>.</para>
-               </description>
-               <see-also>
-                       <ref type="application">SayAlpha</ref>
-                       <ref type="application">SayNumber</ref>
-                       <ref type="application">SayPhonetic</ref>
-                       <ref type="function">CHANNEL</ref>
-               </see-also>
-       </application>
-       <application name="SayNumber" language="en_US">
-               <synopsis>
-                       Say Number.
-               </synopsis>
-               <syntax>
-                       <parameter name="digits" required="true" />
-                       <parameter name="gender" />
-               </syntax>
-               <description>
-                       <para>This application will play the sounds that correspond to the given
-                       <replaceable>digits</replaceable>. Optionally, a <replaceable>gender</replaceable> may be
-                       specified. This will use the language that is currently set for the channel. See the CHANNEL()
-                       function for more information on setting the language for the channel. If the channel variable
-                       <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
-                       application will react to DTMF in the same way as <literal>Background</literal>.</para>
-               </description>
-               <see-also>
-                       <ref type="application">SayAlpha</ref>
-                       <ref type="application">SayDigits</ref>
-                       <ref type="application">SayPhonetic</ref>
-                       <ref type="function">CHANNEL</ref>
-               </see-also>
-       </application>
-       <application name="SayPhonetic" language="en_US">
-               <synopsis>
-                       Say Phonetic.
-               </synopsis>
-               <syntax>
-                       <parameter name="string" required="true" />
-               </syntax>
-               <description>
-                       <para>This application will play the sounds from the phonetic alphabet that correspond to the
-                       letters in the given <replaceable>string</replaceable>. If the channel variable
-                       <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
-                       application will react to DTMF in the same way as <literal>Background</literal>.</para>
-               </description>
-               <see-also>
-                       <ref type="application">SayAlpha</ref>
-                       <ref type="application">SayDigits</ref>
-                       <ref type="application">SayNumber</ref>
-               </see-also>
-       </application>
-       <application name="Set" language="en_US">
-               <synopsis>
-                       Set channel variable or function value.
-               </synopsis>
-               <syntax argsep="=">
-                       <parameter name="name" required="true" />
-                       <parameter name="value" required="true" />
-               </syntax>
-               <description>
-                       <para>This function can be used to set the value of channel variables or dialplan functions.
-                       When setting variables, if the variable name is prefixed with <literal>_</literal>,
-                       the variable will be inherited into channels created from the current channel.
-                       If the variable name is prefixed with <literal>__</literal>, the variable will be
-                       inherited into channels created from the current channel and all children channels.</para>
-                       <note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have
-                       a <literal>[compat]</literal> category, and you have <literal>app_set = 1.4</literal> under that, then
-                       the behavior of this app changes, and strips surrounding quotes from the right hand side as
-                       it did previously in 1.4.
-                       The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar)
-                       were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly
-                       protect separators and quotes in various database access strings has been greatly
-                       reduced by these changes.</para></note>
-               </description>
-               <see-also>
-                       <ref type="application">MSet</ref>
-                       <ref type="function">GLOBAL</ref>
-                       <ref type="function">SET</ref>
-                       <ref type="function">ENV</ref>
-               </see-also>
-       </application>
-       <application name="MSet" language="en_US">
-               <synopsis>
-                       Set channel variable(s) or function value(s).
-               </synopsis>
-               <syntax>
-                       <parameter name="set1" required="true" argsep="=">
-                               <argument name="name1" required="true" />
-                               <argument name="value1" required="true" />
-                       </parameter>
-                       <parameter name="set2" multiple="true" argsep="=">
-                               <argument name="name2" required="true" />
-                               <argument name="value2" required="true" />
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This function can be used to set the value of channel variables or dialplan functions.
-                       When setting variables, if the variable name is prefixed with <literal>_</literal>,
-                       the variable will be inherited into channels created from the current channel
-                       If the variable name is prefixed with <literal>__</literal>, the variable will be
-                       inherited into channels created from the current channel and all children channels.
-                       MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus
-                       prone to doing things that you may not expect. For example, it strips surrounding
-                       double-quotes from the right-hand side (value). If you need to put a separator
-                       character (comma or vert-bar), you will need to escape them by inserting a backslash
-                       before them. Avoid its use if possible.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Set</ref>
-               </see-also>
-       </application>
-       <application name="SetAMAFlags" language="en_US">
-               <synopsis>
-                       Set the AMA Flags.
-               </synopsis>
-               <syntax>
-                       <parameter name="flag" />
-               </syntax>
-               <description>
-                       <para>This application will set the channel's AMA Flags for billing purposes.</para>
-                       <warning><para>This application is deprecated. Please use the CHANNEL function instead.</para></warning>
-               </description>
-               <see-also>
-                       <ref type="function">CDR</ref>
-                       <ref type="function">CHANNEL</ref>
-               </see-also>
-       </application>
-       <application name="Wait" language="en_US">
-               <synopsis>
-                       Waits for some time.
-               </synopsis>
-               <syntax>
-                       <parameter name="seconds" required="true">
-                               <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
-                               application to wait for 1.5 seconds.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application waits for a specified number of <replaceable>seconds</replaceable>.</para>
-               </description>
-       </application>
-       <application name="WaitExten" language="en_US">
-               <synopsis>
-                       Waits for an extension to be entered.
-               </synopsis>
-               <syntax>
-                       <parameter name="seconds">
-                               <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
-                               application to wait for 1.5 seconds.</para>
-                       </parameter>
-                       <parameter name="options">
-                               <optionlist>
-                                       <option name="m">
-                                               <para>Provide music on hold to the caller while waiting for an extension.</para>
-                                               <argument name="x">
-                                                       <para>Specify the class for music on hold. <emphasis>CHANNEL(musicclass) will
-                                                       be used instead if set</emphasis></para>
-                                               </argument>
-                                       </option>
-                               </optionlist>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application waits for the user to enter a new extension for a specified number
-                       of <replaceable>seconds</replaceable>.</para>
-                       <xi:include xpointer="xpointer(/docs/application[@name='Macro']/description/warning[2])" />
-               </description>
-               <see-also>
-                       <ref type="application">Background</ref>
-                       <ref type="function">TIMEOUT</ref>
-               </see-also>
-       </application>
        <function name="EXCEPTION" language="en_US">
                <synopsis>
                        Retrieve the details of the current dialplan exception.
@@ -850,32 +220,10 @@ ASTERISK_REGISTER_FILE()
 
 #define SWITCH_DATA_LENGTH 256
 
-#define VAR_BUF_SIZE 4096
-
 #define        VAR_NORMAL              1
 #define        VAR_SOFTTRAN    2
 #define        VAR_HARDTRAN    3
 
-#define BACKGROUND_SKIP                (1 << 0)
-#define BACKGROUND_NOANSWER    (1 << 1)
-#define BACKGROUND_MATCHEXTEN  (1 << 2)
-#define BACKGROUND_PLAYBACK    (1 << 3)
-
-AST_APP_OPTIONS(background_opts, {
-       AST_APP_OPTION('s', BACKGROUND_SKIP),
-       AST_APP_OPTION('n', BACKGROUND_NOANSWER),
-       AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
-       AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
-});
-
-#define WAITEXTEN_MOH          (1 << 0)
-#define WAITEXTEN_DIALTONE     (1 << 1)
-
-AST_APP_OPTIONS(waitexten_opts, {
-       AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
-       AST_APP_OPTION_ARG('d', WAITEXTEN_DIALTONE, 0),
-});
-
 struct ast_context;
 struct ast_app;
 
@@ -1263,34 +611,10 @@ struct pbx_exception {
        int priority;                           /*!< Priority associated with this exception */
 };
 
-static int pbx_builtin_answer(struct ast_channel *, const char *);
-static int pbx_builtin_goto(struct ast_channel *, const char *);
-static int pbx_builtin_hangup(struct ast_channel *, const char *);
-static int pbx_builtin_background(struct ast_channel *, const char *);
-static int pbx_builtin_wait(struct ast_channel *, const char *);
-static int pbx_builtin_waitexten(struct ast_channel *, const char *);
-static int pbx_builtin_incomplete(struct ast_channel *, const char *);
-static int pbx_builtin_setamaflags(struct ast_channel *, const char *);
-static int pbx_builtin_ringing(struct ast_channel *, const char *);
-static int pbx_builtin_proceeding(struct ast_channel *, const char *);
-static int pbx_builtin_progress(struct ast_channel *, const char *);
-static int pbx_builtin_congestion(struct ast_channel *, const char *);
-static int pbx_builtin_busy(struct ast_channel *, const char *);
-static int pbx_builtin_noop(struct ast_channel *, const char *);
-static int pbx_builtin_gotoif(struct ast_channel *, const char *);
-static int pbx_builtin_gotoiftime(struct ast_channel *, const char *);
-static int pbx_builtin_execiftime(struct ast_channel *, const char *);
-static int pbx_builtin_saynumber(struct ast_channel *, const char *);
-static int pbx_builtin_saydigits(struct ast_channel *, const char *);
-static int pbx_builtin_saycharacters(struct ast_channel *, const char *);
-static int pbx_builtin_saycharacters_case(struct ast_channel *, const char *);
-static int pbx_builtin_sayphonetic(struct ast_channel *, const char *);
 static int matchcid(const char *cidpattern, const char *callerid);
 #ifdef NEED_DEBUG
 static void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */
 #endif
-static int pbx_builtin_importvar(struct ast_channel *, const char *);
-static void set_ext_pri(struct ast_channel *c, const char *exten, int pri);
 static void new_find_extension(const char *str, struct scoreboard *score,
                struct match_char *tree, int length, int spec, const char *callerid,
                const char *label, enum ext_match_t action);
@@ -1442,43 +766,6 @@ static int totalcalls;
  */
 static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
 
-/*! \brief Declaration of builtin applications */
-static struct pbx_builtin {
-       char name[AST_MAX_APP];
-       int (*execute)(struct ast_channel *chan, const char *data);
-} builtins[] =
-{
-       /* These applications are built into the PBX core and do not
-          need separate modules */
-
-       { "Answer",         pbx_builtin_answer },
-       { "BackGround",     pbx_builtin_background },
-       { "Busy",           pbx_builtin_busy },
-       { "Congestion",     pbx_builtin_congestion },
-       { "ExecIfTime",     pbx_builtin_execiftime },
-       { "Goto",           pbx_builtin_goto },
-       { "GotoIf",         pbx_builtin_gotoif },
-       { "GotoIfTime",     pbx_builtin_gotoiftime },
-       { "ImportVar",      pbx_builtin_importvar },
-       { "Hangup",         pbx_builtin_hangup },
-       { "Incomplete",     pbx_builtin_incomplete },
-       { "NoOp",           pbx_builtin_noop },
-       { "Proceeding",     pbx_builtin_proceeding },
-       { "Progress",       pbx_builtin_progress },
-       { "RaiseException", pbx_builtin_raise_exception },
-       { "Ringing",        pbx_builtin_ringing },
-       { "SayAlpha",       pbx_builtin_saycharacters },
-       { "SayAlphaCase",   pbx_builtin_saycharacters_case },
-       { "SayDigits",      pbx_builtin_saydigits },
-       { "SayNumber",      pbx_builtin_saynumber },
-       { "SayPhonetic",    pbx_builtin_sayphonetic },
-       { "Set",            pbx_builtin_setvar },
-       { "MSet",           pbx_builtin_setvar_multiple },
-       { "SetAMAFlags",    pbx_builtin_setamaflags },
-       { "Wait",           pbx_builtin_wait },
-       { "WaitExten",      pbx_builtin_waitexten }
-};
-
 static struct ast_context *contexts;
 static struct ast_hashtab *contexts_table = NULL;
 
@@ -3822,7 +3109,7 @@ static const struct ast_datastore_info exception_store_info = {
  * \retval 0 on success.
  * \retval -1 on error.
  */
-static int raise_exception(struct ast_channel *chan, const char *reason, int priority)
+int raise_exception(struct ast_channel *chan, const char *reason, int priority)
 {
        struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
        struct pbx_exception *exception = NULL;
@@ -3848,12 +3135,6 @@ static int raise_exception(struct ast_channel *chan, const char *reason, int pri
        return 0;
 }
 
-int pbx_builtin_raise_exception(struct ast_channel *chan, const char *reason)
-{
-       /* Priority will become 1, next time through the AUTOLOOP */
-       return raise_exception(chan, reason, 0);
-}
-
 static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
 {
        struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
@@ -6463,7 +5744,7 @@ static char *handle_show_hangup_all(struct ast_cli_entry *e, int cmd, struct ast
 }
 
 /*! helper function to set extension and priority */
-static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
+void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
 {
        ast_channel_lock(c);
        ast_channel_exten_set(c, exten);
@@ -6723,11 +6004,11 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
                                        status = "UNKNOWN";
                                ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", ast_channel_name(c), status);
                                if (!strcasecmp(status, "CONGESTION"))
-                                       res = pbx_builtin_congestion(c, "10");
+                                       res = indicate_congestion(c, "10");
                                else if (!strcasecmp(status, "CHANUNAVAIL"))
-                                       res = pbx_builtin_congestion(c, "10");
+                                       res = indicate_congestion(c, "10");
                                else if (!strcasecmp(status, "BUSY"))
-                                       res = pbx_builtin_busy(c, "10");
+                                       res = indicate_busy(c, "10");
                                error = 1; /* XXX disable message */
                                break;  /* exit from the 'for' loop */
                        }
@@ -11047,7 +10328,7 @@ void ast_context_destroy(struct ast_context *con, const char *registrar)
        ast_unlock_contexts();
 }
 
-static void wait_for_hangup(struct ast_channel *chan, const void *data)
+void wait_for_hangup(struct ast_channel *chan, const void *data)
 {
        int res;
        struct ast_frame *f;
@@ -11070,211 +10351,29 @@ static void wait_for_hangup(struct ast_channel *chan, const void *data)
 }
 
 /*!
- * \ingroup applications
+ * \ingroup functions
  */
-static int pbx_builtin_proceeding(struct ast_channel *chan, const char *data)
+static int testtime_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
 {
-       ast_indicate(chan, AST_CONTROL_PROCEEDING);
-       return 0;
-}
-
-/*!
- * \ingroup applications
- */
-static int pbx_builtin_progress(struct ast_channel *chan, const char *data)
-{
-       ast_indicate(chan, AST_CONTROL_PROGRESS);
-       return 0;
-}
-
-/*!
- * \ingroup applications
- */
-static int pbx_builtin_ringing(struct ast_channel *chan, const char *data)
-{
-       ast_indicate(chan, AST_CONTROL_RINGING);
-       return 0;
-}
-
-/*!
- * \ingroup applications
- */
-static int pbx_builtin_busy(struct ast_channel *chan, const char *data)
-{
-       ast_indicate(chan, AST_CONTROL_BUSY);
-       /* Don't change state of an UP channel, just indicate
-          busy in audio */
-       ast_channel_lock(chan);
-       if (ast_channel_state(chan) != AST_STATE_UP) {
-               ast_channel_hangupcause_set(chan, AST_CAUSE_BUSY);
-               ast_setstate(chan, AST_STATE_BUSY);
-       }
-       ast_channel_unlock(chan);
-       wait_for_hangup(chan, data);
-       return -1;
-}
-
-/*!
- * \ingroup applications
- */
-static int pbx_builtin_congestion(struct ast_channel *chan, const char *data)
-{
-       ast_indicate(chan, AST_CONTROL_CONGESTION);
-       /* Don't change state of an UP channel, just indicate
-          congestion in audio */
-       ast_channel_lock(chan);
-       if (ast_channel_state(chan) != AST_STATE_UP) {
-               ast_channel_hangupcause_set(chan, AST_CAUSE_CONGESTION);
-               ast_setstate(chan, AST_STATE_BUSY);
-       }
-       ast_channel_unlock(chan);
-       wait_for_hangup(chan, data);
-       return -1;
-}
-
-/*!
- * \ingroup applications
- */
-static int pbx_builtin_answer(struct ast_channel *chan, const char *data)
-{
-       int delay = 0;
-       char *parse;
-       AST_DECLARE_APP_ARGS(args,
-               AST_APP_ARG(delay);
-               AST_APP_ARG(answer_cdr);
-       );
-
-       if (ast_strlen_zero(data)) {
-               return __ast_answer(chan, 0);
-       }
-
-       parse = ast_strdupa(data);
-
-       AST_STANDARD_APP_ARGS(args, parse);
-
-       if (!ast_strlen_zero(args.delay) && (ast_channel_state(chan) != AST_STATE_UP))
-               delay = atoi(data);
-
-       if (delay < 0) {
-               delay = 0;
-       }
-
-       if (!ast_strlen_zero(args.answer_cdr) && !strcasecmp(args.answer_cdr, "nocdr")) {
-               ast_log(AST_LOG_WARNING, "The nocdr option for the Answer application has been removed and is no longer supported.\n");
-       }
-
-       return __ast_answer(chan, delay);
-}
-
-static int pbx_builtin_incomplete(struct ast_channel *chan, const char *data)
-{
-       const char *options = data;
-       int answer = 1;
-
-       /* Some channels can receive DTMF in unanswered state; some cannot */
-       if (!ast_strlen_zero(options) && strchr(options, 'n')) {
-               answer = 0;
-       }
-
-       /* If the channel is hungup, stop waiting */
-       if (ast_check_hangup(chan)) {
-               return -1;
-       } else if (ast_channel_state(chan) != AST_STATE_UP && answer) {
-               __ast_answer(chan, 0);
-       }
-
-       ast_indicate(chan, AST_CONTROL_INCOMPLETE);
-
-       return AST_PBX_INCOMPLETE;
-}
-
-/*!
- * \ingroup applications
- */
-static int pbx_builtin_setamaflags(struct ast_channel *chan, const char *data)
-{
-       ast_log(AST_LOG_WARNING, "The SetAMAFlags application is deprecated. Please use the CHANNEL function instead.\n");
-
-       if (ast_strlen_zero(data)) {
-               ast_log(AST_LOG_WARNING, "No parameter passed to SetAMAFlags\n");
-               return 0;
-       }
-       /* Copy the AMA Flags as specified */
-       ast_channel_lock(chan);
-       if (isdigit(data[0])) {
-               int amaflags;
-               if (sscanf(data, "%30d", &amaflags) != 1) {
-                       ast_log(AST_LOG_WARNING, "Unable to set AMA flags on channel %s\n", ast_channel_name(chan));
-                       ast_channel_unlock(chan);
-                       return 0;
-               }
-               ast_channel_amaflags_set(chan, amaflags);
-       } else {
-               ast_channel_amaflags_set(chan, ast_channel_string2amaflag(data));
-       }
-       ast_channel_unlock(chan);
-       return 0;
-}
-
-/*!
- * \ingroup applications
- */
-static int pbx_builtin_hangup(struct ast_channel *chan, const char *data)
-{
-       int cause;
-
-       ast_set_hangupsource(chan, "dialplan/builtin", 0);
-
-       if (!ast_strlen_zero(data)) {
-               cause = ast_str2cause(data);
-               if (cause <= 0) {
-                       if (sscanf(data, "%30d", &cause) != 1 || cause <= 0) {
-                               ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", data);
-                               cause = 0;
-                       }
-               }
-       } else {
-               cause = 0;
-       }
-
-       ast_channel_lock(chan);
-       if (cause <= 0) {
-               cause = ast_channel_hangupcause(chan);
-               if (cause <= 0) {
-                       cause = AST_CAUSE_NORMAL_CLEARING;
-               }
-       }
-       ast_channel_hangupcause_set(chan, cause);
-       ast_softhangup_nolock(chan, AST_SOFTHANGUP_EXPLICIT);
-       ast_channel_unlock(chan);
-
-       return -1;
-}
-
-/*!
- * \ingroup functions
- */
-static int testtime_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
-{
-       struct ast_tm tm;
-       struct timeval tv;
-       char *remainder, result[30], timezone[80];
-
-       /* Turn off testing? */
-       if (!pbx_checkcondition(value)) {
-               pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
-               return 0;
-       }
-
-       /* Parse specified time */
-       if (!(remainder = ast_strptime(value, "%Y/%m/%d %H:%M:%S", &tm))) {
-               return -1;
-       }
-       sscanf(remainder, "%79s", timezone);
-       tv = ast_mktime(&tm, S_OR(timezone, NULL));
-
-       snprintf(result, sizeof(result), "%ld", (long) tv.tv_sec);
-       pbx_builtin_setvar_helper(chan, "__TESTTIME", result);
+       struct ast_tm tm;
+       struct timeval tv;
+       char *remainder, result[30], timezone[80];
+
+       /* Turn off testing? */
+       if (!pbx_checkcondition(value)) {
+               pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
+               return 0;
+       }
+
+       /* Parse specified time */
+       if (!(remainder = ast_strptime(value, "%Y/%m/%d %H:%M:%S", &tm))) {
+               return -1;
+       }
+       sscanf(remainder, "%79s", timezone);
+       tv = ast_mktime(&tm, S_OR(timezone, NULL));
+
+       snprintf(result, sizeof(result), "%ld", (long) tv.tv_sec);
+       pbx_builtin_setvar_helper(chan, "__TESTTIME", result);
        return 0;
 }
 
@@ -11283,333 +10382,6 @@ static struct ast_custom_function testtime_function = {
        .write = testtime_write,
 };
 
-/*!
- * \ingroup applications
- */
-static int pbx_builtin_gotoiftime(struct ast_channel *chan, const char *data)
-{
-       char *s, *ts, *branch1, *branch2, *branch;
-       struct ast_timing timing;
-       const char *ctime;
-       struct timeval tv = ast_tvnow();
-       long timesecs;
-
-       if (!chan) {
-               ast_log(LOG_WARNING, "GotoIfTime requires a channel on which to operate\n");
-               return -1;
-       }
-
-       if (ast_strlen_zero(data)) {
-               ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n  <time range>,<days of week>,<days of month>,<months>[,<timezone>]?'labeliftrue':'labeliffalse'\n");
-               return -1;
-       }
-
-       ts = s = ast_strdupa(data);
-
-       ast_channel_lock(chan);
-       if ((ctime = pbx_builtin_getvar_helper(chan, "TESTTIME")) && sscanf(ctime, "%ld", &timesecs) == 1) {
-               tv.tv_sec = timesecs;
-       } else if (ctime) {
-               ast_log(LOG_WARNING, "Using current time to evaluate\n");
-               /* Reset when unparseable */
-               pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
-       }
-       ast_channel_unlock(chan);
-
-       /* Separate the Goto path */
-       strsep(&ts, "?");
-       branch1 = strsep(&ts,":");
-       branch2 = strsep(&ts,"");
-
-       /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
-       if (ast_build_timing(&timing, s) && ast_check_timing2(&timing, tv)) {
-               branch = branch1;
-       } else {
-               branch = branch2;
-       }
-       ast_destroy_timing(&timing);
-
-       if (ast_strlen_zero(branch)) {
-               ast_debug(1, "Not taking any branch\n");
-               return 0;
-       }
-
-       return pbx_builtin_goto(chan, branch);
-}
-
-/*!
- * \ingroup applications
- */
-static int pbx_builtin_execiftime(struct ast_channel *chan, const char *data)
-{
-       char *s, *appname;
-       struct ast_timing timing;
-       struct ast_app *app;
-       static const char * const usage = "ExecIfTime requires an argument:\n  <time range>,<days of week>,<days of month>,<months>[,<timezone>]?<appname>[(<appargs>)]";
-
-       if (ast_strlen_zero(data)) {
-               ast_log(LOG_WARNING, "%s\n", usage);
-               return -1;
-       }
-
-       appname = ast_strdupa(data);
-
-       s = strsep(&appname, "?");      /* Separate the timerange and application name/data */
-       if (!appname) { /* missing application */
-               ast_log(LOG_WARNING, "%s\n", usage);
-               return -1;
-       }
-
-       if (!ast_build_timing(&timing, s)) {
-               ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
-               ast_destroy_timing(&timing);
-               return -1;
-       }
-
-       if (!ast_check_timing(&timing)) { /* outside the valid time window, just return */
-               ast_destroy_timing(&timing);
-               return 0;
-       }
-       ast_destroy_timing(&timing);
-
-       /* now split appname(appargs) */
-       if ((s = strchr(appname, '('))) {
-               char *e;
-               *s++ = '\0';
-               if ((e = strrchr(s, ')')))
-                       *e = '\0';
-               else
-                       ast_log(LOG_WARNING, "Failed to find closing parenthesis\n");
-       }
-
-
-       if ((app = pbx_findapp(appname))) {
-               return pbx_exec(chan, app, S_OR(s, ""));
-       } else {
-               ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
-               return -1;
-       }
-}
-
-/*!
- * \ingroup applications
- */
-static int pbx_builtin_wait(struct ast_channel *chan, const char *data)
-{
-       int ms;
-
-       /* Wait for "n" seconds */
-       if (!ast_app_parse_timelen(data, &ms, TIMELEN_SECONDS) && ms > 0) {
-               return ast_safe_sleep(chan, ms);
-       }
-       return 0;
-}
-
-/*!
- * \ingroup applications
- */
-static int pbx_builtin_waitexten(struct ast_channel *chan, const char *data)
-{
-       int ms, res;
-       struct ast_flags flags = {0};
-       char *opts[1] = { NULL };
-       char *parse;
-       AST_DECLARE_APP_ARGS(args,
-               AST_APP_ARG(timeout);
-               AST_APP_ARG(options);
-       );
-
-       if (!ast_strlen_zero(data)) {
-               parse = ast_strdupa(data);
-               AST_STANDARD_APP_ARGS(args, parse);
-       } else
-               memset(&args, 0, sizeof(args));
-
-       if (args.options)
-               ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
-
-       if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
-               ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n");
-       } else if (ast_test_flag(&flags, WAITEXTEN_MOH)) {
-               ast_indicate_data(chan, AST_CONTROL_HOLD, S_OR(opts[0], NULL),
-                       !ast_strlen_zero(opts[0]) ? strlen(opts[0]) + 1 : 0);
-       } else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE)) {
-               struct ast_tone_zone_sound *ts = ast_get_indication_tone(ast_channel_zone(chan), "dial");
-               if (ts) {
-                       ast_playtones_start(chan, 0, ts->data, 0);
-                       ts = ast_tone_zone_sound_unref(ts);
-               } else {
-                       ast_tonepair_start(chan, 350, 440, 0, 0);
-               }
-       }
-       /* Wait for "n" seconds */
-       if (!ast_app_parse_timelen(args.timeout, &ms, TIMELEN_SECONDS) && ms > 0) {
-               /* Yay! */
-       } else if (ast_channel_pbx(chan)) {
-               ms = ast_channel_pbx(chan)->rtimeoutms;
-       } else {
-               ms = 10000;
-       }
-
-       res = ast_waitfordigit(chan, ms);
-       if (!res) {
-               if (ast_check_hangup(chan)) {
-                       /* Call is hungup for some reason. */
-                       res = -1;
-               } else if (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan) + 1,
-                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
-                       ast_verb(3, "Timeout on %s, continuing...\n", ast_channel_name(chan));
-               } else if (ast_exists_extension(chan, ast_channel_context(chan), "t", 1,
-                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
-                       ast_verb(3, "Timeout on %s, going to 't'\n", ast_channel_name(chan));
-                       set_ext_pri(chan, "t", 0); /* 0 will become 1, next time through the loop */
-               } else if (ast_exists_extension(chan, ast_channel_context(chan), "e", 1,
-                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
-                       raise_exception(chan, "RESPONSETIMEOUT", 0); /* 0 will become 1, next time through the loop */
-               } else {
-                       ast_log(LOG_WARNING, "Timeout but no rule 't' or 'e' in context '%s'\n",
-                               ast_channel_context(chan));
-                       res = -1;
-               }
-       }
-
-       if (ast_test_flag(&flags, WAITEXTEN_MOH))
-               ast_indicate(chan, AST_CONTROL_UNHOLD);
-       else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE))
-               ast_playtones_stop(chan);
-
-       return res;
-}
-
-/*!
- * \ingroup applications
- */
-static int pbx_builtin_background(struct ast_channel *chan, const char *data)
-{
-       int res = 0;
-       int mres = 0;
-       struct ast_flags flags = {0};
-       char *parse, exten[2] = "";
-       AST_DECLARE_APP_ARGS(args,
-               AST_APP_ARG(filename);
-               AST_APP_ARG(options);
-               AST_APP_ARG(lang);
-               AST_APP_ARG(context);
-       );
-
-       if (ast_strlen_zero(data)) {
-               ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
-               return -1;
-       }
-
-       parse = ast_strdupa(data);
-
-       AST_STANDARD_APP_ARGS(args, parse);
-
-       if (ast_strlen_zero(args.lang))
-               args.lang = (char *)ast_channel_language(chan); /* XXX this is const */
-
-       if (ast_strlen_zero(args.context)) {
-               const char *context;
-               ast_channel_lock(chan);
-               if ((context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"))) {
-                       args.context = ast_strdupa(context);
-               } else {
-                       args.context = ast_strdupa(ast_channel_context(chan));
-               }
-               ast_channel_unlock(chan);
-       }
-
-       if (args.options) {
-               if (!strcasecmp(args.options, "skip"))
-                       flags.flags = BACKGROUND_SKIP;
-               else if (!strcasecmp(args.options, "noanswer"))
-                       flags.flags = BACKGROUND_NOANSWER;
-               else
-                       ast_app_parse_options(background_opts, &flags, NULL, args.options);
-       }
-
-       /* Answer if need be */
-       if (ast_channel_state(chan) != AST_STATE_UP) {
-               if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
-                       goto done;
-               } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
-                       res = ast_answer(chan);
-               }
-       }
-
-       if (!res) {
-               char *back = ast_strip(args.filename);
-               char *front;
-
-               ast_stopstream(chan);           /* Stop anything playing */
-               /* Stream the list of files */
-               while (!res && (front = strsep(&back, "&")) ) {
-                       if ( (res = ast_streamfile(chan, front, args.lang)) ) {
-                               ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", ast_channel_name(chan), (char*)data);
-                               res = 0;
-                               mres = 1;
-                               break;
-                       }
-                       if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
-                               res = ast_waitstream(chan, "");
-                       } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
-                               res = ast_waitstream_exten(chan, args.context);
-                       } else {
-                               res = ast_waitstream(chan, AST_DIGIT_ANY);
-                       }
-                       ast_stopstream(chan);
-               }
-       }
-
-       /*
-        * If the single digit DTMF is an extension in the specified context, then
-        * go there and signal no DTMF.  Otherwise, we should exit with that DTMF.
-        * If we're in Macro, we'll exit and seek that DTMF as the beginning of an
-        * extension in the Macro's calling context.  If we're not in Macro, then
-        * we'll simply seek that extension in the calling context.  Previously,
-        * someone complained about the behavior as it related to the interior of a
-        * Gosub routine, and the fix (#14011) inadvertently broke FreePBX
-        * (#14940).  This change should fix both of these situations, but with the
-        * possible incompatibility that if a single digit extension does not exist
-        * (but a longer extension COULD have matched), it would have previously
-        * gone immediately to the "i" extension, but will now need to wait for a
-        * timeout.
-        *
-        * Later, we had to add a flag to disable this workaround, because AGI
-        * users can EXEC Background and reasonably expect that the DTMF code will
-        * be returned (see #16434).
-        */
-       if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS)
-               && (exten[0] = res)
-               && ast_canmatch_extension(chan, args.context, exten, 1,
-                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
-               && !ast_matchmore_extension(chan, args.context, exten, 1,
-                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
-               char buf[2] = { 0, };
-               snprintf(buf, sizeof(buf), "%c", res);
-               ast_channel_exten_set(chan, buf);
-               ast_channel_context_set(chan, args.context);
-               ast_channel_priority_set(chan, 0);
-               res = 0;
-       }
-done:
-       pbx_builtin_setvar_helper(chan, "BACKGROUNDSTATUS", mres ? "FAILED" : "SUCCESS");
-       return res;
-}
-
-/*! Goto
- * \ingroup applications
- */
-static int pbx_builtin_goto(struct ast_channel *chan, const char *data)
-{
-       int res = ast_parseable_goto(chan, data);
-       if (!res)
-               ast_verb(3, "Goto (%s,%s,%d)\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan) + 1);
-       return res;
-}
-
-
 int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
 {
        struct ast_var_t *variables;
@@ -11832,46 +10604,6 @@ int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *vdata)
        return 0;
 }
 
-int pbx_builtin_importvar(struct ast_channel *chan, const char *data)
-{
-       char *name;
-       char *value;
-       char *channel;
-       char tmp[VAR_BUF_SIZE];
-       static int deprecation_warning = 0;
-
-       if (ast_strlen_zero(data)) {
-               ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
-               return 0;
-       }
-       tmp[0] = 0;
-       if (!deprecation_warning) {
-               ast_log(LOG_WARNING, "ImportVar is deprecated.  Please use Set(varname=${IMPORT(channel,variable)}) instead.\n");
-               deprecation_warning = 1;
-       }
-
-       value = ast_strdupa(data);
-       name = strsep(&value,"=");
-       channel = strsep(&value,",");
-       if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
-               struct ast_channel *chan2 = ast_channel_get_by_name(channel);
-               if (chan2) {
-                       char *s = ast_alloca(strlen(value) + 4);
-                       sprintf(s, "${%s}", value);
-                       pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
-                       chan2 = ast_channel_unref(chan2);
-               }
-               pbx_builtin_setvar_helper(chan, name, tmp);
-       }
-
-       return(0);
-}
-
-static int pbx_builtin_noop(struct ast_channel *chan, const char *data)
-{
-       return 0;
-}
-
 void pbx_builtin_clear_globals(void)
 {
        struct ast_var_t *vardata;
@@ -11894,191 +10626,6 @@ int pbx_checkcondition(const char *condition)
        }
 }
 
-static int pbx_builtin_gotoif(struct ast_channel *chan, const char *data)
-{
-       char *condition, *branch1, *branch2, *branch;
-       char *stringp;
-
-       if (ast_strlen_zero(data)) {
-               ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
-               return 0;
-       }
-
-       stringp = ast_strdupa(data);
-       condition = strsep(&stringp,"?");
-       branch1 = strsep(&stringp,":");
-       branch2 = strsep(&stringp,"");
-       branch = pbx_checkcondition(condition) ? branch1 : branch2;
-
-       if (ast_strlen_zero(branch)) {
-               ast_debug(1, "Not taking any branch\n");
-               return 0;
-       }
-
-       return pbx_builtin_goto(chan, branch);
-}
-
-static int pbx_builtin_saynumber(struct ast_channel *chan, const char *data)
-{
-       char tmp[256];
-       char *number = tmp;
-       int number_val;
-       char *options;
-       int res;
-       int interrupt = 0;
-       const char *interrupt_string;
-
-       ast_channel_lock(chan);
-       interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
-       if (ast_true(interrupt_string)) {
-               interrupt = 1;
-       }
-       ast_channel_unlock(chan);
-
-       if (ast_strlen_zero(data)) {
-               ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
-               return -1;
-       }
-       ast_copy_string(tmp, data, sizeof(tmp));
-       strsep(&number, ",");
-
-       if (sscanf(tmp, "%d", &number_val) != 1) {
-               ast_log(LOG_WARNING, "argument '%s' to SayNumber could not be parsed as a number.\n", tmp);
-               return 0;
-       }
-
-       options = strsep(&number, ",");
-       if (options) {
-               if ( strcasecmp(options, "f") && strcasecmp(options, "m") &&
-                       strcasecmp(options, "c") && strcasecmp(options, "n") ) {
-                       ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
-                       return -1;
-               }
-       }
-
-       res = ast_say_number(chan, number_val, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), options);
-
-       if (res < 0) {
-               ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
-       }
-
-       return interrupt ? res : 0;
-}
-
-static int pbx_builtin_saydigits(struct ast_channel *chan, const char *data)
-{
-       int res = 0;
-       int interrupt = 0;
-       const char *interrupt_string;
-
-       ast_channel_lock(chan);
-       interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
-       if (ast_true(interrupt_string)) {
-               interrupt = 1;
-       }
-       ast_channel_unlock(chan);
-
-       if (data) {
-               res = ast_say_digit_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan));
-       }
-
-       return res;
-}
-
-static int pbx_builtin_saycharacters_case(struct ast_channel *chan, const char *data)
-{
-       int res = 0;
-       int sensitivity = 0;
-       char *parse;
-       int interrupt = 0;
-       const char *interrupt_string;
-
-       AST_DECLARE_APP_ARGS(args,
-               AST_APP_ARG(options);
-               AST_APP_ARG(characters);
-       );
-
-       ast_channel_lock(chan);
-       interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
-       if (ast_true(interrupt_string)) {
-               interrupt = 1;
-       }
-       ast_channel_unlock(chan);
-
-       if (ast_strlen_zero(data)) {
-               ast_log(LOG_WARNING, "SayAlphaCase requires two arguments (options, characters)\n");
-               return 0;
-       }
-
-       parse = ast_strdupa(data);
-       AST_STANDARD_APP_ARGS(args, parse);
-
-       if (!args.options || strlen(args.options) != 1) {
-               ast_log(LOG_WARNING, "SayAlphaCase options are mutually exclusive and required\n");
-               return 0;
-       }
-
-       switch (args.options[0]) {
-       case 'a':
-               sensitivity = AST_SAY_CASE_ALL;
-               break;
-       case 'l':
-               sensitivity = AST_SAY_CASE_LOWER;
-               break;
-       case 'n':
-               sensitivity = AST_SAY_CASE_NONE;
-               break;
-       case 'u':
-               sensitivity = AST_SAY_CASE_UPPER;
-               break;
-       default:
-               ast_log(LOG_WARNING, "Invalid option: '%s'\n", args.options);
-               return 0;
-       }
-
-       res = ast_say_character_str(chan, args.characters, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), sensitivity);
-
-       return res;
-}
-
-static int pbx_builtin_saycharacters(struct ast_channel *chan, const char *data)
-{
-       int res = 0;
-       int interrupt = 0;
-       const char *interrupt_string;
-
-       ast_channel_lock(chan);
-       interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
-       if (ast_true(interrupt_string)) {
-               interrupt = 1;
-       }
-       ast_channel_unlock(chan);
-
-       if (data) {
-               res = ast_say_character_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), AST_SAY_CASE_NONE);
-       }
-
-       return res;
-}
-
-static int pbx_builtin_sayphonetic(struct ast_channel *chan, const char *data)
-{
-       int res = 0;
-       int interrupt = 0;
-       const char *interrupt_string;
-
-       ast_channel_lock(chan);
-       interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
-       if (ast_true(interrupt_string)) {
-               interrupt = 1;
-       }
-       ast_channel_unlock(chan);
-
-       if (data)
-               res = ast_say_phonetic_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan));
-       return res;
-}
-
 static void presence_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
 {
        struct ast_presence_state_message *presence_state;
@@ -12315,15 +10862,9 @@ static int action_extensionstatelist(struct mansession *s, const struct message
  */
 static void unload_pbx(void)
 {
-       int x;
-
        presence_state_sub = stasis_unsubscribe_and_join(presence_state_sub);
        device_state_sub = stasis_unsubscribe_and_join(device_state_sub);
 
-       /* Unregister builtin applications */
-       for (x = 0; x < ARRAY_LEN(builtins); x++) {
-               ast_unregister_application(builtins[x].name);
-       }
        ast_manager_unregister("ShowDialPlan");
        ast_manager_unregister("ExtensionStateList");
        ast_cli_unregister_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
@@ -12335,27 +10876,18 @@ static void unload_pbx(void)
 int load_pbx(void)
 {
        int res = 0;
-       int x;
 
        ast_register_cleanup(unload_pbx);
 
        /* Initialize the PBX */
        ast_verb(1, "Asterisk PBX Core Initializing\n");
 
-       ast_verb(2, "Registering builtin applications and functions:\n");
+       ast_verb(2, "Registering builtin functions:\n");
        ast_cli_register_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
        ast_data_register_multiple_core(pbx_data_providers, ARRAY_LEN(pbx_data_providers));
        __ast_custom_function_register(&exception_function, NULL);
        __ast_custom_function_register(&testtime_function, NULL);
 
-       /* Register builtin applications */
-       for (x = 0; x < ARRAY_LEN(builtins); x++) {
-               if (ast_register_application2(builtins[x].name, builtins[x].execute, NULL, NULL, NULL)) {
-                       ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
-                       return -1;
-               }
-       }
-
        /* Register manager application */
        res |= ast_manager_register_xml_core("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan);
        res |= ast_manager_register_xml_core("ExtensionStateList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstatelist);
diff --git a/main/pbx_builtins.c b/main/pbx_builtins.c
new file mode 100644 (file)
index 0000000..8d9f6b0
--- /dev/null
@@ -0,0 +1,1500 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2015 Fairview 5 Engineering, LLC
+ *
+ * George Joseph <george.joseph@fairview5.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.
+ */
+
+/*! \file
+ *
+ * \brief Core PBX builtin routines.
+ *
+ * \author George Joseph <george.joseph@fairview5.com>
+ */
+
+/*** MODULEINFO
+       <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_REGISTER_FILE()
+
+#include "asterisk/_private.h"
+#include "asterisk/pbx.h"
+#include "asterisk/causes.h"
+#include "asterisk/indications.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/say.h"
+#include "asterisk/app.h"
+#include "asterisk/module.h"
+#include "pbx_private.h"
+
+ /*** DOCUMENTATION
+       <application name="Answer" language="en_US">
+               <synopsis>
+                       Answer a channel if ringing.
+               </synopsis>
+               <syntax>
+                       <parameter name="delay">
+                               <para>Asterisk will wait this number of milliseconds before returning to
+                               the dialplan after answering the call.</para>
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>If the call has not been answered, this application will
+                       answer it. Otherwise, it has no effect on the call.</para>
+               </description>
+               <see-also>
+                       <ref type="application">Hangup</ref>
+               </see-also>
+       </application>
+       <application name="BackGround" language="en_US">
+               <synopsis>
+                       Play an audio file while waiting for digits of an extension to go to.
+               </synopsis>
+               <syntax>
+                       <parameter name="filenames" required="true" argsep="&amp;">
+                               <argument name="filename1" required="true" />
+                               <argument name="filename2" multiple="true" />
+                       </parameter>
+                       <parameter name="options">
+                               <optionlist>
+                                       <option name="s">
+                                               <para>Causes the playback of the message to be skipped
+                                               if the channel is not in the <literal>up</literal> state (i.e. it
+                                               hasn't been answered yet). If this happens, the
+                                               application will return immediately.</para>
+                                       </option>
+                                       <option name="n">
+                                               <para>Don't answer the channel before playing the files.</para>
+                                       </option>
+                                       <option name="m">
+                                               <para>Only break if a digit hit matches a one digit
+                                               extension in the destination context.</para>
+                                       </option>
+                               </optionlist>
+                       </parameter>
+                       <parameter name="langoverride">
+                               <para>Explicitly specifies which language to attempt to use for the requested sound files.</para>
+                       </parameter>
+                       <parameter name="context">
+                               <para>This is the dialplan context that this application will use when exiting
+                               to a dialed extension.</para>
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>This application will play the given list of files <emphasis>(do not put extension)</emphasis>
+                       while waiting for an extension to be dialed by the calling channel. To continue waiting
+                       for digits after this application has finished playing files, the <literal>WaitExten</literal>
+                       application should be used.</para>
+                       <para>If one of the requested sound files does not exist, call processing will be terminated.</para>
+                       <para>This application sets the following channel variable upon completion:</para>
+                       <variablelist>
+                               <variable name="BACKGROUNDSTATUS">
+                                       <para>The status of the background attempt as a text string.</para>
+                                       <value name="SUCCESS" />
+                                       <value name="FAILED" />
+                               </variable>
+                       </variablelist>
+               </description>
+               <see-also>
+                       <ref type="application">ControlPlayback</ref>
+                       <ref type="application">WaitExten</ref>
+                       <ref type="application">BackgroundDetect</ref>
+                       <ref type="function">TIMEOUT</ref>
+               </see-also>
+       </application>
+       <application name="Busy" language="en_US">
+               <synopsis>
+                       Indicate the Busy condition.
+               </synopsis>
+               <syntax>
+                       <parameter name="timeout">
+                               <para>If specified, the calling channel will be hung up after the specified number of seconds.
+                               Otherwise, this application will wait until the calling channel hangs up.</para>
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>This application will indicate the busy condition to the calling channel.</para>
+               </description>
+               <see-also>
+                       <ref type="application">Congestion</ref>
+                       <ref type="application">Progress</ref>
+                       <ref type="application">Playtones</ref>
+                       <ref type="application">Hangup</ref>
+               </see-also>
+       </application>
+       <application name="Congestion" language="en_US">
+               <synopsis>
+                       Indicate the Congestion condition.
+               </synopsis>
+               <syntax>
+                       <parameter name="timeout">
+                               <para>If specified, the calling channel will be hung up after the specified number of seconds.
+                               Otherwise, this application will wait until the calling channel hangs up.</para>
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>This application will indicate the congestion condition to the calling channel.</para>
+               </description>
+               <see-also>
+                       <ref type="application">Busy</ref>
+                       <ref type="application">Progress</ref>
+                       <ref type="application">Playtones</ref>
+                       <ref type="application">Hangup</ref>
+               </see-also>
+       </application>
+       <application name="ExecIfTime" language="en_US">
+               <synopsis>
+                       Conditional application execution based on the current time.
+               </synopsis>
+               <syntax argsep="?">
+                       <parameter name="day_condition" required="true">
+                               <argument name="times" required="true" />
+                               <argument name="weekdays" required="true" />
+                               <argument name="mdays" required="true" />
+                               <argument name="months" required="true" />
+                               <argument name="timezone" required="false" />
+                       </parameter>
+                       <parameter name="appname" required="true" hasparams="optional">
+                               <argument name="appargs" required="true" />
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>This application will execute the specified dialplan application, with optional
+                       arguments, if the current time matches the given time specification.</para>
+               </description>
+               <see-also>
+                       <ref type="application">Exec</ref>
+                       <ref type="application">ExecIf</ref>
+                       <ref type="application">TryExec</ref>
+                       <ref type="application">GotoIfTime</ref>
+               </see-also>
+       </application>
+       <application name="Goto" language="en_US">
+               <synopsis>
+                       Jump to a particular priority, extension, or context.
+               </synopsis>
+               <syntax>
+                       <parameter name="context" />
+                       <parameter name="extensions" />
+                       <parameter name="priority" required="true" />
+               </syntax>
+               <description>
+                       <para>This application will set the current context, extension, and priority in the channel structure.
+                       After it completes, the pbx engine will continue dialplan execution at the specified location.
+                       If no specific <replaceable>extension</replaceable>, or <replaceable>extension</replaceable> and
+                       <replaceable>context</replaceable>, are specified, then this application will
+                       just set the specified <replaceable>priority</replaceable> of the current extension.</para>
+                       <para>At least a <replaceable>priority</replaceable> is required as an argument, or the goto will
+                       return a <literal>-1</literal>, and the channel and call will be terminated.</para>
+                       <para>If the location that is put into the channel information is bogus, and asterisk cannot
+                       find that location in the dialplan, then the execution engine will try to find and execute the code in
+                       the <literal>i</literal> (invalid) extension in the current context. If that does not exist, it will try to execute the
+                       <literal>h</literal> extension. If neither the <literal>h</literal> nor <literal>i</literal> extensions
+                       have been defined, the channel is hung up, and the execution of instructions on the channel is terminated.
+                       What this means is that, for example, you specify a context that does not exist, then
+                       it will not be possible to find the <literal>h</literal> or <literal>i</literal> extensions,
+                       and the call will terminate!</para>
+               </description>
+               <see-also>
+                       <ref type="application">GotoIf</ref>
+                       <ref type="application">GotoIfTime</ref>
+                       <ref type="application">Gosub</ref>
+                       <ref type="application">Macro</ref>
+               </see-also>
+       </application>
+       <application name="GotoIf" language="en_US">
+               <synopsis>
+                       Conditional goto.
+               </synopsis>
+               <syntax argsep="?">
+                       <parameter name="condition" required="true" />
+                       <parameter name="destination" required="true" argsep=":">
+                               <argument name="labeliftrue">
+                                       <para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.
+                                       Takes the form similar to Goto() of [[context,]extension,]priority.</para>
+                               </argument>
+                               <argument name="labeliffalse">
+                                       <para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.
+                                       Takes the form similar to Goto() of [[context,]extension,]priority.</para>
+                               </argument>
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>This application will set the current context, extension, and priority in the channel structure
+                       based on the evaluation of the given condition. After this application completes, the
+                       pbx engine will continue dialplan execution at the specified location in the dialplan.
+                       The labels are specified with the same syntax as used within the Goto application.
+                       If the label chosen by the condition is omitted, no jump is performed, and the execution passes to the
+                       next instruction. If the target location is bogus, and does not exist, the execution engine will try
+                       to find and execute the code in the <literal>i</literal> (invalid) extension in the current context.
+                       If that does not exist, it will try to execute the <literal>h</literal> extension.
+                       If neither the <literal>h</literal> nor <literal>i</literal> extensions have been defined,
+                       the channel is hung up, and the execution of instructions on the channel is terminated.
+                       Remember that this command can set the current context, and if the context specified
+                       does not exist, then it will not be able to find any 'h' or 'i' extensions there, and
+                       the channel and call will both be terminated!.</para>
+               </description>
+               <see-also>
+                       <ref type="application">Goto</ref>
+                       <ref type="application">GotoIfTime</ref>
+                       <ref type="application">GosubIf</ref>
+                       <ref type="application">MacroIf</ref>
+               </see-also>
+       </application>
+       <application name="GotoIfTime" language="en_US">
+               <synopsis>
+                       Conditional Goto based on the current time.
+               </synopsis>
+               <syntax argsep="?">
+                       <parameter name="condition" required="true">
+                               <argument name="times" required="true" />
+                               <argument name="weekdays" required="true" />
+                               <argument name="mdays" required="true" />
+                               <argument name="months" required="true" />
+                               <argument name="timezone" required="false" />
+                       </parameter>
+                       <parameter name="destination" required="true" argsep=":">
+                               <argument name="labeliftrue">
+                                       <para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.
+                                       Takes the form similar to Goto() of [[context,]extension,]priority.</para>
+                               </argument>
+                               <argument name="labeliffalse">
+                                       <para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.
+                                       Takes the form similar to Goto() of [[context,]extension,]priority.</para>
+                               </argument>
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>This application will set the context, extension, and priority in the channel structure
+                       based on the evaluation of the given time specification. After this application completes,
+                       the pbx engine will continue dialplan execution at the specified location in the dialplan.
+                       If the current time is within the given time specification, the channel will continue at
+                       <replaceable>labeliftrue</replaceable>. Otherwise the channel will continue at <replaceable>labeliffalse</replaceable>.
+                       If the label chosen by the condition is omitted, no jump is performed, and execution passes to the next
+                       instruction. If the target jump location is bogus, the same actions would be taken as for <literal>Goto</literal>.
+                       Further information on the time specification can be found in examples
+                       illustrating how to do time-based context includes in the dialplan.</para>
+               </description>
+               <see-also>
+                       <ref type="application">GotoIf</ref>
+                       <ref type="application">Goto</ref>
+                       <ref type="function">IFTIME</ref>
+                       <ref type="function">TESTTIME</ref>
+               </see-also>
+       </application>
+       <application name="ImportVar" language="en_US">
+               <synopsis>
+                       Import a variable from a channel into a new variable.
+               </synopsis>
+               <syntax argsep="=">
+                       <parameter name="newvar" required="true" />
+                       <parameter name="vardata" required="true">
+                               <argument name="channelname" required="true" />
+                               <argument name="variable" required="true" />
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>This application imports a <replaceable>variable</replaceable> from the specified
+                       <replaceable>channel</replaceable> (as opposed to the current one) and stores it as a variable
+                       (<replaceable>newvar</replaceable>) in the current channel (the channel that is calling this
+                       application). Variables created by this application have the same inheritance properties as those
+                       created with the <literal>Set</literal> application.</para>
+               </description>
+               <see-also>
+                       <ref type="application">Set</ref>
+               </see-also>
+       </application>
+       <application name="Hangup" language="en_US">
+               <synopsis>
+                       Hang up the calling channel.
+               </synopsis>
+               <syntax>
+                       <parameter name="causecode">
+                               <para>If a <replaceable>causecode</replaceable> is given the channel's
+                               hangup cause will be set to the given value.</para>
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>This application will hang up the calling channel.</para>
+               </description>
+               <see-also>
+                       <ref type="application">Answer</ref>
+                       <ref type="application">Busy</ref>
+                       <ref type="application">Congestion</ref>
+               </see-also>
+       </application>
+       <application name="Incomplete" language="en_US">
+               <synopsis>
+                       Returns AST_PBX_INCOMPLETE value.
+               </synopsis>
+               <syntax>
+                       <parameter name="n">
+                               <para>If specified, then Incomplete will not attempt to answer the channel first.</para>
+                               <note><para>Most channel types need to be in Answer state in order to receive DTMF.</para></note>
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>Signals the PBX routines that the previous matched extension is incomplete
+                       and that further input should be allowed before matching can be considered
+                       to be complete.  Can be used within a pattern match when certain criteria warrants
+                       a longer match.</para>
+               </description>
+       </application>
+       <application name="NoOp" language="en_US">
+               <synopsis>
+                       Do Nothing (No Operation).
+               </synopsis>
+               <syntax>
+                       <parameter name="text">
+                               <para>Any text provided can be viewed at the Asterisk CLI.</para>
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>This application does nothing. However, it is useful for debugging purposes.</para>
+                       <para>This method can be used to see the evaluations of variables or functions without having any effect.</para>
+               </description>
+               <see-also>
+                       <ref type="application">Verbose</ref>
+                       <ref type="application">Log</ref>
+               </see-also>
+       </application>
+       <application name="Proceeding" language="en_US">
+               <synopsis>
+                       Indicate proceeding.
+               </synopsis>
+               <syntax />
+               <description>
+                       <para>This application will request that a proceeding message be provided to the calling channel.</para>
+               </description>
+       </application>
+       <application name="Progress" language="en_US">
+               <synopsis>
+                       Indicate progress.
+               </synopsis>
+               <syntax />
+               <description>
+                       <para>This application will request that in-band progress information be provided to the calling channel.</para>
+               </description>
+               <see-also>
+                       <ref type="application">Busy</ref>
+                       <ref type="application">Congestion</ref>
+                       <ref type="application">Ringing</ref>
+                       <ref type="application">Playtones</ref>
+               </see-also>
+       </application>
+       <application name="RaiseException" language="en_US">
+               <synopsis>
+                       Handle an exceptional condition.
+               </synopsis>
+               <syntax>
+                       <parameter name="reason" required="true" />
+               </syntax>
+               <description>
+                       <para>This application will jump to the <literal>e</literal> extension in the current context, setting the
+                       dialplan function EXCEPTION(). If the <literal>e</literal> extension does not exist, the call will hangup.</para>
+               </description>
+               <see-also>
+                       <ref type="function">Exception</ref>
+               </see-also>
+       </application>
+       <application name="Ringing" language="en_US">
+               <synopsis>
+                       Indicate ringing tone.
+               </synopsis>
+               <syntax />
+               <description>
+                       <para>This application will request that the channel indicate a ringing tone to the user.</para>
+               </description>
+               <see-also>
+                       <ref type="application">Busy</ref>
+                       <ref type="application">Congestion</ref>
+                       <ref type="application">Progress</ref>
+                       <ref type="application">Playtones</ref>
+               </see-also>
+       </application>
+       <application name="SayAlpha" language="en_US">
+               <synopsis>
+                       Say Alpha.
+               </synopsis>
+               <syntax>
+                       <parameter name="string" required="true" />
+               </syntax>
+               <description>
+                       <para>This application will play the sounds that correspond to the letters
+                       of the given <replaceable>string</replaceable>. If the channel variable
+                       <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive),
+                       then this application will react to DTMF in the same way as
+                       <literal>Background</literal>.</para>
+               </description>
+               <see-also>
+                       <ref type="application">SayDigits</ref>
+                       <ref type="application">SayNumber</ref>
+                       <ref type="application">SayPhonetic</ref>
+                       <ref type="function">CHANNEL</ref>
+               </see-also>
+       </application>
+       <application name="SayAlphaCase" language="en_US">
+               <synopsis>
+                       Say Alpha.
+               </synopsis>
+               <syntax>
+                       <parameter name="casetype" required="true" >
+                               <enumlist>
+                                       <enum name="a">
+                                               <para>Case sensitive (all) pronunciation.
+                                               (Ex: SayAlphaCase(a,aBc); - lowercase a uppercase b lowercase c).</para>
+                                       </enum>
+                                       <enum name="l">
+                                               <para>Case sensitive (lower) pronunciation.
+                                               (Ex: SayAlphaCase(l,aBc); - lowercase a b lowercase c).</para>
+                                       </enum>
+                                       <enum name="n">
+                                               <para>Case insensitive pronunciation. Equivalent to SayAlpha.
+                                               (Ex: SayAlphaCase(n,aBc) - a b c).</para>
+                                       </enum>
+                                       <enum name="u">
+                                               <para>Case sensitive (upper) pronunciation.
+                                               (Ex: SayAlphaCase(u,aBc); - a uppercase b c).</para>
+                                       </enum>
+                               </enumlist>
+                       </parameter>
+                       <parameter name="string" required="true" />
+               </syntax>
+               <description>
+                       <para>This application will play the sounds that correspond to the letters of the
+                       given <replaceable>string</replaceable>.  Optionally, a <replaceable>casetype</replaceable> may be
+                       specified.  This will be used for case-insensitive or case-sensitive pronunciations. If the channel
+                       variable <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
+                       application will react to DTMF in the same way as <literal>Background</literal>.</para>
+               </description>
+               <see-also>
+                       <ref type="application">SayDigits</ref>
+                       <ref type="application">SayNumber</ref>
+                       <ref type="application">SayPhonetic</ref>
+                       <ref type="application">SayAlpha</ref>
+                       <ref type="function">CHANNEL</ref>
+               </see-also>
+       </application>
+       <application name="SayDigits" language="en_US">
+               <synopsis>
+                       Say Digits.
+               </synopsis>
+               <syntax>
+                       <parameter name="digits" required="true" />
+               </syntax>
+               <description>
+                       <para>This application will play the sounds that correspond to the digits of
+                       the given number. This will use the language that is currently set for the channel.
+                       If the channel variable <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true'
+                       (case insensitive), then this application will react to DTMF in the same way as
+                       <literal>Background</literal>.</para>
+               </description>
+               <see-also>
+                       <ref type="application">SayAlpha</ref>
+                       <ref type="application">SayNumber</ref>
+                       <ref type="application">SayPhonetic</ref>
+                       <ref type="function">CHANNEL</ref>
+               </see-also>
+       </application>
+       <application name="SayNumber" language="en_US">
+               <synopsis>
+                       Say Number.
+               </synopsis>
+               <syntax>
+                       <parameter name="digits" required="true" />
+                       <parameter name="gender" />
+               </syntax>
+               <description>
+                       <para>This application will play the sounds that correspond to the given
+                       <replaceable>digits</replaceable>. Optionally, a <replaceable>gender</replaceable> may be
+                       specified. This will use the language that is currently set for the channel. See the CHANNEL()
+                       function for more information on setting the language for the channel. If the channel variable
+                       <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
+                       application will react to DTMF in the same way as <literal>Background</literal>.</para>
+               </description>
+               <see-also>
+                       <ref type="application">SayAlpha</ref>
+                       <ref type="application">SayDigits</ref>
+                       <ref type="application">SayPhonetic</ref>
+                       <ref type="function">CHANNEL</ref>
+               </see-also>
+       </application>
+       <application name="SayPhonetic" language="en_US">
+               <synopsis>
+                       Say Phonetic.
+               </synopsis>
+               <syntax>
+                       <parameter name="string" required="true" />
+               </syntax>
+               <description>
+                       <para>This application will play the sounds from the phonetic alphabet that correspond to the
+                       letters in the given <replaceable>string</replaceable>. If the channel variable
+                       <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
+                       application will react to DTMF in the same way as <literal>Background</literal>.</para>
+               </description>
+               <see-also>
+                       <ref type="application">SayAlpha</ref>
+                       <ref type="application">SayDigits</ref>
+                       <ref type="application">SayNumber</ref>
+               </see-also>
+       </application>
+       <application name="Set" language="en_US">
+               <synopsis>
+                       Set channel variable or function value.
+               </synopsis>
+               <syntax argsep="=">
+                       <parameter name="name" required="true" />
+                       <parameter name="value" required="true" />
+               </syntax>
+               <description>
+                       <para>This function can be used to set the value of channel variables or dialplan functions.
+                       When setting variables, if the variable name is prefixed with <literal>_</literal>,
+                       the variable will be inherited into channels created from the current channel.
+                       If the variable name is prefixed with <literal>__</literal>, the variable will be
+                       inherited into channels created from the current channel and all children channels.</para>
+                       <note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have
+                       a <literal>[compat]</literal> category, and you have <literal>app_set = 1.4</literal> under that, then
+                       the behavior of this app changes, and strips surrounding quotes from the right hand side as
+                       it did previously in 1.4.
+                       The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar)
+                       were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly
+                       protect separators and quotes in various database access strings has been greatly
+                       reduced by these changes.</para></note>
+               </description>
+               <see-also>
+                       <ref type="application">MSet</ref>
+                       <ref type="function">GLOBAL</ref>
+                       <ref type="function">SET</ref>
+                       <ref type="function">ENV</ref>
+               </see-also>
+       </application>
+       <application name="MSet" language="en_US">
+               <synopsis>
+                       Set channel variable(s) or function value(s).
+               </synopsis>
+               <syntax>
+                       <parameter name="set1" required="true" argsep="=">
+                               <argument name="name1" required="true" />
+                               <argument name="value1" required="true" />
+                       </parameter>
+                       <parameter name="set2" multiple="true" argsep="=">
+                               <argument name="name2" required="true" />
+                               <argument name="value2" required="true" />
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>This function can be used to set the value of channel variables or dialplan functions.
+                       When setting variables, if the variable name is prefixed with <literal>_</literal>,
+                       the variable will be inherited into channels created from the current channel
+                       If the variable name is prefixed with <literal>__</literal>, the variable will be
+                       inherited into channels created from the current channel and all children channels.
+                       MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus
+                       prone to doing things that you may not expect. For example, it strips surrounding
+                       double-quotes from the right-hand side (value). If you need to put a separator
+                       character (comma or vert-bar), you will need to escape them by inserting a backslash
+                       before them. Avoid its use if possible.</para>
+               </description>
+               <see-also>
+                       <ref type="application">Set</ref>
+               </see-also>
+       </application>
+       <application name="SetAMAFlags" language="en_US">
+               <synopsis>
+                       Set the AMA Flags.
+               </synopsis>
+               <syntax>
+                       <parameter name="flag" />
+               </syntax>
+               <description>
+                       <para>This application will set the channel's AMA Flags for billing purposes.</para>
+                       <warning><para>This application is deprecated. Please use the CHANNEL function instead.</para></warning>
+               </description>
+               <see-also>
+                       <ref type="function">CDR</ref>
+                       <ref type="function">CHANNEL</ref>
+               </see-also>
+       </application>
+       <application name="Wait" language="en_US">
+               <synopsis>
+                       Waits for some time.
+               </synopsis>
+               <syntax>
+                       <parameter name="seconds" required="true">
+                               <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
+                               application to wait for 1.5 seconds.</para>
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>This application waits for a specified number of <replaceable>seconds</replaceable>.</para>
+               </description>
+       </application>
+       <application name="WaitExten" language="en_US">
+               <synopsis>
+                       Waits for an extension to be entered.
+               </synopsis>
+               <syntax>
+                       <parameter name="seconds">
+                               <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
+                               application to wait for 1.5 seconds.</para>
+                       </parameter>
+                       <parameter name="options">
+                               <optionlist>
+                                       <option name="m">
+                                               <para>Provide music on hold to the caller while waiting for an extension.</para>
+                                               <argument name="x">
+                                                       <para>Specify the class for music on hold. <emphasis>CHANNEL(musicclass) will
+                                                       be used instead if set</emphasis></para>
+                                               </argument>
+                                       </option>
+                               </optionlist>
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>This application waits for the user to enter a new extension for a specified number
+                       of <replaceable>seconds</replaceable>.</para>
+                       <xi:include xpointer="xpointer(/docs/application[@name='Macro']/description/warning[2])" />
+               </description>
+               <see-also>
+                       <ref type="application">Background</ref>
+                       <ref type="function">TIMEOUT</ref>
+               </see-also>
+       </application>
+ ***/
+
+#define BACKGROUND_SKIP                (1 << 0)
+#define BACKGROUND_NOANSWER    (1 << 1)
+#define BACKGROUND_MATCHEXTEN  (1 << 2)
+#define BACKGROUND_PLAYBACK    (1 << 3)
+
+AST_APP_OPTIONS(background_opts, {
+       AST_APP_OPTION('s', BACKGROUND_SKIP),
+       AST_APP_OPTION('n', BACKGROUND_NOANSWER),
+       AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
+       AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
+});
+
+#define WAITEXTEN_MOH          (1 << 0)
+#define WAITEXTEN_DIALTONE     (1 << 1)
+
+AST_APP_OPTIONS(waitexten_opts, {
+       AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
+       AST_APP_OPTION_ARG('d', WAITEXTEN_DIALTONE, 0),
+});
+
+int pbx_builtin_raise_exception(struct ast_channel *chan, const char *reason)
+{
+       /* Priority will become 1, next time through the AUTOLOOP */
+       return raise_exception(chan, reason, 0);
+}
+
+/*!
+ * \ingroup applications
+ */
+static int pbx_builtin_proceeding(struct ast_channel *chan, const char *data)
+{
+       ast_indicate(chan, AST_CONTROL_PROCEEDING);
+       return 0;
+}
+
+/*!
+ * \ingroup applications
+ */
+static int pbx_builtin_progress(struct ast_channel *chan, const char *data)
+{
+       ast_indicate(chan, AST_CONTROL_PROGRESS);
+       return 0;
+}
+
+/*!
+ * \ingroup applications
+ */
+static int pbx_builtin_ringing(struct ast_channel *chan, const char *data)
+{
+       ast_indicate(chan, AST_CONTROL_RINGING);
+       return 0;
+}
+
+/*!
+ * \ingroup applications
+ */
+int indicate_busy(struct ast_channel *chan, const char *data)
+{
+       ast_indicate(chan, AST_CONTROL_BUSY);
+       /* Don't change state of an UP channel, just indicate
+          busy in audio */
+       ast_channel_lock(chan);
+       if (ast_channel_state(chan) != AST_STATE_UP) {
+               ast_channel_hangupcause_set(chan, AST_CAUSE_BUSY);
+               ast_setstate(chan, AST_STATE_BUSY);
+       }
+       ast_channel_unlock(chan);
+       wait_for_hangup(chan, data);
+       return -1;
+}
+
+/*!
+ * \ingroup applications
+ */
+int indicate_congestion(struct ast_channel *chan, const char *data)
+{
+       ast_indicate(chan, AST_CONTROL_CONGESTION);
+       /* Don't change state of an UP channel, just indicate
+          congestion in audio */
+       ast_channel_lock(chan);
+       if (ast_channel_state(chan) != AST_STATE_UP) {
+               ast_channel_hangupcause_set(chan, AST_CAUSE_CONGESTION);
+               ast_setstate(chan, AST_STATE_BUSY);
+       }
+       ast_channel_unlock(chan);
+       wait_for_hangup(chan, data);
+       return -1;
+}
+
+/*!
+ * \ingroup applications
+ */
+static int pbx_builtin_answer(struct ast_channel *chan, const char *data)
+{
+       int delay = 0;
+       char *parse;
+       AST_DECLARE_APP_ARGS(args,
+               AST_APP_ARG(delay);
+               AST_APP_ARG(answer_cdr);
+       );
+
+       if (ast_strlen_zero(data)) {
+               return __ast_answer(chan, 0);
+       }
+
+       parse = ast_strdupa(data);
+
+       AST_STANDARD_APP_ARGS(args, parse);
+
+       if (!ast_strlen_zero(args.delay) && (ast_channel_state(chan) != AST_STATE_UP))
+               delay = atoi(data);
+
+       if (delay < 0) {
+               delay = 0;
+       }
+
+       if (!ast_strlen_zero(args.answer_cdr) && !strcasecmp(args.answer_cdr, "nocdr")) {
+               ast_log(AST_LOG_WARNING, "The nocdr option for the Answer application has been removed and is no longer supported.\n");
+       }
+
+       return __ast_answer(chan, delay);
+}
+
+static int pbx_builtin_incomplete(struct ast_channel *chan, const char *data)
+{
+       const char *options = data;
+       int answer = 1;
+
+       /* Some channels can receive DTMF in unanswered state; some cannot */
+       if (!ast_strlen_zero(options) && strchr(options, 'n')) {
+               answer = 0;
+       }
+
+       /* If the channel is hungup, stop waiting */
+       if (ast_check_hangup(chan)) {
+               return -1;
+       } else if (ast_channel_state(chan) != AST_STATE_UP && answer) {
+               __ast_answer(chan, 0);
+       }
+
+       ast_indicate(chan, AST_CONTROL_INCOMPLETE);
+
+       return AST_PBX_INCOMPLETE;
+}
+
+/*!
+ * \ingroup applications
+ */
+static int pbx_builtin_setamaflags(struct ast_channel *chan, const char *data)
+{
+       ast_log(AST_LOG_WARNING, "The SetAMAFlags application is deprecated. Please use the CHANNEL function instead.\n");
+
+       if (ast_strlen_zero(data)) {
+               ast_log(AST_LOG_WARNING, "No parameter passed to SetAMAFlags\n");
+               return 0;
+       }
+       /* Copy the AMA Flags as specified */
+       ast_channel_lock(chan);
+       if (isdigit(data[0])) {
+               int amaflags;
+               if (sscanf(data, "%30d", &amaflags) != 1) {
+                       ast_log(AST_LOG_WARNING, "Unable to set AMA flags on channel %s\n", ast_channel_name(chan));
+                       ast_channel_unlock(chan);
+                       return 0;
+               }
+               ast_channel_amaflags_set(chan, amaflags);
+       } else {
+               ast_channel_amaflags_set(chan, ast_channel_string2amaflag(data));
+       }
+       ast_channel_unlock(chan);
+       return 0;
+}
+
+/*!
+ * \ingroup applications
+ */
+static int pbx_builtin_hangup(struct ast_channel *chan, const char *data)
+{
+       int cause;
+
+       ast_set_hangupsource(chan, "dialplan/builtin", 0);
+
+       if (!ast_strlen_zero(data)) {
+               cause = ast_str2cause(data);
+               if (cause <= 0) {
+                       if (sscanf(data, "%30d", &cause) != 1 || cause <= 0) {
+                               ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", data);
+                               cause = 0;
+                       }
+               }
+       } else {
+               cause = 0;
+       }
+
+       ast_channel_lock(chan);
+       if (cause <= 0) {
+               cause = ast_channel_hangupcause(chan);
+               if (cause <= 0) {
+                       cause = AST_CAUSE_NORMAL_CLEARING;
+               }
+       }
+       ast_channel_hangupcause_set(chan, cause);
+       ast_softhangup_nolock(chan, AST_SOFTHANGUP_EXPLICIT);
+       ast_channel_unlock(chan);
+
+       return -1;
+}
+
+/*! Goto
+ * \ingroup applications
+ */
+static int pbx_builtin_goto(struct ast_channel *chan, const char *data)
+{
+       int res = ast_parseable_goto(chan, data);
+       if (!res)
+               ast_verb(3, "Goto (%s,%s,%d)\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan) + 1);
+       return res;
+}
+
+/*!
+ * \ingroup applications
+ */
+static int pbx_builtin_gotoiftime(struct ast_channel *chan, const char *data)
+{
+       char *s, *ts, *branch1, *branch2, *branch;
+       struct ast_timing timing;
+       const char *ctime;
+       struct timeval tv = ast_tvnow();
+       long timesecs;
+
+       if (!chan) {
+               ast_log(LOG_WARNING, "GotoIfTime requires a channel on which to operate\n");
+               return -1;
+       }
+
+       if (ast_strlen_zero(data)) {
+               ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n  <time range>,<days of week>,<days of month>,<months>[,<timezone>]?'labeliftrue':'labeliffalse'\n");
+               return -1;
+       }
+
+       ts = s = ast_strdupa(data);
+
+       ast_channel_lock(chan);
+       if ((ctime = pbx_builtin_getvar_helper(chan, "TESTTIME")) && sscanf(ctime, "%ld", &timesecs) == 1) {
+               tv.tv_sec = timesecs;
+       } else if (ctime) {
+               ast_log(LOG_WARNING, "Using current time to evaluate\n");
+               /* Reset when unparseable */
+               pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
+       }
+       ast_channel_unlock(chan);
+
+       /* Separate the Goto path */
+       strsep(&ts, "?");
+       branch1 = strsep(&ts,":");
+       branch2 = strsep(&ts,"");
+
+       /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
+       if (ast_build_timing(&timing, s) && ast_check_timing2(&timing, tv)) {
+               branch = branch1;
+       } else {
+               branch = branch2;
+       }
+       ast_destroy_timing(&timing);
+
+       if (ast_strlen_zero(branch)) {
+               ast_debug(1, "Not taking any branch\n");
+               return 0;
+       }
+
+       return pbx_builtin_goto(chan, branch);
+}
+
+/*!
+ * \ingroup applications
+ */
+static int pbx_builtin_execiftime(struct ast_channel *chan, const char *data)
+{
+       char *s, *appname;
+       struct ast_timing timing;
+       struct ast_app *app;
+       static const char * const usage = "ExecIfTime requires an argument:\n  <time range>,<days of week>,<days of month>,<months>[,<timezone>]?<appname>[(<appargs>)]";
+
+       if (ast_strlen_zero(data)) {
+               ast_log(LOG_WARNING, "%s\n", usage);
+               return -1;
+       }
+
+       appname = ast_strdupa(data);
+
+       s = strsep(&appname, "?");      /* Separate the timerange and application name/data */
+       if (!appname) { /* missing application */
+               ast_log(LOG_WARNING, "%s\n", usage);
+               return -1;
+       }
+
+       if (!ast_build_timing(&timing, s)) {
+               ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
+               ast_destroy_timing(&timing);
+               return -1;
+       }
+
+       if (!ast_check_timing(&timing)) { /* outside the valid time window, just return */
+               ast_destroy_timing(&timing);
+               return 0;
+       }
+       ast_destroy_timing(&timing);
+
+       /* now split appname(appargs) */
+       if ((s = strchr(appname, '('))) {
+               char *e;
+               *s++ = '\0';
+               if ((e = strrchr(s, ')')))
+                       *e = '\0';
+               else
+                       ast_log(LOG_WARNING, "Failed to find closing parenthesis\n");
+       }
+
+
+       if ((app = pbx_findapp(appname))) {
+               return pbx_exec(chan, app, S_OR(s, ""));
+       } else {
+               ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
+               return -1;
+       }
+}
+
+/*!
+ * \ingroup applications
+ */
+static int pbx_builtin_wait(struct ast_channel *chan, const char *data)
+{
+       int ms;
+
+       /* Wait for "n" seconds */
+       if (!ast_app_parse_timelen(data, &ms, TIMELEN_SECONDS) && ms > 0) {
+               return ast_safe_sleep(chan, ms);
+       }
+       return 0;
+}
+
+/*!
+ * \ingroup applications
+ */
+static int pbx_builtin_waitexten(struct ast_channel *chan, const char *data)
+{
+       int ms, res;
+       struct ast_flags flags = {0};
+       char *opts[1] = { NULL };
+       char *parse;
+       AST_DECLARE_APP_ARGS(args,
+               AST_APP_ARG(timeout);
+               AST_APP_ARG(options);
+       );
+
+       if (!ast_strlen_zero(data)) {
+               parse = ast_strdupa(data);
+               AST_STANDARD_APP_ARGS(args, parse);
+       } else
+               memset(&args, 0, sizeof(args));
+
+       if (args.options)
+               ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
+
+       if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
+               ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n");
+       } else if (ast_test_flag(&flags, WAITEXTEN_MOH)) {
+               ast_indicate_data(chan, AST_CONTROL_HOLD, S_OR(opts[0], NULL),
+                       !ast_strlen_zero(opts[0]) ? strlen(opts[0]) + 1 : 0);
+       } else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE)) {
+               struct ast_tone_zone_sound *ts = ast_get_indication_tone(ast_channel_zone(chan), "dial");
+               if (ts) {
+                       ast_playtones_start(chan, 0, ts->data, 0);
+                       ts = ast_tone_zone_sound_unref(ts);
+               } else {
+                       ast_tonepair_start(chan, 350, 440, 0, 0);
+               }
+       }
+       /* Wait for "n" seconds */
+       if (!ast_app_parse_timelen(args.timeout, &ms, TIMELEN_SECONDS) && ms > 0) {
+               /* Yay! */
+       } else if (ast_channel_pbx(chan)) {
+               ms = ast_channel_pbx(chan)->rtimeoutms;
+       } else {
+               ms = 10000;
+       }
+
+       res = ast_waitfordigit(chan, ms);
+       if (!res) {
+               if (ast_check_hangup(chan)) {
+                       /* Call is hungup for some reason. */
+                       res = -1;
+               } else if (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan) + 1,
+                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
+                       ast_verb(3, "Timeout on %s, continuing...\n", ast_channel_name(chan));
+               } else if (ast_exists_extension(chan, ast_channel_context(chan), "t", 1,
+                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
+                       ast_verb(3, "Timeout on %s, going to 't'\n", ast_channel_name(chan));
+                       set_ext_pri(chan, "t", 0); /* 0 will become 1, next time through the loop */
+               } else if (ast_exists_extension(chan, ast_channel_context(chan), "e", 1,
+                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
+                       raise_exception(chan, "RESPONSETIMEOUT", 0); /* 0 will become 1, next time through the loop */
+               } else {
+                       ast_log(LOG_WARNING, "Timeout but no rule 't' or 'e' in context '%s'\n",
+                               ast_channel_context(chan));
+                       res = -1;
+               }
+       }
+
+       if (ast_test_flag(&flags, WAITEXTEN_MOH))
+               ast_indicate(chan, AST_CONTROL_UNHOLD);
+       else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE))
+               ast_playtones_stop(chan);
+
+       return res;
+}
+
+/*!
+ * \ingroup applications
+ */
+static int pbx_builtin_background(struct ast_channel *chan, const char *data)
+{
+       int res = 0;
+       int mres = 0;
+       struct ast_flags flags = {0};
+       char *parse, exten[2] = "";
+       AST_DECLARE_APP_ARGS(args,
+               AST_APP_ARG(filename);
+               AST_APP_ARG(options);
+               AST_APP_ARG(lang);
+               AST_APP_ARG(context);
+       );
+
+       if (ast_strlen_zero(data)) {
+               ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
+               return -1;
+       }
+
+       parse = ast_strdupa(data);
+
+       AST_STANDARD_APP_ARGS(args, parse);
+
+       if (ast_strlen_zero(args.lang))
+               args.lang = (char *)ast_channel_language(chan); /* XXX this is const */
+
+       if (ast_strlen_zero(args.context)) {
+               const char *context;
+               ast_channel_lock(chan);
+               if ((context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"))) {
+                       args.context = ast_strdupa(context);
+               } else {
+                       args.context = ast_strdupa(ast_channel_context(chan));
+               }
+               ast_channel_unlock(chan);
+       }
+
+       if (args.options) {
+               if (!strcasecmp(args.options, "skip"))
+                       flags.flags = BACKGROUND_SKIP;
+               else if (!strcasecmp(args.options, "noanswer"))
+                       flags.flags = BACKGROUND_NOANSWER;
+               else
+                       ast_app_parse_options(background_opts, &flags, NULL, args.options);
+       }
+
+       /* Answer if need be */
+       if (ast_channel_state(chan) != AST_STATE_UP) {
+               if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
+                       goto done;
+               } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
+                       res = ast_answer(chan);
+               }
+       }
+
+       if (!res) {
+               char *back = ast_strip(args.filename);
+               char *front;
+
+               ast_stopstream(chan);           /* Stop anything playing */
+               /* Stream the list of files */
+               while (!res && (front = strsep(&back, "&")) ) {
+                       if ( (res = ast_streamfile(chan, front, args.lang)) ) {
+                               ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", ast_channel_name(chan), (char*)data);
+                               res = 0;
+                               mres = 1;
+                               break;
+                       }
+                       if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
+                               res = ast_waitstream(chan, "");
+                       } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
+                               res = ast_waitstream_exten(chan, args.context);
+                       } else {
+                               res = ast_waitstream(chan, AST_DIGIT_ANY);
+                       }
+                       ast_stopstream(chan);
+               }
+       }
+
+       /*
+        * If the single digit DTMF is an extension in the specified context, then
+        * go there and signal no DTMF.  Otherwise, we should exit with that DTMF.
+        * If we're in Macro, we'll exit and seek that DTMF as the beginning of an
+        * extension in the Macro's calling context.  If we're not in Macro, then
+        * we'll simply seek that extension in the calling context.  Previously,
+        * someone complained about the behavior as it related to the interior of a
+        * Gosub routine, and the fix (#14011) inadvertently broke FreePBX
+        * (#14940).  This change should fix both of these situations, but with the
+        * possible incompatibility that if a single digit extension does not exist
+        * (but a longer extension COULD have matched), it would have previously
+        * gone immediately to the "i" extension, but will now need to wait for a
+        * timeout.
+        *
+        * Later, we had to add a flag to disable this workaround, because AGI
+        * users can EXEC Background and reasonably expect that the DTMF code will
+        * be returned (see #16434).
+        */
+       if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS)
+               && (exten[0] = res)
+               && ast_canmatch_extension(chan, args.context, exten, 1,
+                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
+               && !ast_matchmore_extension(chan, args.context, exten, 1,
+                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
+               char buf[2] = { 0, };
+               snprintf(buf, sizeof(buf), "%c", res);
+               ast_channel_exten_set(chan, buf);
+               ast_channel_context_set(chan, args.context);
+               ast_channel_priority_set(chan, 0);
+               res = 0;
+       }
+done:
+       pbx_builtin_setvar_helper(chan, "BACKGROUNDSTATUS", mres ? "FAILED" : "SUCCESS");
+       return res;
+}
+
+static int pbx_builtin_noop(struct ast_channel *chan, const char *data)
+{
+       return 0;
+}
+
+static int pbx_builtin_gotoif(struct ast_channel *chan, const char *data)
+{
+       char *condition, *branch1, *branch2, *branch;
+       char *stringp;
+
+       if (ast_strlen_zero(data)) {
+               ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
+               return 0;
+       }
+
+       stringp = ast_strdupa(data);
+       condition = strsep(&stringp,"?");
+       branch1 = strsep(&stringp,":");
+       branch2 = strsep(&stringp,"");
+       branch = pbx_checkcondition(condition) ? branch1 : branch2;
+
+       if (ast_strlen_zero(branch)) {
+               ast_debug(1, "Not taking any branch\n");
+               return 0;
+       }
+
+       return pbx_builtin_goto(chan, branch);
+}
+
+static int pbx_builtin_saynumber(struct ast_channel *chan, const char *data)
+{
+       char tmp[256];
+       char *number = tmp;
+       int number_val;
+       char *options;
+       int res;
+       int interrupt = 0;
+       const char *interrupt_string;
+
+       ast_channel_lock(chan);
+       interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
+       if (ast_true(interrupt_string)) {
+               interrupt = 1;
+       }
+       ast_channel_unlock(chan);
+
+       if (ast_strlen_zero(data)) {
+               ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
+               return -1;
+       }
+       ast_copy_string(tmp, data, sizeof(tmp));
+       strsep(&number, ",");
+
+       if (sscanf(tmp, "%d", &number_val) != 1) {
+               ast_log(LOG_WARNING, "argument '%s' to SayNumber could not be parsed as a number.\n", tmp);
+               return 0;
+       }
+
+       options = strsep(&number, ",");
+       if (options) {
+               if ( strcasecmp(options, "f") && strcasecmp(options, "m") &&
+                       strcasecmp(options, "c") && strcasecmp(options, "n") ) {
+                       ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
+                       return -1;
+               }
+       }
+
+       res = ast_say_number(chan, number_val, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), options);
+
+       if (res < 0) {
+               ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
+       }
+
+       return interrupt ? res : 0;
+}
+
+static int pbx_builtin_saydigits(struct ast_channel *chan, const char *data)
+{
+       int res = 0;
+       int interrupt = 0;
+       const char *interrupt_string;
+
+       ast_channel_lock(chan);
+       interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
+       if (ast_true(interrupt_string)) {
+               interrupt = 1;
+       }
+       ast_channel_unlock(chan);
+
+       if (data) {
+               res = ast_say_digit_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan));
+       }
+
+       return res;
+}
+
+static int pbx_builtin_saycharacters_case(struct ast_channel *chan, const char *data)
+{
+       int res = 0;
+       int sensitivity = 0;
+       char *parse;
+       int interrupt = 0;
+       const char *interrupt_string;
+
+       AST_DECLARE_APP_ARGS(args,
+               AST_APP_ARG(options);
+               AST_APP_ARG(characters);
+       );
+
+       ast_channel_lock(chan);
+       interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
+       if (ast_true(interrupt_string)) {
+               interrupt = 1;
+       }
+       ast_channel_unlock(chan);
+
+       if (ast_strlen_zero(data)) {
+               ast_log(LOG_WARNING, "SayAlphaCase requires two arguments (options, characters)\n");
+               return 0;
+       }
+
+       parse = ast_strdupa(data);
+       AST_STANDARD_APP_ARGS(args, parse);
+
+       if (!args.options || strlen(args.options) != 1) {
+               ast_log(LOG_WARNING, "SayAlphaCase options are mutually exclusive and required\n");
+               return 0;
+       }
+
+       switch (args.options[0]) {
+       case 'a':
+               sensitivity = AST_SAY_CASE_ALL;
+               break;
+       case 'l':
+               sensitivity = AST_SAY_CASE_LOWER;
+               break;
+       case 'n':
+               sensitivity = AST_SAY_CASE_NONE;
+               break;
+       case 'u':
+               sensitivity = AST_SAY_CASE_UPPER;
+               break;
+       default:
+               ast_log(LOG_WARNING, "Invalid option: '%s'\n", args.options);
+               return 0;
+       }
+
+       res = ast_say_character_str(chan, args.characters, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), sensitivity);
+
+       return res;
+}
+
+static int pbx_builtin_saycharacters(struct ast_channel *chan, const char *data)
+{
+       int res = 0;
+       int interrupt = 0;
+       const char *interrupt_string;
+
+       ast_channel_lock(chan);
+       interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
+       if (ast_true(interrupt_string)) {
+               interrupt = 1;
+       }
+       ast_channel_unlock(chan);
+
+       if (data) {
+               res = ast_say_character_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), AST_SAY_CASE_NONE);
+       }
+
+       return res;
+}
+
+static int pbx_builtin_sayphonetic(struct ast_channel *chan, const char *data)
+{
+       int res = 0;
+       int interrupt = 0;
+       const char *interrupt_string;
+
+       ast_channel_lock(chan);
+       interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
+       if (ast_true(interrupt_string)) {
+               interrupt = 1;
+       }
+       ast_channel_unlock(chan);
+
+       if (data)
+               res = ast_say_phonetic_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan));
+       return res;
+}
+
+static int pbx_builtin_importvar(struct ast_channel *chan, const char *data)
+{
+       char *name;
+       char *value;
+       char *channel;
+       char tmp[VAR_BUF_SIZE];
+       static int deprecation_warning = 0;
+
+       if (ast_strlen_zero(data)) {
+               ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
+               return 0;
+       }
+       tmp[0] = 0;
+       if (!deprecation_warning) {
+               ast_log(LOG_WARNING, "ImportVar is deprecated.  Please use Set(varname=${IMPORT(channel,variable)}) instead.\n");
+               deprecation_warning = 1;
+       }
+
+       value = ast_strdupa(data);
+       name = strsep(&value,"=");
+       channel = strsep(&value,",");
+       if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
+               struct ast_channel *chan2 = ast_channel_get_by_name(channel);
+               if (chan2) {
+                       char *s = ast_alloca(strlen(value) + 4);
+                       sprintf(s, "${%s}", value);
+                       pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
+                       chan2 = ast_channel_unref(chan2);
+               }
+               pbx_builtin_setvar_helper(chan, name, tmp);
+       }
+
+       return(0);
+}
+
+/*! \brief Declaration of builtin applications */
+struct pbx_builtin {
+       char name[AST_MAX_APP];
+       int (*execute)(struct ast_channel *chan, const char *data);
+} builtins[] =
+{
+       /* These applications are built into the PBX core and do not
+          need separate modules */
+
+       { "Answer",         pbx_builtin_answer },
+       { "BackGround",     pbx_builtin_background },
+       { "Busy",           indicate_busy },
+       { "Congestion",     indicate_congestion },
+       { "ExecIfTime",     pbx_builtin_execiftime },
+       { "Goto",           pbx_builtin_goto },
+       { "GotoIf",         pbx_builtin_gotoif },
+       { "GotoIfTime",     pbx_builtin_gotoiftime },
+       { "ImportVar",      pbx_builtin_importvar },
+       { "Hangup",         pbx_builtin_hangup },
+       { "Incomplete",     pbx_builtin_incomplete },
+       { "NoOp",           pbx_builtin_noop },
+       { "Proceeding",     pbx_builtin_proceeding },
+       { "Progress",       pbx_builtin_progress },
+       { "RaiseException", pbx_builtin_raise_exception },
+       { "Ringing",        pbx_builtin_ringing },
+       { "SayAlpha",       pbx_builtin_saycharacters },
+       { "SayAlphaCase",   pbx_builtin_saycharacters_case },
+       { "SayDigits",      pbx_builtin_saydigits },
+       { "SayNumber",      pbx_builtin_saynumber },
+       { "SayPhonetic",    pbx_builtin_sayphonetic },
+       { "Set",            pbx_builtin_setvar },
+       { "MSet",           pbx_builtin_setvar_multiple },
+       { "SetAMAFlags",    pbx_builtin_setamaflags },
+       { "Wait",           pbx_builtin_wait },
+       { "WaitExten",      pbx_builtin_waitexten }
+};
+
+static void unload_pbx_builtins(void)
+{
+       int x;
+
+       /* Unregister builtin applications */
+       for (x = 0; x < ARRAY_LEN(builtins); x++) {
+               ast_unregister_application(builtins[x].name);
+       }
+}
+
+int load_pbx_builtins(void)
+{
+       int x;
+
+       /* Register builtin applications */
+       for (x = 0; x < ARRAY_LEN(builtins); x++) {
+               if (ast_register_application2(builtins[x].name, builtins[x].execute, NULL, NULL, NULL)) {
+                       ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
+                       unload_pbx_builtins();
+                       return -1;
+               }
+       }
+
+       ast_register_cleanup(unload_pbx_builtins);
+
+       return 0;
+}
diff --git a/main/pbx_private.h b/main/pbx_private.h
new file mode 100644 (file)
index 0000000..e171179
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2015 Fairview 5 Engineering, LLC
+ *
+ * George Joseph <george.joseph@fairview5.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.
+ */
+
+/*! \file
+ * \brief Private include file for pbx
+ */
+
+#ifndef _PBX_PRIVATE_H
+#define _PBX_PRIVATE_H
+
+/*! pbx.c functions needed by pbx_builtins.c */
+int raise_exception(struct ast_channel *chan, const char *reason, int priority);
+void wait_for_hangup(struct ast_channel *chan, const void *data);
+void set_ext_pri(struct ast_channel *c, const char *exten, int pri);
+
+/*! pbx_builtins.c functions needed by pbx.c */
+int indicate_congestion(struct ast_channel *, const char *);
+int indicate_busy(struct ast_channel *, const char *);
+
+#define VAR_BUF_SIZE 4096
+
+#endif /* _PBX_PRIVATE_H */