2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2015 Fairview 5 Engineering, LLC
6 * George Joseph <george.joseph@fairview5.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Core PBX builtin routines.
23 * \author George Joseph <george.joseph@fairview5.com>
27 <support_level>core</support_level>
32 ASTERISK_REGISTER_FILE()
34 #include "asterisk/_private.h"
35 #include "asterisk/pbx.h"
36 #include "asterisk/causes.h"
37 #include "asterisk/indications.h"
38 #include "asterisk/stasis_channels.h"
39 #include "asterisk/say.h"
40 #include "asterisk/app.h"
41 #include "asterisk/module.h"
42 #include "pbx_private.h"
45 <application name="Answer" language="en_US">
47 Answer a channel if ringing.
50 <parameter name="delay">
51 <para>Asterisk will wait this number of milliseconds before returning to
52 the dialplan after answering the call.</para>
56 <para>If the call has not been answered, this application will
57 answer it. Otherwise, it has no effect on the call.</para>
60 <ref type="application">Hangup</ref>
63 <application name="BackGround" language="en_US">
65 Play an audio file while waiting for digits of an extension to go to.
68 <parameter name="filenames" required="true" argsep="&">
69 <argument name="filename1" required="true" />
70 <argument name="filename2" multiple="true" />
72 <parameter name="options">
75 <para>Causes the playback of the message to be skipped
76 if the channel is not in the <literal>up</literal> state (i.e. it
77 hasn't been answered yet). If this happens, the
78 application will return immediately.</para>
81 <para>Don't answer the channel before playing the files.</para>
84 <para>Only break if a digit hit matches a one digit
85 extension in the destination context.</para>
89 <parameter name="langoverride">
90 <para>Explicitly specifies which language to attempt to use for the requested sound files.</para>
92 <parameter name="context">
93 <para>This is the dialplan context that this application will use when exiting
94 to a dialed extension.</para>
98 <para>This application will play the given list of files <emphasis>(do not put extension)</emphasis>
99 while waiting for an extension to be dialed by the calling channel. To continue waiting
100 for digits after this application has finished playing files, the <literal>WaitExten</literal>
101 application should be used.</para>
102 <para>If one of the requested sound files does not exist, call processing will be terminated.</para>
103 <para>This application sets the following channel variable upon completion:</para>
105 <variable name="BACKGROUNDSTATUS">
106 <para>The status of the background attempt as a text string.</para>
107 <value name="SUCCESS" />
108 <value name="FAILED" />
113 <ref type="application">ControlPlayback</ref>
114 <ref type="application">WaitExten</ref>
115 <ref type="application">BackgroundDetect</ref>
116 <ref type="function">TIMEOUT</ref>
119 <application name="Busy" language="en_US">
121 Indicate the Busy condition.
124 <parameter name="timeout">
125 <para>If specified, the calling channel will be hung up after the specified number of seconds.
126 Otherwise, this application will wait until the calling channel hangs up.</para>
130 <para>This application will indicate the busy condition to the calling channel.</para>
133 <ref type="application">Congestion</ref>
134 <ref type="application">Progress</ref>
135 <ref type="application">Playtones</ref>
136 <ref type="application">Hangup</ref>
139 <application name="Congestion" language="en_US">
141 Indicate the Congestion condition.
144 <parameter name="timeout">
145 <para>If specified, the calling channel will be hung up after the specified number of seconds.
146 Otherwise, this application will wait until the calling channel hangs up.</para>
150 <para>This application will indicate the congestion condition to the calling channel.</para>
153 <ref type="application">Busy</ref>
154 <ref type="application">Progress</ref>
155 <ref type="application">Playtones</ref>
156 <ref type="application">Hangup</ref>
159 <application name="ExecIfTime" language="en_US">
161 Conditional application execution based on the current time.
164 <parameter name="day_condition" required="true">
165 <argument name="times" required="true" />
166 <argument name="weekdays" required="true" />
167 <argument name="mdays" required="true" />
168 <argument name="months" required="true" />
169 <argument name="timezone" required="false" />
171 <parameter name="appname" required="true" hasparams="optional">
172 <argument name="appargs" required="true" />
176 <para>This application will execute the specified dialplan application, with optional
177 arguments, if the current time matches the given time specification.</para>
180 <ref type="application">Exec</ref>
181 <ref type="application">ExecIf</ref>
182 <ref type="application">TryExec</ref>
183 <ref type="application">GotoIfTime</ref>
186 <application name="Goto" language="en_US">
188 Jump to a particular priority, extension, or context.
191 <parameter name="context" />
192 <parameter name="extensions" />
193 <parameter name="priority" required="true" />
196 <para>This application will set the current context, extension, and priority in the channel structure.
197 After it completes, the pbx engine will continue dialplan execution at the specified location.
198 If no specific <replaceable>extension</replaceable>, or <replaceable>extension</replaceable> and
199 <replaceable>context</replaceable>, are specified, then this application will
200 just set the specified <replaceable>priority</replaceable> of the current extension.</para>
201 <para>At least a <replaceable>priority</replaceable> is required as an argument, or the goto will
202 return a <literal>-1</literal>, and the channel and call will be terminated.</para>
203 <para>If the location that is put into the channel information is bogus, and asterisk cannot
204 find that location in the dialplan, then the execution engine will try to find and execute the code in
205 the <literal>i</literal> (invalid) extension in the current context. If that does not exist, it will try to execute the
206 <literal>h</literal> extension. If neither the <literal>h</literal> nor <literal>i</literal> extensions
207 have been defined, the channel is hung up, and the execution of instructions on the channel is terminated.
208 What this means is that, for example, you specify a context that does not exist, then
209 it will not be possible to find the <literal>h</literal> or <literal>i</literal> extensions,
210 and the call will terminate!</para>
213 <ref type="application">GotoIf</ref>
214 <ref type="application">GotoIfTime</ref>
215 <ref type="application">Gosub</ref>
216 <ref type="application">Macro</ref>
219 <application name="GotoIf" language="en_US">
224 <parameter name="condition" required="true" />
225 <parameter name="destination" required="true" argsep=":">
226 <argument name="labeliftrue">
227 <para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.
228 Takes the form similar to Goto() of [[context,]extension,]priority.</para>
230 <argument name="labeliffalse">
231 <para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.
232 Takes the form similar to Goto() of [[context,]extension,]priority.</para>
237 <para>This application will set the current context, extension, and priority in the channel structure
238 based on the evaluation of the given condition. After this application completes, the
239 pbx engine will continue dialplan execution at the specified location in the dialplan.
240 The labels are specified with the same syntax as used within the Goto application.
241 If the label chosen by the condition is omitted, no jump is performed, and the execution passes to the
242 next instruction. If the target location is bogus, and does not exist, the execution engine will try
243 to find and execute the code in the <literal>i</literal> (invalid) extension in the current context.
244 If that does not exist, it will try to execute the <literal>h</literal> extension.
245 If neither the <literal>h</literal> nor <literal>i</literal> extensions have been defined,
246 the channel is hung up, and the execution of instructions on the channel is terminated.
247 Remember that this command can set the current context, and if the context specified
248 does not exist, then it will not be able to find any 'h' or 'i' extensions there, and
249 the channel and call will both be terminated!.</para>
252 <ref type="application">Goto</ref>
253 <ref type="application">GotoIfTime</ref>
254 <ref type="application">GosubIf</ref>
255 <ref type="application">MacroIf</ref>
258 <application name="GotoIfTime" language="en_US">
260 Conditional Goto based on the current time.
263 <parameter name="condition" required="true">
264 <argument name="times" required="true" />
265 <argument name="weekdays" required="true" />
266 <argument name="mdays" required="true" />
267 <argument name="months" required="true" />
268 <argument name="timezone" required="false" />
270 <parameter name="destination" required="true" argsep=":">
271 <argument name="labeliftrue">
272 <para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.
273 Takes the form similar to Goto() of [[context,]extension,]priority.</para>
275 <argument name="labeliffalse">
276 <para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.
277 Takes the form similar to Goto() of [[context,]extension,]priority.</para>
282 <para>This application will set the context, extension, and priority in the channel structure
283 based on the evaluation of the given time specification. After this application completes,
284 the pbx engine will continue dialplan execution at the specified location in the dialplan.
285 If the current time is within the given time specification, the channel will continue at
286 <replaceable>labeliftrue</replaceable>. Otherwise the channel will continue at <replaceable>labeliffalse</replaceable>.
287 If the label chosen by the condition is omitted, no jump is performed, and execution passes to the next
288 instruction. If the target jump location is bogus, the same actions would be taken as for <literal>Goto</literal>.
289 Further information on the time specification can be found in examples
290 illustrating how to do time-based context includes in the dialplan.</para>
293 <ref type="application">GotoIf</ref>
294 <ref type="application">Goto</ref>
295 <ref type="function">IFTIME</ref>
296 <ref type="function">TESTTIME</ref>
299 <application name="ImportVar" language="en_US">
301 Import a variable from a channel into a new variable.
304 <parameter name="newvar" required="true" />
305 <parameter name="vardata" required="true">
306 <argument name="channelname" required="true" />
307 <argument name="variable" required="true" />
311 <para>This application imports a <replaceable>variable</replaceable> from the specified
312 <replaceable>channel</replaceable> (as opposed to the current one) and stores it as a variable
313 (<replaceable>newvar</replaceable>) in the current channel (the channel that is calling this
314 application). Variables created by this application have the same inheritance properties as those
315 created with the <literal>Set</literal> application.</para>
318 <ref type="application">Set</ref>
321 <application name="Hangup" language="en_US">
323 Hang up the calling channel.
326 <parameter name="causecode">
327 <para>If a <replaceable>causecode</replaceable> is given the channel's
328 hangup cause will be set to the given value.</para>
332 <para>This application will hang up the calling channel.</para>
335 <ref type="application">Answer</ref>
336 <ref type="application">Busy</ref>
337 <ref type="application">Congestion</ref>
340 <application name="Incomplete" language="en_US">
342 Returns AST_PBX_INCOMPLETE value.
346 <para>If specified, then Incomplete will not attempt to answer the channel first.</para>
347 <note><para>Most channel types need to be in Answer state in order to receive DTMF.</para></note>
351 <para>Signals the PBX routines that the previous matched extension is incomplete
352 and that further input should be allowed before matching can be considered
353 to be complete. Can be used within a pattern match when certain criteria warrants
354 a longer match.</para>
357 <application name="NoOp" language="en_US">
359 Do Nothing (No Operation).
362 <parameter name="text">
363 <para>Any text provided can be viewed at the Asterisk CLI.</para>
367 <para>This application does nothing. However, it is useful for debugging purposes.</para>
368 <para>This method can be used to see the evaluations of variables or functions without having any effect.</para>
371 <ref type="application">Verbose</ref>
372 <ref type="application">Log</ref>
375 <application name="Proceeding" language="en_US">
381 <para>This application will request that a proceeding message be provided to the calling channel.</para>
384 <application name="Progress" language="en_US">
390 <para>This application will request that in-band progress information be provided to the calling channel.</para>
393 <ref type="application">Busy</ref>
394 <ref type="application">Congestion</ref>
395 <ref type="application">Ringing</ref>
396 <ref type="application">Playtones</ref>
399 <application name="RaiseException" language="en_US">
401 Handle an exceptional condition.
404 <parameter name="reason" required="true" />
407 <para>This application will jump to the <literal>e</literal> extension in the current context, setting the
408 dialplan function EXCEPTION(). If the <literal>e</literal> extension does not exist, the call will hangup.</para>
411 <ref type="function">Exception</ref>
414 <application name="Ringing" language="en_US">
416 Indicate ringing tone.
420 <para>This application will request that the channel indicate a ringing tone to the user.</para>
423 <ref type="application">Busy</ref>
424 <ref type="application">Congestion</ref>
425 <ref type="application">Progress</ref>
426 <ref type="application">Playtones</ref>
429 <application name="SayAlpha" language="en_US">
434 <parameter name="string" required="true" />
437 <para>This application will play the sounds that correspond to the letters
438 of the given <replaceable>string</replaceable>. If the channel variable
439 <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive),
440 then this application will react to DTMF in the same way as
441 <literal>Background</literal>.</para>
444 <ref type="application">SayDigits</ref>
445 <ref type="application">SayNumber</ref>
446 <ref type="application">SayPhonetic</ref>
447 <ref type="function">CHANNEL</ref>
450 <application name="SayAlphaCase" language="en_US">
455 <parameter name="casetype" required="true" >
458 <para>Case sensitive (all) pronunciation.
459 (Ex: SayAlphaCase(a,aBc); - lowercase a uppercase b lowercase c).</para>
462 <para>Case sensitive (lower) pronunciation.
463 (Ex: SayAlphaCase(l,aBc); - lowercase a b lowercase c).</para>
466 <para>Case insensitive pronunciation. Equivalent to SayAlpha.
467 (Ex: SayAlphaCase(n,aBc) - a b c).</para>
470 <para>Case sensitive (upper) pronunciation.
471 (Ex: SayAlphaCase(u,aBc); - a uppercase b c).</para>
475 <parameter name="string" required="true" />
478 <para>This application will play the sounds that correspond to the letters of the
479 given <replaceable>string</replaceable>. Optionally, a <replaceable>casetype</replaceable> may be
480 specified. This will be used for case-insensitive or case-sensitive pronunciations. If the channel
481 variable <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
482 application will react to DTMF in the same way as <literal>Background</literal>.</para>
485 <ref type="application">SayDigits</ref>
486 <ref type="application">SayNumber</ref>
487 <ref type="application">SayPhonetic</ref>
488 <ref type="application">SayAlpha</ref>
489 <ref type="function">CHANNEL</ref>
492 <application name="SayDigits" language="en_US">
497 <parameter name="digits" required="true" />
500 <para>This application will play the sounds that correspond to the digits of
501 the given number. This will use the language that is currently set for the channel.
502 If the channel variable <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true'
503 (case insensitive), then this application will react to DTMF in the same way as
504 <literal>Background</literal>.</para>
507 <ref type="application">SayAlpha</ref>
508 <ref type="application">SayNumber</ref>
509 <ref type="application">SayPhonetic</ref>
510 <ref type="function">CHANNEL</ref>
513 <application name="SayNumber" language="en_US">
518 <parameter name="digits" required="true" />
519 <parameter name="gender" />
522 <para>This application will play the sounds that correspond to the given
523 <replaceable>digits</replaceable>. Optionally, a <replaceable>gender</replaceable> may be
524 specified. This will use the language that is currently set for the channel. See the CHANNEL()
525 function for more information on setting the language for the channel. If the channel variable
526 <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
527 application will react to DTMF in the same way as <literal>Background</literal>.</para>
530 <ref type="application">SayAlpha</ref>
531 <ref type="application">SayDigits</ref>
532 <ref type="application">SayPhonetic</ref>
533 <ref type="function">CHANNEL</ref>
536 <application name="SayPhonetic" language="en_US">
541 <parameter name="string" required="true" />
544 <para>This application will play the sounds from the phonetic alphabet that correspond to the
545 letters in the given <replaceable>string</replaceable>. If the channel variable
546 <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
547 application will react to DTMF in the same way as <literal>Background</literal>.</para>
550 <ref type="application">SayAlpha</ref>
551 <ref type="application">SayDigits</ref>
552 <ref type="application">SayNumber</ref>
555 <application name="SetAMAFlags" language="en_US">
560 <parameter name="flag" />
563 <para>This application will set the channel's AMA Flags for billing purposes.</para>
564 <warning><para>This application is deprecated. Please use the CHANNEL function instead.</para></warning>
567 <ref type="function">CDR</ref>
568 <ref type="function">CHANNEL</ref>
571 <application name="Wait" language="en_US">
576 <parameter name="seconds" required="true">
577 <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
578 application to wait for 1.5 seconds.</para>
582 <para>This application waits for a specified number of <replaceable>seconds</replaceable>.</para>
585 <application name="WaitExten" language="en_US">
587 Waits for an extension to be entered.
590 <parameter name="seconds">
591 <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
592 application to wait for 1.5 seconds.</para>
594 <parameter name="options">
597 <para>Provide music on hold to the caller while waiting for an extension.</para>
599 <para>Specify the class for music on hold. <emphasis>CHANNEL(musicclass) will
600 be used instead if set</emphasis></para>
607 <para>This application waits for the user to enter a new extension for a specified number
608 of <replaceable>seconds</replaceable>.</para>
609 <xi:include xpointer="xpointer(/docs/application[@name='Macro']/description/warning[2])" />
612 <ref type="application">Background</ref>
613 <ref type="function">TIMEOUT</ref>
618 #define BACKGROUND_SKIP (1 << 0)
619 #define BACKGROUND_NOANSWER (1 << 1)
620 #define BACKGROUND_MATCHEXTEN (1 << 2)
621 #define BACKGROUND_PLAYBACK (1 << 3)
623 AST_APP_OPTIONS(background_opts, {
624 AST_APP_OPTION('s', BACKGROUND_SKIP),
625 AST_APP_OPTION('n', BACKGROUND_NOANSWER),
626 AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
627 AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
630 #define WAITEXTEN_MOH (1 << 0)
631 #define WAITEXTEN_DIALTONE (1 << 1)
633 AST_APP_OPTIONS(waitexten_opts, {
634 AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
635 AST_APP_OPTION_ARG('d', WAITEXTEN_DIALTONE, 0),
638 int pbx_builtin_raise_exception(struct ast_channel *chan, const char *reason)
640 /* Priority will become 1, next time through the AUTOLOOP */
641 return raise_exception(chan, reason, 0);
645 * \ingroup applications
647 static int pbx_builtin_proceeding(struct ast_channel *chan, const char *data)
649 ast_indicate(chan, AST_CONTROL_PROCEEDING);
654 * \ingroup applications
656 static int pbx_builtin_progress(struct ast_channel *chan, const char *data)
658 ast_indicate(chan, AST_CONTROL_PROGRESS);
663 * \ingroup applications
665 static int pbx_builtin_ringing(struct ast_channel *chan, const char *data)
667 ast_indicate(chan, AST_CONTROL_RINGING);
672 * \ingroup applications
674 int indicate_busy(struct ast_channel *chan, const char *data)
676 ast_indicate(chan, AST_CONTROL_BUSY);
677 /* Don't change state of an UP channel, just indicate
679 ast_channel_lock(chan);
680 if (ast_channel_state(chan) != AST_STATE_UP) {
681 ast_channel_hangupcause_set(chan, AST_CAUSE_BUSY);
682 ast_setstate(chan, AST_STATE_BUSY);
684 ast_channel_unlock(chan);
685 wait_for_hangup(chan, data);
690 * \ingroup applications
692 int indicate_congestion(struct ast_channel *chan, const char *data)
694 ast_indicate(chan, AST_CONTROL_CONGESTION);
695 /* Don't change state of an UP channel, just indicate
696 congestion in audio */
697 ast_channel_lock(chan);
698 if (ast_channel_state(chan) != AST_STATE_UP) {
699 ast_channel_hangupcause_set(chan, AST_CAUSE_CONGESTION);
700 ast_setstate(chan, AST_STATE_BUSY);
702 ast_channel_unlock(chan);
703 wait_for_hangup(chan, data);
708 * \ingroup applications
710 static int pbx_builtin_answer(struct ast_channel *chan, const char *data)
714 AST_DECLARE_APP_ARGS(args,
716 AST_APP_ARG(answer_cdr);
719 if (ast_strlen_zero(data)) {
720 return __ast_answer(chan, 0);
723 parse = ast_strdupa(data);
725 AST_STANDARD_APP_ARGS(args, parse);
727 if (!ast_strlen_zero(args.delay) && (ast_channel_state(chan) != AST_STATE_UP))
734 if (!ast_strlen_zero(args.answer_cdr) && !strcasecmp(args.answer_cdr, "nocdr")) {
735 ast_log(AST_LOG_WARNING, "The nocdr option for the Answer application has been removed and is no longer supported.\n");
738 return __ast_answer(chan, delay);
741 static int pbx_builtin_incomplete(struct ast_channel *chan, const char *data)
743 const char *options = data;
746 /* Some channels can receive DTMF in unanswered state; some cannot */
747 if (!ast_strlen_zero(options) && strchr(options, 'n')) {
751 /* If the channel is hungup, stop waiting */
752 if (ast_check_hangup(chan)) {
754 } else if (ast_channel_state(chan) != AST_STATE_UP && answer) {
755 __ast_answer(chan, 0);
758 ast_indicate(chan, AST_CONTROL_INCOMPLETE);
760 return AST_PBX_INCOMPLETE;
764 * \ingroup applications
766 static int pbx_builtin_setamaflags(struct ast_channel *chan, const char *data)
768 ast_log(AST_LOG_WARNING, "The SetAMAFlags application is deprecated. Please use the CHANNEL function instead.\n");
770 if (ast_strlen_zero(data)) {
771 ast_log(AST_LOG_WARNING, "No parameter passed to SetAMAFlags\n");
774 /* Copy the AMA Flags as specified */
775 ast_channel_lock(chan);
776 if (isdigit(data[0])) {
778 if (sscanf(data, "%30d", &amaflags) != 1) {
779 ast_log(AST_LOG_WARNING, "Unable to set AMA flags on channel %s\n", ast_channel_name(chan));
780 ast_channel_unlock(chan);
783 ast_channel_amaflags_set(chan, amaflags);
785 ast_channel_amaflags_set(chan, ast_channel_string2amaflag(data));
787 ast_channel_unlock(chan);
792 * \ingroup applications
794 static int pbx_builtin_hangup(struct ast_channel *chan, const char *data)
798 ast_set_hangupsource(chan, "dialplan/builtin", 0);
800 if (!ast_strlen_zero(data)) {
801 cause = ast_str2cause(data);
803 if (sscanf(data, "%30d", &cause) != 1 || cause <= 0) {
804 ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", data);
812 ast_channel_lock(chan);
814 cause = ast_channel_hangupcause(chan);
816 cause = AST_CAUSE_NORMAL_CLEARING;
819 ast_channel_hangupcause_set(chan, cause);
820 ast_softhangup_nolock(chan, AST_SOFTHANGUP_EXPLICIT);
821 ast_channel_unlock(chan);
827 * \ingroup applications
829 static int pbx_builtin_goto(struct ast_channel *chan, const char *data)
831 int res = ast_parseable_goto(chan, data);
833 ast_verb(3, "Goto (%s,%s,%d)\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan) + 1);
838 * \ingroup applications
840 static int pbx_builtin_gotoiftime(struct ast_channel *chan, const char *data)
842 char *s, *ts, *branch1, *branch2, *branch;
843 struct ast_timing timing;
845 struct timeval tv = ast_tvnow();
849 ast_log(LOG_WARNING, "GotoIfTime requires a channel on which to operate\n");
853 if (ast_strlen_zero(data)) {
854 ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>[,<timezone>]?'labeliftrue':'labeliffalse'\n");
858 ts = s = ast_strdupa(data);
860 ast_channel_lock(chan);
861 if ((ctime = pbx_builtin_getvar_helper(chan, "TESTTIME")) && sscanf(ctime, "%ld", ×ecs) == 1) {
862 tv.tv_sec = timesecs;
864 ast_log(LOG_WARNING, "Using current time to evaluate\n");
865 /* Reset when unparseable */
866 pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
868 ast_channel_unlock(chan);
870 /* Separate the Goto path */
872 branch1 = strsep(&ts,":");
873 branch2 = strsep(&ts,"");
875 /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
876 if (ast_build_timing(&timing, s) && ast_check_timing2(&timing, tv)) {
881 ast_destroy_timing(&timing);
883 if (ast_strlen_zero(branch)) {
884 ast_debug(1, "Not taking any branch\n");
888 return pbx_builtin_goto(chan, branch);
892 * \ingroup applications
894 static int pbx_builtin_execiftime(struct ast_channel *chan, const char *data)
897 struct ast_timing timing;
899 static const char * const usage = "ExecIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>[,<timezone>]?<appname>[(<appargs>)]";
901 if (ast_strlen_zero(data)) {
902 ast_log(LOG_WARNING, "%s\n", usage);
906 appname = ast_strdupa(data);
908 s = strsep(&appname, "?"); /* Separate the timerange and application name/data */
909 if (!appname) { /* missing application */
910 ast_log(LOG_WARNING, "%s\n", usage);
914 if (!ast_build_timing(&timing, s)) {
915 ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
916 ast_destroy_timing(&timing);
920 if (!ast_check_timing(&timing)) { /* outside the valid time window, just return */
921 ast_destroy_timing(&timing);
924 ast_destroy_timing(&timing);
926 /* now split appname(appargs) */
927 if ((s = strchr(appname, '('))) {
930 if ((e = strrchr(s, ')')))
933 ast_log(LOG_WARNING, "Failed to find closing parenthesis\n");
937 if ((app = pbx_findapp(appname))) {
938 return pbx_exec(chan, app, S_OR(s, ""));
940 ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
946 * \ingroup applications
948 static int pbx_builtin_wait(struct ast_channel *chan, const char *data)
952 /* Wait for "n" seconds */
953 if (!ast_app_parse_timelen(data, &ms, TIMELEN_SECONDS) && ms > 0) {
954 return ast_safe_sleep(chan, ms);
960 * \ingroup applications
962 static int pbx_builtin_waitexten(struct ast_channel *chan, const char *data)
965 struct ast_flags flags = {0};
966 char *opts[1] = { NULL };
968 AST_DECLARE_APP_ARGS(args,
969 AST_APP_ARG(timeout);
970 AST_APP_ARG(options);
973 if (!ast_strlen_zero(data)) {
974 parse = ast_strdupa(data);
975 AST_STANDARD_APP_ARGS(args, parse);
977 memset(&args, 0, sizeof(args));
980 ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
982 if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
983 ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n");
984 } else if (ast_test_flag(&flags, WAITEXTEN_MOH)) {
985 ast_indicate_data(chan, AST_CONTROL_HOLD, S_OR(opts[0], NULL),
986 !ast_strlen_zero(opts[0]) ? strlen(opts[0]) + 1 : 0);
987 } else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE)) {
988 struct ast_tone_zone_sound *ts = ast_get_indication_tone(ast_channel_zone(chan), "dial");
990 ast_playtones_start(chan, 0, ts->data, 0);
991 ts = ast_tone_zone_sound_unref(ts);
993 ast_tonepair_start(chan, 350, 440, 0, 0);
996 /* Wait for "n" seconds */
997 if (!ast_app_parse_timelen(args.timeout, &ms, TIMELEN_SECONDS) && ms > 0) {
999 } else if (ast_channel_pbx(chan)) {
1000 ms = ast_channel_pbx(chan)->rtimeoutms;
1005 res = ast_waitfordigit(chan, ms);
1007 if (ast_check_hangup(chan)) {
1008 /* Call is hungup for some reason. */
1010 } else if (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan) + 1,
1011 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
1012 ast_verb(3, "Timeout on %s, continuing...\n", ast_channel_name(chan));
1013 } else if (ast_exists_extension(chan, ast_channel_context(chan), "t", 1,
1014 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
1015 ast_verb(3, "Timeout on %s, going to 't'\n", ast_channel_name(chan));
1016 set_ext_pri(chan, "t", 0); /* 0 will become 1, next time through the loop */
1017 } else if (ast_exists_extension(chan, ast_channel_context(chan), "e", 1,
1018 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
1019 raise_exception(chan, "RESPONSETIMEOUT", 0); /* 0 will become 1, next time through the loop */
1021 ast_log(LOG_WARNING, "Timeout but no rule 't' or 'e' in context '%s'\n",
1022 ast_channel_context(chan));
1027 if (ast_test_flag(&flags, WAITEXTEN_MOH))
1028 ast_indicate(chan, AST_CONTROL_UNHOLD);
1029 else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE))
1030 ast_playtones_stop(chan);
1036 * \ingroup applications
1038 static int pbx_builtin_background(struct ast_channel *chan, const char *data)
1042 struct ast_flags flags = {0};
1043 char *parse, exten[2] = "";
1044 AST_DECLARE_APP_ARGS(args,
1045 AST_APP_ARG(filename);
1046 AST_APP_ARG(options);
1048 AST_APP_ARG(context);
1051 if (ast_strlen_zero(data)) {
1052 ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
1056 parse = ast_strdupa(data);
1058 AST_STANDARD_APP_ARGS(args, parse);
1060 if (ast_strlen_zero(args.lang))
1061 args.lang = (char *)ast_channel_language(chan); /* XXX this is const */
1063 if (ast_strlen_zero(args.context)) {
1064 const char *context;
1065 ast_channel_lock(chan);
1066 if ((context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"))) {
1067 args.context = ast_strdupa(context);
1069 args.context = ast_strdupa(ast_channel_context(chan));
1071 ast_channel_unlock(chan);
1075 if (!strcasecmp(args.options, "skip"))
1076 flags.flags = BACKGROUND_SKIP;
1077 else if (!strcasecmp(args.options, "noanswer"))
1078 flags.flags = BACKGROUND_NOANSWER;
1080 ast_app_parse_options(background_opts, &flags, NULL, args.options);
1083 /* Answer if need be */
1084 if (ast_channel_state(chan) != AST_STATE_UP) {
1085 if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
1087 } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
1088 res = ast_answer(chan);
1093 char *back = ast_strip(args.filename);
1096 ast_stopstream(chan); /* Stop anything playing */
1097 /* Stream the list of files */
1098 while (!res && (front = strsep(&back, "&")) ) {
1099 if ( (res = ast_streamfile(chan, front, args.lang)) ) {
1100 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", ast_channel_name(chan), (char*)data);
1105 if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
1106 res = ast_waitstream(chan, "");
1107 } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
1108 res = ast_waitstream_exten(chan, args.context);
1110 res = ast_waitstream(chan, AST_DIGIT_ANY);
1112 ast_stopstream(chan);
1117 * If the single digit DTMF is an extension in the specified context, then
1118 * go there and signal no DTMF. Otherwise, we should exit with that DTMF.
1119 * If we're in Macro, we'll exit and seek that DTMF as the beginning of an
1120 * extension in the Macro's calling context. If we're not in Macro, then
1121 * we'll simply seek that extension in the calling context. Previously,
1122 * someone complained about the behavior as it related to the interior of a
1123 * Gosub routine, and the fix (#14011) inadvertently broke FreePBX
1124 * (#14940). This change should fix both of these situations, but with the
1125 * possible incompatibility that if a single digit extension does not exist
1126 * (but a longer extension COULD have matched), it would have previously
1127 * gone immediately to the "i" extension, but will now need to wait for a
1130 * Later, we had to add a flag to disable this workaround, because AGI
1131 * users can EXEC Background and reasonably expect that the DTMF code will
1132 * be returned (see #16434).
1134 if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS)
1136 && ast_canmatch_extension(chan, args.context, exten, 1,
1137 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
1138 && !ast_matchmore_extension(chan, args.context, exten, 1,
1139 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
1140 char buf[2] = { 0, };
1141 snprintf(buf, sizeof(buf), "%c", res);
1142 ast_channel_exten_set(chan, buf);
1143 ast_channel_context_set(chan, args.context);
1144 ast_channel_priority_set(chan, 0);
1148 pbx_builtin_setvar_helper(chan, "BACKGROUNDSTATUS", mres ? "FAILED" : "SUCCESS");
1152 static int pbx_builtin_noop(struct ast_channel *chan, const char *data)
1157 static int pbx_builtin_gotoif(struct ast_channel *chan, const char *data)
1159 char *condition, *branch1, *branch2, *branch;
1162 if (ast_strlen_zero(data)) {
1163 ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
1167 stringp = ast_strdupa(data);
1168 condition = strsep(&stringp,"?");
1169 branch1 = strsep(&stringp,":");
1170 branch2 = strsep(&stringp,"");
1171 branch = pbx_checkcondition(condition) ? branch1 : branch2;
1173 if (ast_strlen_zero(branch)) {
1174 ast_debug(1, "Not taking any branch\n");
1178 return pbx_builtin_goto(chan, branch);
1181 static int pbx_builtin_saynumber(struct ast_channel *chan, const char *data)
1189 const char *interrupt_string;
1191 ast_channel_lock(chan);
1192 interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
1193 if (ast_true(interrupt_string)) {
1196 ast_channel_unlock(chan);
1198 if (ast_strlen_zero(data)) {
1199 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
1202 ast_copy_string(tmp, data, sizeof(tmp));
1203 strsep(&number, ",");
1205 if (sscanf(tmp, "%d", &number_val) != 1) {
1206 ast_log(LOG_WARNING, "argument '%s' to SayNumber could not be parsed as a number.\n", tmp);
1210 options = strsep(&number, ",");
1212 if ( strcasecmp(options, "f") && strcasecmp(options, "m") &&
1213 strcasecmp(options, "c") && strcasecmp(options, "n") ) {
1214 ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
1219 res = ast_say_number(chan, number_val, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), options);
1222 ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
1225 return interrupt ? res : 0;
1228 static int pbx_builtin_saydigits(struct ast_channel *chan, const char *data)
1232 const char *interrupt_string;
1234 ast_channel_lock(chan);
1235 interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
1236 if (ast_true(interrupt_string)) {
1239 ast_channel_unlock(chan);
1242 res = ast_say_digit_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan));
1248 static int pbx_builtin_saycharacters_case(struct ast_channel *chan, const char *data)
1251 int sensitivity = 0;
1254 const char *interrupt_string;
1256 AST_DECLARE_APP_ARGS(args,
1257 AST_APP_ARG(options);
1258 AST_APP_ARG(characters);
1261 ast_channel_lock(chan);
1262 interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
1263 if (ast_true(interrupt_string)) {
1266 ast_channel_unlock(chan);
1268 if (ast_strlen_zero(data)) {
1269 ast_log(LOG_WARNING, "SayAlphaCase requires two arguments (options, characters)\n");
1273 parse = ast_strdupa(data);
1274 AST_STANDARD_APP_ARGS(args, parse);
1276 if (!args.options || strlen(args.options) != 1) {
1277 ast_log(LOG_WARNING, "SayAlphaCase options are mutually exclusive and required\n");
1281 switch (args.options[0]) {
1283 sensitivity = AST_SAY_CASE_ALL;
1286 sensitivity = AST_SAY_CASE_LOWER;
1289 sensitivity = AST_SAY_CASE_NONE;
1292 sensitivity = AST_SAY_CASE_UPPER;
1295 ast_log(LOG_WARNING, "Invalid option: '%s'\n", args.options);
1299 res = ast_say_character_str(chan, args.characters, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), sensitivity);
1304 static int pbx_builtin_saycharacters(struct ast_channel *chan, const char *data)
1308 const char *interrupt_string;
1310 ast_channel_lock(chan);
1311 interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
1312 if (ast_true(interrupt_string)) {
1315 ast_channel_unlock(chan);
1318 res = ast_say_character_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), AST_SAY_CASE_NONE);
1324 static int pbx_builtin_sayphonetic(struct ast_channel *chan, const char *data)
1328 const char *interrupt_string;
1330 ast_channel_lock(chan);
1331 interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
1332 if (ast_true(interrupt_string)) {
1335 ast_channel_unlock(chan);
1338 res = ast_say_phonetic_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan));
1342 static int pbx_builtin_importvar(struct ast_channel *chan, const char *data)
1347 char tmp[VAR_BUF_SIZE];
1348 static int deprecation_warning = 0;
1350 if (ast_strlen_zero(data)) {
1351 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
1355 if (!deprecation_warning) {
1356 ast_log(LOG_WARNING, "ImportVar is deprecated. Please use Set(varname=${IMPORT(channel,variable)}) instead.\n");
1357 deprecation_warning = 1;
1360 value = ast_strdupa(data);
1361 name = strsep(&value,"=");
1362 channel = strsep(&value,",");
1363 if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
1364 struct ast_channel *chan2 = ast_channel_get_by_name(channel);
1366 char *s = ast_alloca(strlen(value) + 4);
1367 sprintf(s, "${%s}", value);
1368 pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
1369 chan2 = ast_channel_unref(chan2);
1371 pbx_builtin_setvar_helper(chan, name, tmp);
1377 /*! \brief Declaration of builtin applications */
1378 struct pbx_builtin {
1379 char name[AST_MAX_APP];
1380 int (*execute)(struct ast_channel *chan, const char *data);
1383 /* These applications are built into the PBX core and do not
1384 need separate modules */
1386 { "Answer", pbx_builtin_answer },
1387 { "BackGround", pbx_builtin_background },
1388 { "Busy", indicate_busy },
1389 { "Congestion", indicate_congestion },
1390 { "ExecIfTime", pbx_builtin_execiftime },
1391 { "Goto", pbx_builtin_goto },
1392 { "GotoIf", pbx_builtin_gotoif },
1393 { "GotoIfTime", pbx_builtin_gotoiftime },
1394 { "ImportVar", pbx_builtin_importvar },
1395 { "Hangup", pbx_builtin_hangup },
1396 { "Incomplete", pbx_builtin_incomplete },
1397 { "NoOp", pbx_builtin_noop },
1398 { "Proceeding", pbx_builtin_proceeding },
1399 { "Progress", pbx_builtin_progress },
1400 { "RaiseException", pbx_builtin_raise_exception },
1401 { "Ringing", pbx_builtin_ringing },
1402 { "SayAlpha", pbx_builtin_saycharacters },
1403 { "SayAlphaCase", pbx_builtin_saycharacters_case },
1404 { "SayDigits", pbx_builtin_saydigits },
1405 { "SayNumber", pbx_builtin_saynumber },
1406 { "SayPhonetic", pbx_builtin_sayphonetic },
1407 { "SetAMAFlags", pbx_builtin_setamaflags },
1408 { "Wait", pbx_builtin_wait },
1409 { "WaitExten", pbx_builtin_waitexten }
1412 static void unload_pbx_builtins(void)
1416 /* Unregister builtin applications */
1417 for (x = 0; x < ARRAY_LEN(builtins); x++) {
1418 ast_unregister_application(builtins[x].name);
1422 int load_pbx_builtins(void)
1426 /* Register builtin applications */
1427 for (x = 0; x < ARRAY_LEN(builtins); x++) {
1428 if (ast_register_application2(builtins[x].name, builtins[x].execute, NULL, NULL, NULL)) {
1429 ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
1430 unload_pbx_builtins();
1435 ast_register_cleanup(unload_pbx_builtins);