Asterisk - The Open Source Telephony Project GIT-master-0deac78
res_agi.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2006, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
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.
13 *
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.
17 */
18
19/*! \file
20 *
21 * \brief AGI - the Asterisk Gateway Interface
22 *
23 * \author Mark Spencer <markster@digium.com>
24 *
25 */
26
27/*** MODULEINFO
28 <depend>res_speech</depend>
29 <support_level>core</support_level>
30 ***/
31
32#include "asterisk.h"
33
34#include <math.h>
35#include <signal.h>
36#include <sys/time.h>
37#include <sys/wait.h>
38#include <sys/stat.h>
39#include <pthread.h>
40
41#include "asterisk/paths.h" /* use many ast_config_AST_*_DIR */
42#include "asterisk/network.h"
43#include "asterisk/file.h"
44#include "asterisk/channel.h"
45#include "asterisk/pbx.h"
46#include "asterisk/module.h"
47#include "asterisk/astdb.h"
48#include "asterisk/callerid.h"
49#include "asterisk/cli.h"
50#include "asterisk/image.h"
51#include "asterisk/say.h"
52#include "asterisk/app.h"
53#include "asterisk/dsp.h"
55#include "asterisk/utils.h"
56#include "asterisk/lock.h"
57#include "asterisk/strings.h"
58#include "asterisk/manager.h"
60#include "asterisk/speech.h"
61#include "asterisk/manager.h"
62#include "asterisk/term.h"
63#include "asterisk/xmldoc.h"
64#include "asterisk/srv.h"
65#include "asterisk/test.h"
66#include "asterisk/netsock2.h"
70
71#define AST_API_MODULE
72#include "asterisk/agi.h"
73
74/*** DOCUMENTATION
75 <agi name="answer" language="en_US">
76 <since>
77 <version>0.4.0</version>
78 </since>
79 <synopsis>
80 Answer channel
81 </synopsis>
82 <syntax />
83 <description>
84 <para>Answers channel if not already in answer state. Returns <literal>-1</literal> on
85 channel failure, or <literal>0</literal> if successful.</para>
86 </description>
87 <see-also>
88 <ref type="agi">hangup</ref>
89 <ref type="application">AGI</ref>
90 </see-also>
91 </agi>
92 <agi name="asyncagi break" language="en_US">
93 <since>
94 <version>1.8.0</version>
95 </since>
96 <synopsis>
97 Interrupts Async AGI
98 </synopsis>
99 <syntax />
100 <description>
101 <para>Interrupts expected flow of Async AGI commands and returns control to previous source
102 (typically, the PBX dialplan).</para>
103 </description>
104 <see-also>
105 <ref type="agi">hangup</ref>
106 <ref type="application">AGI</ref>
107 </see-also>
108 </agi>
109 <agi name="channel status" language="en_US">
110 <since>
111 <version>0.4.0</version>
112 </since>
113 <synopsis>
114 Returns status of the connected channel.
115 </synopsis>
116 <syntax>
117 <parameter name="channelname" />
118 </syntax>
119 <description>
120 <para>Returns the status of the specified <replaceable>channelname</replaceable>.
121 If no channel name is given then returns the status of the current channel.</para>
122 <para>Return values:</para>
123 <enumlist>
124 <enum name="0">
125 <para>Channel is down and available.</para>
126 </enum>
127 <enum name="1">
128 <para>Channel is down, but reserved.</para>
129 </enum>
130 <enum name="2">
131 <para>Channel is off hook.</para>
132 </enum>
133 <enum name="3">
134 <para>Digits (or equivalent) have been dialed.</para>
135 </enum>
136 <enum name="4">
137 <para>Line is ringing.</para>
138 </enum>
139 <enum name="5">
140 <para>Remote end is ringing.</para>
141 </enum>
142 <enum name="6">
143 <para>Line is up.</para>
144 </enum>
145 <enum name="7">
146 <para>Line is busy.</para>
147 </enum>
148 </enumlist>
149 </description>
150 <see-also>
151 <ref type="application">AGI</ref>
152 </see-also>
153 </agi>
154 <agi name="control stream file" language="en_US">
155 <since>
156 <version>1.2.0</version>
157 </since>
158 <synopsis>
159 Sends audio file on channel and allows the listener to control the stream.
160 </synopsis>
161 <syntax>
162 <parameter name="filename" required="true">
163 <para>The file extension must not be included in the filename.</para>
164 </parameter>
165 <parameter name="escape_digits" required="true" />
166 <parameter name="skipms" />
167 <parameter name="ffchar">
168 <para>Defaults to <literal>#</literal></para>
169 </parameter>
170 <parameter name="rewchr">
171 <para>Defaults to <literal>*</literal></para>
172 </parameter>
173 <parameter name="pausechr" />
174 <parameter name="offsetms">
175 <para>Offset, in milliseconds, to start the audio playback</para>
176 </parameter>
177 </syntax>
178 <description>
179 <para>Send the given file, allowing playback to be controlled by the given
180 digits, if any. Use double quotes for the digits if you wish none to be
181 permitted. If offsetms is provided then the audio will seek to offsetms
182 before play starts. Returns <literal>0</literal> if playback completes without a digit
183 being pressed, or the ASCII numerical value of the digit if one was pressed,
184 or <literal>-1</literal> on error or if the channel was disconnected. Returns the
185 position where playback was terminated as endpos.</para>
186
187 <para>It sets the following channel variables upon completion:</para>
188 <variablelist>
189 <variable name="CPLAYBACKSTATUS">
190 <para>Contains the status of the attempt as a text string</para>
191 <value name="SUCCESS" />
192 <value name="USERSTOPPED" />
193 <value name="REMOTESTOPPED" />
194 <value name="ERROR" />
195 </variable>
196 <variable name="CPLAYBACKOFFSET">
197 <para>Contains the offset in ms into the file where playback
198 was at when it stopped. <literal>-1</literal> is end of file.</para>
199 </variable>
200 <variable name="CPLAYBACKSTOPKEY">
201 <para>If the playback is stopped by the user this variable contains
202 the key that was pressed.</para>
203 </variable>
204 </variablelist>
205 </description>
206 <see-also>
207 <ref type="agi">get option</ref>
208 <ref type="agi">control stream file</ref>
209 <ref type="application">AGI</ref>
210 </see-also>
211 </agi>
212 <agi name="database del" language="en_US">
213 <since>
214 <version>0.4.0</version>
215 </since>
216 <synopsis>
217 Removes database key/value
218 </synopsis>
219 <syntax>
220 <parameter name="family" required="true" />
221 <parameter name="key" required="true" />
222 </syntax>
223 <description>
224 <para>Deletes an entry in the Asterisk database for a given
225 <replaceable>family</replaceable> and <replaceable>key</replaceable>.</para>
226 <para>Returns <literal>1</literal> if successful, <literal>0</literal>
227 otherwise.</para>
228 </description>
229 <see-also>
230 <ref type="agi">database get</ref>
231 <ref type="agi">database put</ref>
232 <ref type="agi">database deltree</ref>
233 <ref type="application">AGI</ref>
234 </see-also>
235 </agi>
236 <agi name="database deltree" language="en_US">
237 <since>
238 <version>0.4.0</version>
239 </since>
240 <synopsis>
241 Removes database keytree/value
242 </synopsis>
243 <syntax>
244 <parameter name="family" required="true" />
245 <parameter name="keytree" />
246 </syntax>
247 <description>
248 <para>Deletes a <replaceable>family</replaceable> or specific <replaceable>keytree</replaceable>
249 within a <replaceable>family</replaceable> in the Asterisk database.</para>
250 <para>Returns <literal>1</literal> if successful, <literal>0</literal> otherwise.</para>
251 </description>
252 <see-also>
253 <ref type="agi">database get</ref>
254 <ref type="agi">database put</ref>
255 <ref type="agi">database del</ref>
256 <ref type="application">AGI</ref>
257 </see-also>
258 </agi>
259 <agi name="database get" language="en_US">
260 <since>
261 <version>0.4.0</version>
262 </since>
263 <synopsis>
264 Gets database value
265 </synopsis>
266 <syntax>
267 <parameter name="family" required="true" />
268 <parameter name="key" required="true" />
269 </syntax>
270 <description>
271 <para>Retrieves an entry in the Asterisk database for a given <replaceable>family</replaceable>
272 and <replaceable>key</replaceable>.</para>
273 <para>Returns <literal>0</literal> if <replaceable>key</replaceable> is not set.
274 Returns <literal>1</literal> if <replaceable>key</replaceable> is set and returns the variable
275 in parenthesis.</para>
276 <para>Example return code: 200 result=1 (testvariable)</para>
277 </description>
278 <see-also>
279 <ref type="agi">database put</ref>
280 <ref type="agi">database del</ref>
281 <ref type="agi">database deltree</ref>
282 <ref type="application">AGI</ref>
283 </see-also>
284 </agi>
285 <agi name="database put" language="en_US">
286 <since>
287 <version>0.4.0</version>
288 </since>
289 <synopsis>
290 Adds/updates database value
291 </synopsis>
292 <syntax>
293 <parameter name="family" required="true" />
294 <parameter name="key" required="true" />
295 <parameter name="value" required="true" />
296 </syntax>
297 <description>
298 <para>Adds or updates an entry in the Asterisk database for a given
299 <replaceable>family</replaceable>, <replaceable>key</replaceable>, and
300 <replaceable>value</replaceable>.</para>
301 <para>Returns <literal>1</literal> if successful, <literal>0</literal> otherwise.</para>
302 </description>
303 <see-also>
304 <ref type="agi">database get</ref>
305 <ref type="agi">database del</ref>
306 <ref type="agi">database deltree</ref>
307 <ref type="application">AGI</ref>
308 </see-also>
309 </agi>
310 <agi name="exec" language="en_US">
311 <since>
312 <version>0.4.0</version>
313 </since>
314 <synopsis>
315 Executes a given Application
316 </synopsis>
317 <syntax>
318 <parameter name="application" required="true" />
319 <parameter name="options" required="true" />
320 </syntax>
321 <description>
322 <para>Executes <replaceable>application</replaceable> with given
323 <replaceable>options</replaceable>.</para>
324 <para>Returns whatever the <replaceable>application</replaceable> returns, or
325 <literal>-2</literal> on failure to find <replaceable>application</replaceable>.</para>
326 <note>
327 <para>exec does not evaluate dialplan functions and variables unless it is explicitly enabled by setting the <variable>AGIEXECFULL</variable> variable to <literal>yes</literal>.</para>
328 </note>
329 </description>
330 <see-also>
331 <ref type="application">AGI</ref>
332 </see-also>
333 </agi>
334 <agi name="get data" language="en_US">
335 <since>
336 <version>0.4.0</version>
337 </since>
338 <synopsis>
339 Prompts for DTMF on a channel
340 </synopsis>
341 <syntax>
342 <parameter name="file" required="true" />
343 <parameter name="timeout" />
344 <parameter name="maxdigits" />
345 </syntax>
346 <description>
347 <para>Stream the given <replaceable>file</replaceable>, and receive DTMF data.</para>
348 <para>Returns the digits received from the channel at the other end.</para>
349 </description>
350 <see-also>
351 <ref type="application">AGI</ref>
352 </see-also>
353 </agi>
354 <agi name="get full variable" language="en_US">
355 <since>
356 <version>1.2.0</version>
357 </since>
358 <synopsis>
359 Evaluates a channel expression
360 </synopsis>
361 <syntax>
362 <parameter name="expression" required="true" />
363 <parameter name="channelname" />
364 </syntax>
365 <description>
366 <para>Evaluates the given <replaceable>expression</replaceable> against the
367 channel specified by <replaceable>channelname</replaceable>, or the current
368 channel if <replaceable>channelname</replaceable> is not provided.</para>
369 <para>Unlike GET VARIABLE, the <replaceable>expression</replaceable> is
370 processed in a manner similar to dialplan evaluation, allowing complex
371 and built-in variables to be accessed, e.g. <literal>The time is
372 ${EPOCH}</literal></para>
373 <para>Returns <literal>0</literal> if no channel matching
374 <replaceable>channelname</replaceable> exists, <literal>1</literal>
375 otherwise.</para>
376 <para>Example return code: 200 result=1 (The time is 1578493800)</para>
377 </description>
378 <see-also>
379 <ref type="agi">get variable</ref>
380 <ref type="agi">set variable</ref>
381 <ref type="application">AGI</ref>
382 </see-also>
383 </agi>
384 <agi name="get option" language="en_US">
385 <since>
386 <version>1.2.0</version>
387 </since>
388 <synopsis>
389 Stream file, prompt for DTMF, with timeout.
390 </synopsis>
391 <syntax>
392 <parameter name="filename" required="true" />
393 <parameter name="escape_digits" required="true" />
394 <parameter name="timeout" />
395 </syntax>
396 <description>
397 <para>Behaves similar to STREAM FILE but used with a timeout option.</para>
398 </description>
399 <see-also>
400 <ref type="agi">stream file</ref>
401 <ref type="agi">control stream file</ref>
402 <ref type="application">AGI</ref>
403 </see-also>
404 </agi>
405 <agi name="get variable" language="en_US">
406 <since>
407 <version>0.4.0</version>
408 </since>
409 <synopsis>
410 Gets a channel variable.
411 </synopsis>
412 <syntax>
413 <parameter name="variablename" required="true" />
414 </syntax>
415 <description>
416 <para>Returns <literal>0</literal> if <replaceable>variablename</replaceable> is not set.
417 Returns <literal>1</literal> if <replaceable>variablename</replaceable> is set and returns
418 the variable in parentheses.</para>
419 <para>Example return code: 200 result=1 (testvariable)</para>
420 </description>
421 <see-also>
422 <ref type="agi">get full variable</ref>
423 <ref type="agi">set variable</ref>
424 <ref type="application">AGI</ref>
425 </see-also>
426 </agi>
427 <agi name="hangup" language="en_US">
428 <since>
429 <version>0.4.0</version>
430 </since>
431 <synopsis>
432 Hangup a channel.
433 </synopsis>
434 <syntax>
435 <parameter name="channelname" />
436 </syntax>
437 <description>
438 <para>Hangs up the specified channel. If no channel name is given, hangs
439 up the current channel</para>
440 </description>
441 <see-also>
442 <ref type="application">AGI</ref>
443 </see-also>
444 </agi>
445 <agi name="noop" language="en_US">
446 <since>
447 <version>0.4.0</version>
448 </since>
449 <synopsis>
450 Does nothing.
451 </synopsis>
452 <syntax />
453 <description>
454 <para>Does nothing.</para>
455 </description>
456 <see-also>
457 <ref type="application">AGI</ref>
458 </see-also>
459 </agi>
460 <agi name="receive char" language="en_US">
461 <since>
462 <version>0.4.0</version>
463 </since>
464 <synopsis>
465 Receives one character from channels supporting it.
466 </synopsis>
467 <syntax>
468 <parameter name="timeout" required="true">
469 <para>The maximum time to wait for input in milliseconds, or <literal>0</literal>
470 for infinite. Most channels</para>
471 </parameter>
472 </syntax>
473 <description>
474 <para>Receives a character of text on a channel. Most channels do not support
475 the reception of text. Returns the decimal value of the character
476 if one is received, or <literal>0</literal> if the channel does not support
477 text reception. Returns <literal>-1</literal> only on error/hangup.</para>
478 </description>
479 <see-also>
480 <ref type="agi">receive text</ref>
481 <ref type="application">AGI</ref>
482 </see-also>
483 </agi>
484 <agi name="receive text" language="en_US">
485 <since>
486 <version>1.2.0</version>
487 </since>
488 <synopsis>
489 Receives text from channels supporting it.
490 </synopsis>
491 <syntax>
492 <parameter name="timeout" required="true">
493 <para>The timeout to be the maximum time to wait for input in
494 milliseconds, or <literal>0</literal> for infinite.</para>
495 </parameter>
496 </syntax>
497 <description>
498 <para>Receives a string of text on a channel. Most channels
499 do not support the reception of text. Returns <literal>-1</literal> for failure
500 or <literal>1</literal> for success, and the string in parenthesis.</para>
501 </description>
502 <see-also>
503 <ref type="agi">receive char</ref>
504 <ref type="agi">send text</ref>
505 <ref type="application">AGI</ref>
506 </see-also>
507 </agi>
508 <agi name="record file" language="en_US">
509 <since>
510 <version>0.4.0</version>
511 </since>
512 <synopsis>
513 Records to a given file.
514 </synopsis>
515 <syntax>
516 <parameter name="filename" required="true">
517 <para>The destination filename of the recorded audio.</para>
518 </parameter>
519 <parameter name="format" required="true">
520 <para>The audio format in which to save the resulting file.</para>
521 </parameter>
522 <parameter name="escape_digits" required="true">
523 <para>The DTMF digits that will terminate the recording process.</para>
524 </parameter>
525 <parameter name="timeout" required="true">
526 <para>The maximum recording time in milliseconds. Set to -1 for no
527 limit.</para>
528 </parameter>
529 <parameter name="offset_samples">
530 <para>Causes the recording to first seek to the specified offset before
531 recording begins.</para>
532 </parameter>
533 <parameter name="beep">
534 <para>Causes Asterisk to play a beep as recording begins. This argument
535 can take any value.</para>
536 </parameter>
537 <parameter name="s=silence">
538 <para>The number of seconds of silence that are permitted before the
539 recording is terminated, regardless of the
540 <replaceable>escape_digits</replaceable> or <replaceable>timeout</replaceable>
541 arguments. If specified, this parameter must be preceded by
542 <literal>s=</literal>.</para>
543 </parameter>
544 </syntax>
545 <description>
546 <para>Record to a file until a given dtmf digit in the sequence is received.
547 Returns <literal>-1</literal> on hangup or error. The format will specify what kind of file
548 will be recorded. The <replaceable>timeout</replaceable> is the maximum record time in
549 milliseconds, or <literal>-1</literal> for no <replaceable>timeout</replaceable>.
550 <replaceable>offset samples</replaceable> is optional, and, if provided, will seek
551 to the offset without exceeding the end of the
552 file. <replaceable>beep</replaceable> can take any value, and causes Asterisk
553 to play a beep to the channel that is about to be recorded. <replaceable>silence</replaceable> is
554 the number of seconds of silence allowed before the function returns despite the
555 lack of dtmf digits or reaching <replaceable>timeout</replaceable>. <replaceable>silence</replaceable>
556 value must be preceded by <literal>s=</literal> and is also optional.</para>
557 </description>
558 <see-also>
559 <ref type="application">AGI</ref>
560 </see-also>
561 </agi>
562 <agi name="say alpha" language="en_US">
563 <since>
564 <version>1.2.0</version>
565 </since>
566 <synopsis>
567 Says a given character string.
568 </synopsis>
569 <syntax>
570 <parameter name="number" required="true" />
571 <parameter name="escape_digits" required="true" />
572 </syntax>
573 <description>
574 <para>Say a given character string, returning early if any of the given DTMF digits
575 are received on the channel. Returns <literal>0</literal> if playback completes
576 without a digit being pressed, or the ASCII numerical value of the digit if one
577 was pressed or <literal>-1</literal> on error/hangup.</para>
578 </description>
579 <see-also>
580 <ref type="agi">say digits</ref>
581 <ref type="agi">say number</ref>
582 <ref type="agi">say phonetic</ref>
583 <ref type="agi">say date</ref>
584 <ref type="agi">say time</ref>
585 <ref type="agi">say datetime</ref>
586 <ref type="application">AGI</ref>
587 </see-also>
588 </agi>
589 <agi name="say digits" language="en_US">
590 <since>
591 <version>0.4.0</version>
592 </since>
593 <synopsis>
594 Says a given digit string.
595 </synopsis>
596 <syntax>
597 <parameter name="number" required="true" />
598 <parameter name="escape_digits" required="true" />
599 </syntax>
600 <description>
601 <para>Say a given digit string, returning early if any of the given DTMF digits
602 are received on the channel. Returns <literal>0</literal> if playback completes
603 without a digit being pressed, or the ASCII numerical value of the digit if one
604 was pressed or <literal>-1</literal> on error/hangup.</para>
605 </description>
606 <see-also>
607 <ref type="agi">say alpha</ref>
608 <ref type="agi">say number</ref>
609 <ref type="agi">say phonetic</ref>
610 <ref type="agi">say date</ref>
611 <ref type="agi">say time</ref>
612 <ref type="agi">say datetime</ref>
613 <ref type="application">AGI</ref>
614 </see-also>
615 </agi>
616 <agi name="say number" language="en_US">
617 <since>
618 <version>0.4.0</version>
619 </since>
620 <synopsis>
621 Says a given number.
622 </synopsis>
623 <syntax>
624 <parameter name="number" required="true" />
625 <parameter name="escape_digits" required="true" />
626 <parameter name="gender" />
627 </syntax>
628 <description>
629 <para>Say a given number, returning early if any of the given DTMF digits
630 are received on the channel. Returns <literal>0</literal> if playback
631 completes without a digit being pressed, or the ASCII numerical value of
632 the digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
633 </description>
634 <see-also>
635 <ref type="agi">say alpha</ref>
636 <ref type="agi">say digits</ref>
637 <ref type="agi">say phonetic</ref>
638 <ref type="agi">say date</ref>
639 <ref type="agi">say time</ref>
640 <ref type="agi">say datetime</ref>
641 <ref type="application">AGI</ref>
642 </see-also>
643 </agi>
644 <agi name="say phonetic" language="en_US">
645 <since>
646 <version>1.0.0</version>
647 </since>
648 <synopsis>
649 Says a given character string with phonetics.
650 </synopsis>
651 <syntax>
652 <parameter name="string" required="true" />
653 <parameter name="escape_digits" required="true" />
654 </syntax>
655 <description>
656 <para>Say a given character string with phonetics, returning early if any of the
657 given DTMF digits are received on the channel. Returns <literal>0</literal> if
658 playback completes without a digit pressed, the ASCII numerical value of the digit
659 if one was pressed, or <literal>-1</literal> on error/hangup.</para>
660 </description>
661 <see-also>
662 <ref type="agi">say alpha</ref>
663 <ref type="agi">say digits</ref>
664 <ref type="agi">say number</ref>
665 <ref type="agi">say date</ref>
666 <ref type="agi">say time</ref>
667 <ref type="agi">say datetime</ref>
668 <ref type="application">AGI</ref>
669 </see-also>
670 </agi>
671 <agi name="say date" language="en_US">
672 <since>
673 <version>1.2.0</version>
674 </since>
675 <synopsis>
676 Says a given date.
677 </synopsis>
678 <syntax>
679 <parameter name="date" required="true">
680 <para>Is number of seconds elapsed since 00:00:00 on January 1, 1970.
681 Coordinated Universal Time (UTC).</para>
682 </parameter>
683 <parameter name="escape_digits" required="true" />
684 </syntax>
685 <description>
686 <para>Say a given date, returning early if any of the given DTMF digits are
687 received on the channel. Returns <literal>0</literal> if playback
688 completes without a digit being pressed, or the ASCII numerical value of the
689 digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
690 </description>
691 <see-also>
692 <ref type="agi">say alpha</ref>
693 <ref type="agi">say digits</ref>
694 <ref type="agi">say number</ref>
695 <ref type="agi">say phonetic</ref>
696 <ref type="agi">say time</ref>
697 <ref type="agi">say datetime</ref>
698 <ref type="application">AGI</ref>
699 </see-also>
700 </agi>
701 <agi name="say time" language="en_US">
702 <since>
703 <version>1.0.0</version>
704 </since>
705 <synopsis>
706 Says a given time.
707 </synopsis>
708 <syntax>
709 <parameter name="time" required="true">
710 <para>Is number of seconds elapsed since 00:00:00 on January 1, 1970.
711 Coordinated Universal Time (UTC).</para>
712 </parameter>
713 <parameter name="escape_digits" required="true" />
714 </syntax>
715 <description>
716 <para>Say a given time, returning early if any of the given DTMF digits are
717 received on the channel. Returns <literal>0</literal> if playback completes
718 without a digit being pressed, or the ASCII numerical value of the digit if
719 one was pressed or <literal>-1</literal> on error/hangup.</para>
720 </description>
721 <see-also>
722 <ref type="agi">say alpha</ref>
723 <ref type="agi">say digits</ref>
724 <ref type="agi">say number</ref>
725 <ref type="agi">say phonetic</ref>
726 <ref type="agi">say date</ref>
727 <ref type="agi">say datetime</ref>
728 <ref type="application">AGI</ref>
729 </see-also>
730 </agi>
731 <agi name="say datetime" language="en_US">
732 <since>
733 <version>1.2.0</version>
734 </since>
735 <synopsis>
736 Says a given time as specified by the format given.
737 </synopsis>
738 <syntax>
739 <parameter name="time" required="true">
740 <para>Is number of seconds elapsed since 00:00:00
741 on January 1, 1970, Coordinated Universal Time (UTC)</para>
742 </parameter>
743 <parameter name="escape_digits" required="true" />
744 <parameter name="format">
745 <para>Is the format the time should be said in. See
746 <filename>voicemail.conf</filename> (defaults to <literal>ABdY
747 'digits/at' IMp</literal>).</para>
748 </parameter>
749 <parameter name="timezone">
750 <para>Acceptable values can be found in <filename>/usr/share/zoneinfo</filename>
751 Defaults to machine default.</para>
752 </parameter>
753 </syntax>
754 <description>
755 <para>Say a given time, returning early if any of the given DTMF digits are
756 received on the channel. Returns <literal>0</literal> if playback
757 completes without a digit being pressed, or the ASCII numerical value of the
758 digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
759 </description>
760 <see-also>
761 <ref type="agi">say alpha</ref>
762 <ref type="agi">say digits</ref>
763 <ref type="agi">say number</ref>
764 <ref type="agi">say phonetic</ref>
765 <ref type="agi">say date</ref>
766 <ref type="agi">say time</ref>
767 <ref type="application">AGI</ref>
768 </see-also>
769 </agi>
770 <agi name="send image" language="en_US">
771 <since>
772 <version>0.4.0</version>
773 </since>
774 <synopsis>
775 Sends images to channels supporting it.
776 </synopsis>
777 <syntax>
778 <parameter name="image" required="true" />
779 </syntax>
780 <description>
781 <para>Sends the given image on a channel. Most channels do not support the
782 transmission of images. Returns <literal>0</literal> if image is sent, or if
783 the channel does not support image transmission. Returns <literal>-1</literal>
784 only on error/hangup. Image names should not include extensions.</para>
785 </description>
786 <see-also>
787 <ref type="application">AGI</ref>
788 </see-also>
789 </agi>
790 <agi name="send text" language="en_US">
791 <since>
792 <version>0.4.0</version>
793 </since>
794 <synopsis>
795 Sends text to channels supporting it.
796 </synopsis>
797 <syntax>
798 <parameter name="text to send" required="true">
799 <para>Text consisting of greater than one word should be placed
800 in quotes since the command only accepts a single argument.</para>
801 </parameter>
802 </syntax>
803 <description>
804 <para>Sends the given text on a channel. Most channels do not support the
805 transmission of text. Returns <literal>0</literal> if text is sent, or if the
806 channel does not support text transmission. Returns <literal>-1</literal> only
807 on error/hangup.</para>
808 </description>
809 <see-also>
810 <ref type="agi">receive text</ref>
811 <ref type="application">AGI</ref>
812 </see-also>
813 </agi>
814 <agi name="set autohangup" language="en_US">
815 <since>
816 <version>0.4.0</version>
817 </since>
818 <synopsis>
819 Autohangup channel in some time.
820 </synopsis>
821 <syntax>
822 <parameter name="time" required="true" />
823 </syntax>
824 <description>
825 <para>Cause the channel to automatically hangup at <replaceable>time</replaceable>
826 seconds in the future. Of course it can be hungup before then as well. Setting to
827 <literal>0</literal> will cause the autohangup feature to be disabled on this channel.</para>
828 </description>
829 <see-also>
830 <ref type="application">AGI</ref>
831 </see-also>
832 </agi>
833 <agi name="set callerid" language="en_US">
834 <since>
835 <version>0.4.0</version>
836 </since>
837 <synopsis>
838 Sets callerid for the current channel.
839 </synopsis>
840 <syntax>
841 <parameter name="number" required="true" />
842 </syntax>
843 <description>
844 <para>Changes the callerid of the current channel.</para>
845 </description>
846 <see-also>
847 <ref type="application">AGI</ref>
848 </see-also>
849 </agi>
850 <agi name="set context" language="en_US">
851 <since>
852 <version>0.4.0</version>
853 </since>
854 <synopsis>
855 Sets channel context.
856 </synopsis>
857 <syntax>
858 <parameter name="desired context" required="true" />
859 </syntax>
860 <description>
861 <para>Sets the context for continuation upon exiting the application.</para>
862 </description>
863 <see-also>
864 <ref type="agi">set extension</ref>
865 <ref type="agi">set priority</ref>
866 <ref type="application">AGI</ref>
867 </see-also>
868 </agi>
869 <agi name="set extension" language="en_US">
870 <since>
871 <version>0.4.0</version>
872 </since>
873 <synopsis>
874 Changes channel extension.
875 </synopsis>
876 <syntax>
877 <parameter name="new extension" required="true" />
878 </syntax>
879 <description>
880 <para>Changes the extension for continuation upon exiting the application.</para>
881 </description>
882 <see-also>
883 <ref type="agi">set context</ref>
884 <ref type="agi">set priority</ref>
885 <ref type="application">AGI</ref>
886 </see-also>
887 </agi>
888 <agi name="set music" language="en_US">
889 <since>
890 <version>0.5.0</version>
891 </since>
892 <synopsis>
893 Enable/Disable Music on hold generator
894 </synopsis>
895 <syntax>
896 <parameter name="boolean" required="true">
897 <enumlist>
898 <enum name="on" />
899 <enum name="off" />
900 </enumlist>
901 </parameter>
902 <parameter name="class" required="true" />
903 </syntax>
904 <description>
905 <para>Enables/Disables the music on hold generator. If <replaceable>class</replaceable>
906 is not specified, then the <literal>default</literal> music on hold class will be
907 used. This generator will be stopped automatically when playing a file.</para>
908 <para>Always returns <literal>0</literal>.</para>
909 </description>
910 <see-also>
911 <ref type="application">AGI</ref>
912 </see-also>
913 </agi>
914 <agi name="set priority" language="en_US">
915 <since>
916 <version>0.4.0</version>
917 </since>
918 <synopsis>
919 Set channel dialplan priority.
920 </synopsis>
921 <syntax>
922 <parameter name="priority" required="true" />
923 </syntax>
924 <description>
925 <para>Changes the priority for continuation upon exiting the application.
926 The priority must be a valid priority or label.</para>
927 </description>
928 <see-also>
929 <ref type="agi">set context</ref>
930 <ref type="agi">set extension</ref>
931 <ref type="application">AGI</ref>
932 </see-also>
933 </agi>
934 <agi name="set variable" language="en_US">
935 <since>
936 <version>0.4.0</version>
937 </since>
938 <synopsis>
939 Sets a channel variable.
940 </synopsis>
941 <syntax>
942 <parameter name="variablename" required="true" />
943 <parameter name="value" required="true" />
944 </syntax>
945 <description>
946 <para>Sets a variable to the current channel.</para>
947 </description>
948 <see-also>
949 <ref type="agi">get variable</ref>
950 <ref type="agi">get full variable</ref>
951 <ref type="application">AGI</ref>
952 </see-also>
953 </agi>
954 <agi name="stream file" language="en_US">
955 <since>
956 <version>0.4.0</version>
957 </since>
958 <synopsis>
959 Sends audio file on channel.
960 </synopsis>
961 <syntax>
962 <parameter name="filename" required="true">
963 <para>File name to play. The file extension must not be
964 included in the <replaceable>filename</replaceable>.</para>
965 </parameter>
966 <parameter name="escape_digits" required="true">
967 <para>Use double quotes for the digits if you wish none to be
968 permitted.</para>
969 </parameter>
970 <parameter name="sample offset">
971 <para>If sample offset is provided then the audio will seek to sample
972 offset before play starts.</para>
973 </parameter>
974 </syntax>
975 <description>
976 <para>Send the given file, allowing playback to be interrupted by the given
977 digits, if any. Returns <literal>0</literal> if playback completes without a digit
978 being pressed, or the ASCII numerical value of the digit if one was pressed,
979 or <literal>-1</literal> on error or if the channel was disconnected. If
980 musiconhold is playing before calling stream file it will be automatically
981 stopped and will not be restarted after completion.</para>
982 <para>It sets the following channel variables upon completion:</para>
983 <variablelist>
984 <variable name="PLAYBACKSTATUS">
985 <para>The status of the playback attempt as a text string.</para>
986 <value name="SUCCESS"/>
987 <value name="FAILED"/>
988 </variable>
989 </variablelist>
990 </description>
991 <see-also>
992 <ref type="agi">control stream file</ref>
993 <ref type="agi">get option</ref>
994 <ref type="application">AGI</ref>
995 </see-also>
996 </agi>
997 <agi name="tdd mode" language="en_US">
998 <since>
999 <version>0.4.0</version>
1000 </since>
1001 <synopsis>
1002 Toggles TDD mode (for the deaf).
1003 </synopsis>
1004 <syntax>
1005 <parameter name="boolean" required="true">
1006 <enumlist>
1007 <enum name="on" />
1008 <enum name="off" />
1009 </enumlist>
1010 </parameter>
1011 </syntax>
1012 <description>
1013 <para>Enable/Disable TDD transmission/reception on a channel. Returns <literal>1</literal> if
1014 successful, or <literal>0</literal> if channel is not TDD-capable.</para>
1015 </description>
1016 <see-also>
1017 <ref type="application">AGI</ref>
1018 </see-also>
1019 </agi>
1020 <agi name="verbose" language="en_US">
1021 <since>
1022 <version>0.4.0</version>
1023 </since>
1024 <synopsis>
1025 Logs a message to the asterisk verbose log.
1026 </synopsis>
1027 <syntax>
1028 <parameter name="message" required="true" />
1029 <parameter name="level" required="true" />
1030 </syntax>
1031 <description>
1032 <para>Sends <replaceable>message</replaceable> to the console via verbose
1033 message system. <replaceable>level</replaceable> is the verbose level (1-4).
1034 Always returns <literal>1</literal></para>
1035 </description>
1036 <see-also>
1037 <ref type="application">AGI</ref>
1038 </see-also>
1039 </agi>
1040 <agi name="wait for digit" language="en_US">
1041 <since>
1042 <version>0.4.0</version>
1043 </since>
1044 <synopsis>
1045 Waits for a digit to be pressed.
1046 </synopsis>
1047 <syntax>
1048 <parameter name="timeout" required="true" />
1049 </syntax>
1050 <description>
1051 <para>Waits up to <replaceable>timeout</replaceable> milliseconds for channel to
1052 receive a DTMF digit. Returns <literal>-1</literal> on channel failure, <literal>0</literal>
1053 if no digit is received in the timeout, or the numerical value of the ascii of the digit if
1054 one is received. Use <literal>-1</literal> for the <replaceable>timeout</replaceable> value if
1055 you desire the call to block indefinitely.</para>
1056 </description>
1057 <see-also>
1058 <ref type="application">AGI</ref>
1059 </see-also>
1060 </agi>
1061 <agi name="speech create" language="en_US">
1062 <since>
1063 <version>1.6.0</version>
1064 </since>
1065 <synopsis>
1066 Creates a speech object.
1067 </synopsis>
1068 <syntax>
1069 <parameter name="engine" required="true" />
1070 </syntax>
1071 <description>
1072 <para>Create a speech object to be used by the other Speech AGI commands.</para>
1073 </description>
1074 <see-also>
1075 <ref type="agi">speech set</ref>
1076 <ref type="agi">speech destroy</ref>
1077 <ref type="agi">speech load grammar</ref>
1078 <ref type="agi">speech unload grammar</ref>
1079 <ref type="agi">speech activate grammar</ref>
1080 <ref type="agi">speech deactivate grammar</ref>
1081 <ref type="agi">speech recognize</ref>
1082 <ref type="application">AGI</ref>
1083 </see-also>
1084 </agi>
1085 <agi name="speech set" language="en_US">
1086 <since>
1087 <version>1.6.0</version>
1088 </since>
1089 <synopsis>
1090 Sets a speech engine setting.
1091 </synopsis>
1092 <syntax>
1093 <parameter name="name" required="true" />
1094 <parameter name="value" required="true" />
1095 </syntax>
1096 <description>
1097 <para>Set an engine-specific setting.</para>
1098 </description>
1099 <see-also>
1100 <ref type="agi">speech create</ref>
1101 <ref type="agi">speech destroy</ref>
1102 <ref type="agi">speech load grammar</ref>
1103 <ref type="agi">speech unload grammar</ref>
1104 <ref type="agi">speech activate grammar</ref>
1105 <ref type="agi">speech deactivate grammar</ref>
1106 <ref type="agi">speech recognize</ref>
1107 <ref type="application">AGI</ref>
1108 </see-also>
1109 </agi>
1110 <agi name="speech destroy" language="en_US">
1111 <since>
1112 <version>1.6.0</version>
1113 </since>
1114 <synopsis>
1115 Destroys a speech object.
1116 </synopsis>
1117 <syntax>
1118 </syntax>
1119 <description>
1120 <para>Destroy the speech object created by <literal>SPEECH CREATE</literal>.</para>
1121 </description>
1122 <see-also>
1123 <ref type="agi">speech create</ref>
1124 <ref type="agi">speech set</ref>
1125 <ref type="agi">speech load grammar</ref>
1126 <ref type="agi">speech unload grammar</ref>
1127 <ref type="agi">speech activate grammar</ref>
1128 <ref type="agi">speech deactivate grammar</ref>
1129 <ref type="agi">speech recognize</ref>
1130 <ref type="application">AGI</ref>
1131 </see-also>
1132 </agi>
1133 <agi name="speech load grammar" language="en_US">
1134 <since>
1135 <version>1.6.0</version>
1136 </since>
1137 <synopsis>
1138 Loads a grammar.
1139 </synopsis>
1140 <syntax>
1141 <parameter name="grammar name" required="true" />
1142 <parameter name="path to grammar" required="true" />
1143 </syntax>
1144 <description>
1145 <para>Loads the specified grammar as the specified name.</para>
1146 </description>
1147 <see-also>
1148 <ref type="agi">speech create</ref>
1149 <ref type="agi">speech set</ref>
1150 <ref type="agi">speech destroy</ref>
1151 <ref type="agi">speech unload grammar</ref>
1152 <ref type="agi">speech activate grammar</ref>
1153 <ref type="agi">speech deactivate grammar</ref>
1154 <ref type="agi">speech recognize</ref>
1155 <ref type="application">AGI</ref>
1156 </see-also>
1157 </agi>
1158 <agi name="speech unload grammar" language="en_US">
1159 <since>
1160 <version>1.6.0</version>
1161 </since>
1162 <synopsis>
1163 Unloads a grammar.
1164 </synopsis>
1165 <syntax>
1166 <parameter name="grammar name" required="true" />
1167 </syntax>
1168 <description>
1169 <para>Unloads the specified grammar.</para>
1170 </description>
1171 <see-also>
1172 <ref type="agi">speech create</ref>
1173 <ref type="agi">speech set</ref>
1174 <ref type="agi">speech destroy</ref>
1175 <ref type="agi">speech load grammar</ref>
1176 <ref type="agi">speech activate grammar</ref>
1177 <ref type="agi">speech deactivate grammar</ref>
1178 <ref type="agi">speech recognize</ref>
1179 <ref type="application">AGI</ref>
1180 </see-also>
1181 </agi>
1182 <agi name="speech activate grammar" language="en_US">
1183 <since>
1184 <version>1.6.0</version>
1185 </since>
1186 <synopsis>
1187 Activates a grammar.
1188 </synopsis>
1189 <syntax>
1190 <parameter name="grammar name" required="true" />
1191 </syntax>
1192 <description>
1193 <para>Activates the specified grammar on the speech object.</para>
1194 </description>
1195 <see-also>
1196 <ref type="agi">speech create</ref>
1197 <ref type="agi">speech set</ref>
1198 <ref type="agi">speech destroy</ref>
1199 <ref type="agi">speech load grammar</ref>
1200 <ref type="agi">speech unload grammar</ref>
1201 <ref type="agi">speech deactivate grammar</ref>
1202 <ref type="agi">speech recognize</ref>
1203 <ref type="application">AGI</ref>
1204 </see-also>
1205 </agi>
1206 <agi name="speech deactivate grammar" language="en_US">
1207 <since>
1208 <version>1.6.0</version>
1209 </since>
1210 <synopsis>
1211 Deactivates a grammar.
1212 </synopsis>
1213 <syntax>
1214 <parameter name="grammar name" required="true" />
1215 </syntax>
1216 <description>
1217 <para>Deactivates the specified grammar on the speech object.</para>
1218 </description>
1219 <see-also>
1220 <ref type="agi">speech create</ref>
1221 <ref type="agi">speech set</ref>
1222 <ref type="agi">speech destroy</ref>
1223 <ref type="agi">speech load grammar</ref>
1224 <ref type="agi">speech unload grammar</ref>
1225 <ref type="agi">speech activate grammar</ref>
1226 <ref type="agi">speech recognize</ref>
1227 <ref type="application">AGI</ref>
1228 </see-also>
1229 </agi>
1230 <agi name="speech recognize" language="en_US">
1231 <since>
1232 <version>1.6.0</version>
1233 </since>
1234 <synopsis>
1235 Recognizes speech.
1236 </synopsis>
1237 <syntax>
1238 <parameter name="prompt" required="true" />
1239 <parameter name="timeout" required="true" />
1240 <parameter name="offset" />
1241 </syntax>
1242 <description>
1243 <para>Plays back given <replaceable>prompt</replaceable> while listening for
1244 speech and dtmf.</para>
1245 </description>
1246 <see-also>
1247 <ref type="agi">speech create</ref>
1248 <ref type="agi">speech set</ref>
1249 <ref type="agi">speech destroy</ref>
1250 <ref type="agi">speech load grammar</ref>
1251 <ref type="agi">speech unload grammar</ref>
1252 <ref type="agi">speech activate grammar</ref>
1253 <ref type="agi">speech deactivate grammar</ref>
1254 <ref type="application">AGI</ref>
1255 </see-also>
1256 </agi>
1257 <application name="AGI" language="en_US">
1258 <since>
1259 <version>0.1.9</version>
1260 </since>
1261 <synopsis>
1262 Executes an AGI compliant application.
1263 </synopsis>
1264 <syntax>
1265 <parameter name="command" required="true">
1266 <para>How AGI should be invoked on the channel.</para>
1267 </parameter>
1268 <parameter name="args">
1269 <para>Arguments to pass to the AGI script or server.</para>
1270 <argument name="arg1" required="true" />
1271 <argument name="arg2" multiple="yes" />
1272 </parameter>
1273 </syntax>
1274 <description>
1275 <para>Executes an Asterisk Gateway Interface compliant
1276 program on a channel. AGI allows Asterisk to launch external programs written
1277 in any language to control a telephony channel, play audio, read DTMF digits,
1278 etc. by communicating with the AGI protocol.</para>
1279 <para>The following variants of AGI exist, and are chosen based on the value
1280 passed to <replaceable>command</replaceable>:</para>
1281 <enumlist>
1282 <enum name="AGI">
1283 <para>The classic variant of AGI, this will launch the script
1284 specified by <replaceable>command</replaceable> as a new process.
1285 Communication with the script occurs on <literal>stdin</literal> and
1286 <literal>stdout</literal>. If the full path to the script is not
1287 provided, the <directory>astagidir</directory> specified in
1288 <filename>asterisk.conf</filename> will be used.
1289 </para>
1290 </enum>
1291 <enum name="FastAGI">
1292 <para>Connect Asterisk to a FastAGI server using a TCP connection.
1293 The URI to the FastAGI server should be given in the form
1294 <literal>[scheme]://host.domain[:port][/script/name]</literal>,
1295 where <replaceable>scheme</replaceable> is either <literal>agi</literal>
1296 or <literal>hagi</literal>.</para>
1297 <para>In the case of <literal>hagi</literal>, an SRV lookup will be
1298 performed to try to connect to a list of FastAGI servers. The hostname in
1299 the URI must be prefixed with <literal>_agi._tcp</literal>. prior to the DNS resolution. For
1300 example, if you specify the URI <literal>hagi://agi.example.com/foo.agi</literal>
1301 the DNS query would be for <literal>_agi._tcp.agi.example.com</literal>. You
1302 will need to make sure this resolves correctly.</para>
1303 </enum>
1304 <enum name="AsyncAGI">
1305 <para>Use AMI to control the channel in AGI. AGI commands can be invoked
1306 using the <literal>AMI</literal> action, with a variety of AGI specific
1307 events passed back over the AMI connection. AsyncAGI should be invoked
1308 by passing <literal>agi:async</literal> to the <replaceable>command</replaceable>
1309 parameter.</para>
1310 </enum>
1311 </enumlist>
1312 <note>
1313 <para>As of <literal>1.6.0</literal>, this channel will
1314 not stop dialplan execution on hangup inside of this application. Dialplan
1315 execution will continue normally, even upon hangup until the AGI application
1316 signals a desire to stop (either by exiting or, in the case of a net script, by
1317 closing the connection).</para>
1318 <para>A locally executed AGI script will receive <literal>SIGHUP</literal> on
1319 hangup from the channel, except when it is already hung up. A fast AGI server will
1320 correspondingly receive a <literal>HANGUP</literal> inline with the command dialog.
1321 Both of these signals may be disabled by setting the <variable>AGISIGHUP</variable>
1322 channel variable to <literal>no</literal> before executing the AGI application.
1323 Alternatively, if you would like the AGI application to exit immediately
1324 after a channel hangup is detected, set the <variable>AGIEXITONHANGUP</variable>
1325 variable to <literal>yes</literal>.</para>
1326 </note>
1327 <example title="Start the AGI script /tmp/my-cool-script.sh, passing it the contents of the channel variable FOO">
1328 same => n,AGI(/tmp/my-cool-script.sh,${FOO})
1329 </example>
1330 <example title="Start the AGI script my-cool-script.sh located in the astagidir directory, specified in asterisk.conf">
1331 same => n,AGI(my-cool-script.sh)
1332 </example>
1333 <example title="Connect to the FastAGI server located at 127.0.0.1 and start the script awesome-script">
1334 same => n,AGI(agi://127.0.0.1/awesome-script)
1335 </example>
1336 <example title="Start AsyncAGI">
1337 same => n,AGI(agi:async)
1338 </example>
1339 <para>This application sets the following channel variable upon completion:</para>
1340 <variablelist>
1341 <variable name="AGISTATUS">
1342 <para>The status of the attempt to the run the AGI script
1343 text string, one of:</para>
1344 <value name="SUCCESS" />
1345 <value name="FAILURE" />
1346 <value name="NOTFOUND" />
1347 <value name="HANGUP" />
1348 </variable>
1349 </variablelist>
1350 </description>
1351 <see-also>
1352 <ref type="manager">AGI</ref>
1353 <ref type="managerEvent">AsyncAGIStart</ref>
1354 <ref type="managerEvent">AsyncAGIEnd</ref>
1355 <ref type="application">EAGI</ref>
1356 <ref type="filename">asterisk.conf</ref>
1357 </see-also>
1358 </application>
1359 <application name="EAGI" language="en_US">
1360 <since>
1361 <version>0.4.0</version>
1362 </since>
1363 <synopsis>
1364 Executes an EAGI compliant application.
1365 </synopsis>
1366 <syntax>
1367 <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='command'])" />
1368 <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='args'])" />
1369 </syntax>
1370 <description>
1371 <para>Using 'EAGI' provides enhanced AGI, with incoming audio available out of band
1372 on file descriptor 3. In all other respects, it behaves in the same fashion as
1373 AGI. See the documentation for the <literal>AGI</literal> dialplan application for
1374 more information on invoking AGI on a channel.</para>
1375 <para>This application sets the following channel variable upon completion:</para>
1376 <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/variablelist)" />
1377 </description>
1378 <see-also>
1379 <ref type="application">AGI</ref>
1380 </see-also>
1381 </application>
1382 <manager name="AGI" language="en_US">
1383 <since>
1384 <version>1.6.0</version>
1385 </since>
1386 <synopsis>
1387 Add an AGI command to execute by Async AGI.
1388 </synopsis>
1389 <syntax>
1390 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1391 <parameter name="Channel" required="true">
1392 <para>Channel that is currently in Async AGI.</para>
1393 </parameter>
1394 <parameter name="Command" required="true">
1395 <para>Application to execute.</para>
1396 </parameter>
1397 <parameter name="CommandID">
1398 <para>This will be sent back in CommandID header of AsyncAGI exec
1399 event notification.</para>
1400 </parameter>
1401 </syntax>
1402 <description>
1403 <para>Add an AGI command to the execute queue of the channel in Async AGI.</para>
1404 </description>
1405 <see-also>
1406 <ref type="managerEvent">AsyncAGIStart</ref>
1407 <ref type="managerEvent">AsyncAGIExec</ref>
1408 <ref type="managerEvent">AsyncAGIEnd</ref>
1409 </see-also>
1410 </manager>
1411 <managerEvent language="en_US" name="AsyncAGIStart">
1412 <managerEventInstance class="EVENT_FLAG_AGI">
1413 <since>
1414 <version>12.0.0</version>
1415 </since>
1416 <synopsis>Raised when a channel starts AsyncAGI command processing.</synopsis>
1417 <syntax>
1418 <channel_snapshot/>
1419 <parameter name="Env">
1420 <para>URL encoded string read from the AsyncAGI server.</para>
1421 </parameter>
1422 </syntax>
1423 <see-also>
1424 <ref type="managerEvent">AsyncAGIEnd</ref>
1425 <ref type="managerEvent">AsyncAGIExec</ref>
1426 <ref type="application">AGI</ref>
1427 <ref type="manager">AGI</ref>
1428 </see-also>
1429 </managerEventInstance>
1430 </managerEvent>
1431 <managerEvent language="en_US" name="AsyncAGIEnd">
1432 <managerEventInstance class="EVENT_FLAG_AGI">
1433 <since>
1434 <version>12.0.0</version>
1435 </since>
1436 <synopsis>Raised when a channel stops AsyncAGI command processing.</synopsis>
1437 <syntax>
1438 <channel_snapshot/>
1439 </syntax>
1440 <see-also>
1441 <ref type="managerEvent">AsyncAGIStart</ref>
1442 <ref type="managerEvent">AsyncAGIExec</ref>
1443 <ref type="application">AGI</ref>
1444 <ref type="manager">AGI</ref>
1445 </see-also>
1446 </managerEventInstance>
1447 </managerEvent>
1448 <managerEvent language="en_US" name="AsyncAGIExec">
1449 <managerEventInstance class="EVENT_FLAG_AGI">
1450 <since>
1451 <version>12.0.0</version>
1452 </since>
1453 <synopsis>Raised when AsyncAGI completes an AGI command.</synopsis>
1454 <syntax>
1455 <channel_snapshot/>
1456 <parameter name="CommandID" required="false">
1457 <para>Optional command ID sent by the AsyncAGI server to identify the command.</para>
1458 </parameter>
1459 <parameter name="Result">
1460 <para>URL encoded result string from the executed AGI command.</para>
1461 </parameter>
1462 </syntax>
1463 <see-also>
1464 <ref type="managerEvent">AsyncAGIStart</ref>
1465 <ref type="managerEvent">AsyncAGIEnd</ref>
1466 <ref type="application">AGI</ref>
1467 <ref type="manager">AGI</ref>
1468 </see-also>
1469 </managerEventInstance>
1470 </managerEvent>
1471 <managerEvent language="en_US" name="AGIExecStart">
1472 <managerEventInstance class="EVENT_FLAG_AGI">
1473 <since>
1474 <version>12.0.0</version>
1475 </since>
1476 <synopsis>Raised when a received AGI command starts processing.</synopsis>
1477 <syntax>
1478 <channel_snapshot/>
1479 <parameter name="Command">
1480 <para>The AGI command as received from the external source.</para>
1481 </parameter>
1482 <parameter name="CommandId">
1483 <para>Random identification number assigned to the execution of this command.</para>
1484 </parameter>
1485 </syntax>
1486 <see-also>
1487 <ref type="managerEvent">AGIExecEnd</ref>
1488 <ref type="application">AGI</ref>
1489 </see-also>
1490 </managerEventInstance>
1491 </managerEvent>
1492 <managerEvent language="en_US" name="AGIExecEnd">
1493 <managerEventInstance class="EVENT_FLAG_AGI">
1494 <since>
1495 <version>12.0.0</version>
1496 </since>
1497 <synopsis>Raised when a received AGI command completes processing.</synopsis>
1498 <syntax>
1499 <channel_snapshot/>
1500 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AGIExecStart']/managerEventInstance/syntax/parameter)" />
1501 <parameter name="ResultCode">
1502 <para>The numeric result code from AGI</para>
1503 </parameter>
1504 <parameter name="Result">
1505 <para>The text result reason from AGI</para>
1506 </parameter>
1507 </syntax>
1508 <see-also>
1509 <ref type="managerEvent">AGIExecStart</ref>
1510 <ref type="application">AGI</ref>
1511 </see-also>
1512 </managerEventInstance>
1513 </managerEvent>
1514 ***/
1515
1516#define MAX_ARGS 128
1517#define MAX_CMD_LEN 80
1518#define AGI_NANDFS_RETRY 3
1519#define AGI_BUF_LEN 8192
1520#define SRV_PREFIX "_agi._tcp."
1521
1522static char *app = "AGI";
1523
1524static char *eapp = "EAGI";
1525
1526static int agidebug = 0;
1527
1528#define TONE_BLOCK_SIZE 200
1529
1530/* Max time to connect to an AGI remote host */
1531#define MAX_AGI_CONNECT 2000
1532
1533#define AGI_PORT 4573
1534
1535/*! Special return code for "asyncagi break" command. */
1536#define ASYNC_AGI_BREAK 3
1537
1545};
1546
1548{
1550 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
1551 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
1552
1553 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1554 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
1555 if (!channel_string || !event_string) {
1556 return NULL;
1557 }
1558
1560 "%s"
1561 "%s",
1562 ast_str_buffer(channel_string),
1563 ast_str_buffer(event_string));
1564}
1565
1567{
1568 return agi_channel_to_ami("AGIExecStart", message);
1569}
1570
1572{
1573 return agi_channel_to_ami("AGIExecEnd", message);
1574}
1575
1577{
1578 return agi_channel_to_ami("AsyncAGIStart", message);
1579}
1580
1582{
1583 return agi_channel_to_ami("AsyncAGIExec", message);
1584}
1585
1587{
1588 return agi_channel_to_ami("AsyncAGIEnd", message);
1589}
1590
1593 );
1596 );
1599 );
1602 );
1605 );
1606
1607static agi_command *find_command(const char * const cmds[], int exact);
1608
1610#define AGI_BUF_INITSIZE 256
1611
1612int AST_OPTIONAL_API_NAME(ast_agi_send)(int fd, struct ast_channel *chan, char *fmt, ...)
1613{
1614 int res = 0;
1615 va_list ap;
1616 struct ast_str *buf;
1617
1619 return -1;
1620
1621 va_start(ap, fmt);
1622 res = ast_str_set_va(&buf, 0, fmt, ap);
1623 va_end(ap);
1624
1625 if (res == -1) {
1626 ast_log(LOG_ERROR, "Out of memory\n");
1627 return -1;
1628 }
1629
1630 if (agidebug) {
1631 if (chan) {
1632 ast_verbose("<%s>AGI Tx >> %s", ast_channel_name(chan), ast_str_buffer(buf));
1633 } else {
1634 ast_verbose("AGI Tx >> %s", ast_str_buffer(buf));
1635 }
1636 }
1637
1639}
1640
1641/* linked list of AGI commands ready to be executed by Async AGI */
1642struct agi_cmd {
1644 char *cmd_id;
1646};
1647
1648static void free_agi_cmd(struct agi_cmd *cmd)
1649{
1650 ast_free(cmd->cmd_buffer);
1651 ast_free(cmd->cmd_id);
1652 ast_free(cmd);
1653}
1654
1655/* AGI datastore destructor */
1656static void agi_destroy_commands_cb(void *data)
1657{
1658 struct agi_cmd *cmd;
1659 AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
1660 AST_LIST_LOCK(chan_cmds);
1661 while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
1662 free_agi_cmd(cmd);
1663 }
1664 AST_LIST_UNLOCK(chan_cmds);
1665 AST_LIST_HEAD_DESTROY(chan_cmds);
1666 ast_free(chan_cmds);
1667}
1668
1669/* channel datastore to keep the queue of AGI commands in the channel */
1671 .type = "AsyncAGI",
1672 .destroy = agi_destroy_commands_cb
1673};
1674
1675/*!
1676 * \brief Retrieve the list head to the requested channel's AGI datastore
1677 * \param chan Channel datastore is requested for
1678 * \param cmd Pointer to the struct pointer which will reference the head of the agi command list.
1679 *
1680 * \retval 0 if the datastore was valid and the list head was retrieved appropriately (even if it's
1681 * NULL and the list is empty)
1682 * \retval -1 if the datastore could not be retrieved causing an error
1683*/
1684static int get_agi_cmd(struct ast_channel *chan, struct agi_cmd **cmd)
1685{
1686 struct ast_datastore *store;
1688
1689 ast_channel_lock(chan);
1691 ast_channel_unlock(chan);
1692 if (!store) {
1693 ast_log(LOG_ERROR, "Huh? Async AGI datastore disappeared on Channel %s!\n",
1694 ast_channel_name(chan));
1695 *cmd = NULL;
1696 return -1;
1697 }
1698 agi_commands = store->data;
1702 return 0;
1703}
1704
1705/* channel is locked when calling this one either from the CLI or manager thread */
1706static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
1707{
1708 struct ast_datastore *store;
1709 struct agi_cmd *cmd;
1711
1713 if (!store) {
1714 ast_log(LOG_WARNING, "Channel %s is not setup for Async AGI.\n", ast_channel_name(chan));
1715 return -1;
1716 }
1717 agi_commands = store->data;
1718 cmd = ast_calloc(1, sizeof(*cmd));
1719 if (!cmd) {
1720 return -1;
1721 }
1722 cmd->cmd_buffer = ast_strdup(cmd_buff);
1723 if (!cmd->cmd_buffer) {
1724 ast_free(cmd);
1725 return -1;
1726 }
1727 cmd->cmd_id = ast_strdup(cmd_id);
1728 if (!cmd->cmd_id) {
1729 ast_free(cmd->cmd_buffer);
1730 ast_free(cmd);
1731 return -1;
1732 }
1736 return 0;
1737}
1738
1739static int add_to_agi(struct ast_channel *chan)
1740{
1741 struct ast_datastore *datastore;
1742 AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
1743
1744 /* check if already on AGI */
1745 ast_channel_lock(chan);
1747 ast_channel_unlock(chan);
1748 if (datastore) {
1749 /* we already have an AGI datastore, let's just
1750 return success */
1751 return 0;
1752 }
1753
1754 /* the channel has never been on Async AGI,
1755 let's allocate it's datastore */
1757 if (!datastore) {
1758 return -1;
1759 }
1760 agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
1761 if (!agi_cmds_list) {
1762 ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
1763 ast_datastore_free(datastore);
1764 return -1;
1765 }
1766 datastore->data = agi_cmds_list;
1767 AST_LIST_HEAD_INIT(agi_cmds_list);
1768 ast_channel_lock(chan);
1769 ast_channel_datastore_add(chan, datastore);
1770 ast_channel_unlock(chan);
1771 return 0;
1772}
1773
1774/*!
1775 * \brief CLI command to add applications to execute in Async AGI
1776 * \param e
1777 * \param cmd
1778 * \param a
1779 *
1780 * \retval CLI_SUCCESS on success
1781 * \retval NULL when init or tab completion is used
1782*/
1783static char *handle_cli_agi_add_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1784{
1785 struct ast_channel *chan;
1786 switch (cmd) {
1787 case CLI_INIT:
1788 e->command = "agi exec";
1789 e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
1790 " Add AGI command to the execute queue of the specified channel in Async AGI\n";
1791 return NULL;
1792 case CLI_GENERATE:
1793 if (a->pos == 2)
1794 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1795 return NULL;
1796 }
1797
1798 if (a->argc < 4) {
1799 return CLI_SHOWUSAGE;
1800 }
1801
1802 if (!(chan = ast_channel_get_by_name(a->argv[2]))) {
1803 ast_cli(a->fd, "Channel %s does not exist.\n", a->argv[2]);
1804 return CLI_FAILURE;
1805 }
1806
1807 ast_channel_lock(chan);
1808
1809 if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
1810 ast_cli(a->fd, "Failed to add AGI command to queue of channel %s\n", ast_channel_name(chan));
1811 ast_channel_unlock(chan);
1812 chan = ast_channel_unref(chan);
1813 return CLI_FAILURE;
1814 }
1815
1816 ast_debug(1, "Added AGI command to channel %s queue\n", ast_channel_name(chan));
1817
1818 ast_channel_unlock(chan);
1819 chan = ast_channel_unref(chan);
1820
1821 return CLI_SUCCESS;
1822}
1823
1824/*!
1825 * \brief Add a new command to execute by the Async AGI application
1826 * \param s
1827 * \param m
1828 *
1829 * It will append the application to the specified channel's queue
1830 * if the channel is not inside Async AGI application it will return an error
1831 * \retval 0 on success or incorrect use
1832 * \retval 1 on failure to add the command ( most likely because the channel
1833 * is not in Async AGI loop )
1834*/
1835static int action_add_agi_cmd(struct mansession *s, const struct message *m)
1836{
1837 const char *channel = astman_get_header(m, "Channel");
1838 const char *cmdbuff = astman_get_header(m, "Command");
1839 const char *cmdid = astman_get_header(m, "CommandID");
1840 struct ast_channel *chan;
1841 char buf[256];
1842
1843 if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
1844 astman_send_error(s, m, "Both, Channel and Command are *required*");
1845 return 0;
1846 }
1847
1848 if (!(chan = ast_channel_get_by_name(channel))) {
1849 snprintf(buf, sizeof(buf), "Channel %s does not exist.", channel);
1850 astman_send_error(s, m, buf);
1851 return 0;
1852 }
1853
1854 ast_channel_lock(chan);
1855
1856 if (add_agi_cmd(chan, cmdbuff, cmdid)) {
1857 snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", ast_channel_name(chan));
1858 astman_send_error(s, m, buf);
1859 ast_channel_unlock(chan);
1860 chan = ast_channel_unref(chan);
1861 return 0;
1862 }
1863
1864 ast_channel_unlock(chan);
1865 chan = ast_channel_unref(chan);
1866
1867 astman_send_ack(s, m, "Added AGI command to queue");
1868
1869 return 0;
1870}
1871
1872static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead);
1873static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[]);
1874
1875/*!
1876 * \internal
1877 * \brief Read and handle a channel frame for Async AGI.
1878 *
1879 * \param chan Channel to read a frame from.
1880 *
1881 * \retval AGI_RESULT_SUCCESS on success.
1882 * \retval AGI_RESULT_HANGUP on hangup.
1883 * \retval AGI_RESULT_FAILURE on error.
1884 */
1886{
1887 struct ast_frame *f;
1888
1889 f = ast_read(chan);
1890 if (!f) {
1891 ast_debug(3, "No frame read on channel %s, going out ...\n", ast_channel_name(chan));
1892 return AGI_RESULT_HANGUP;
1893 }
1894 if (f->frametype == AST_FRAME_CONTROL) {
1895 /*
1896 * Is there any other frame we should care about besides
1897 * AST_CONTROL_HANGUP?
1898 */
1899 switch (f->subclass.integer) {
1900 case AST_CONTROL_HANGUP:
1901 ast_debug(3, "Got HANGUP frame on channel %s, going out ...\n", ast_channel_name(chan));
1902 ast_frfree(f);
1903 return AGI_RESULT_HANGUP;
1904 default:
1905 break;
1906 }
1907 }
1908 ast_frfree(f);
1909
1910 return AGI_RESULT_SUCCESS;
1911}
1912
1913static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char *argv[], int *efd)
1914{
1915/* This buffer sizes might cause truncation if the AGI command writes more data
1916 than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command
1917 that writes a response larger than 1024 bytes?, I don't think so, most of
1918 them are just result=blah stuff. However probably if GET VARIABLE is called
1919 and the variable has large amount of data, that could be a problem. We could
1920 make this buffers dynamic, but let's leave that as a second step.
1921
1922 AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe
1923 number. Some characters of AGI buf will be url encoded to be sent to manager
1924 clients. An URL encoded character will take 3 bytes, but again, to cause
1925 truncation more than about 70% of the AGI buffer should be URL encoded for
1926 that to happen. Not likely at all.
1927
1928 On the other hand. I wonder if read() could eventually return less data than
1929 the amount already available in the pipe? If so, how to deal with that?
1930 So far, my tests on Linux have not had any problems.
1931 */
1932#define AGI_BUF_SIZE 1024
1933#define AMI_BUF_SIZE 2048
1934 enum agi_result cmd_status;
1935 struct agi_cmd *cmd;
1936 int res;
1937 int fds[2];
1938 int hungup;
1939 int timeout = 100;
1940 char agi_buffer[AGI_BUF_SIZE + 1];
1941 char ami_buffer[AMI_BUF_SIZE];
1942 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
1943 AGI async_agi;
1944 RAII_VAR(struct ast_json *, startblob, NULL, ast_json_unref);
1945
1946 if (efd) {
1947 ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
1948 return AGI_RESULT_FAILURE;
1949 }
1950
1951 /* add AsyncAGI datastore to the channel */
1952 if (add_to_agi(chan)) {
1953 ast_log(LOG_ERROR, "Failed to start Async AGI on channel %s\n", ast_channel_name(chan));
1954 return AGI_RESULT_FAILURE;
1955 }
1956
1957 /* this pipe allows us to create a "fake" AGI struct to use
1958 the AGI commands */
1959 res = pipe(fds);
1960 if (res) {
1961 ast_log(LOG_ERROR, "Failed to create Async AGI pipe\n");
1962 /*
1963 * Intentionally do not remove the datastore added with
1964 * add_to_agi() the from channel. It will be removed when the
1965 * channel is hung up anyway.
1966 */
1967 return AGI_RESULT_FAILURE;
1968 }
1969
1970 /* handlers will get the pipe write fd and we read the AGI responses
1971 from the pipe read fd */
1972 async_agi.fd = fds[1];
1973 async_agi.ctrl = fds[1];
1974 async_agi.audio = -1; /* no audio support */
1975 async_agi.fast = 0;
1976 async_agi.speech = NULL;
1977
1978 /* notify possible manager users of a new channel ready to
1979 receive commands */
1980 setup_env(chan, "async", fds[1], 0, argc, argv);
1981 /* read the environment */
1982 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
1983 if (res <= 0) {
1984 ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
1985 ast_channel_name(chan), res < 0 ? strerror(errno) : "EOF");
1986 returnstatus = AGI_RESULT_FAILURE;
1987 goto async_agi_abort;
1988 }
1989 agi_buffer[res] = '\0';
1990 /* encode it and send it thru the manager so whoever is going to take
1991 care of AGI commands on this channel can decide which AGI commands
1992 to execute based on the setup info */
1993 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, ast_uri_http);
1994 startblob = ast_json_pack("{s: s}", "Env", ami_buffer);
1995
1996 ast_channel_publish_cached_blob(chan, agi_async_start_type(), startblob);
1997
1998 hungup = ast_check_hangup_locked(chan);
1999
2000 for (;;) {
2001 /*
2002 * Process as many commands as we can. Commands are added via
2003 * the manager or the cli threads.
2004 */
2005 while (!hungup) {
2006 RAII_VAR(struct ast_json *, execblob, NULL, ast_json_unref);
2007 res = get_agi_cmd(chan, &cmd);
2008
2009 if (res) {
2010 returnstatus = AGI_RESULT_FAILURE;
2011 goto async_agi_done;
2012 } else if (!cmd) {
2013 break;
2014 }
2015
2016 /* OK, we have a command, let's call the command handler. */
2017 cmd_status = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
2018
2019 /*
2020 * The command handler must have written to our fake AGI struct
2021 * fd (the pipe), let's read the response.
2022 */
2023 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
2024 if (res <= 0) {
2025 ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
2026 ast_channel_name(chan), res < 0 ? strerror(errno) : "EOF");
2027 free_agi_cmd(cmd);
2028 returnstatus = AGI_RESULT_FAILURE;
2029 goto async_agi_done;
2030 }
2031 /*
2032 * We have a response, let's send the response thru the manager.
2033 * Include the CommandID if it was specified when the command
2034 * was added.
2035 */
2036 agi_buffer[res] = '\0';
2037 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, ast_uri_http);
2038
2039 execblob = ast_json_pack("{s: s}", "Result", ami_buffer);
2040 if (execblob && !ast_strlen_zero(cmd->cmd_id)) {
2041 ast_json_object_set(execblob, "CommandId", ast_json_string_create(cmd->cmd_id));
2042 }
2043 ast_channel_publish_cached_blob(chan, agi_async_exec_type(), execblob);
2044
2045 free_agi_cmd(cmd);
2046
2047 /*
2048 * Check the command status to determine if we should continue
2049 * executing more commands.
2050 */
2051 hungup = ast_check_hangup(chan);
2052 switch (cmd_status) {
2053 case AGI_RESULT_FAILURE:
2054 if (!hungup) {
2055 /* The failure was not because of a hangup. */
2056 returnstatus = AGI_RESULT_FAILURE;
2057 goto async_agi_done;
2058 }
2059 break;
2061 /* Only the "asyncagi break" command does this. */
2062 returnstatus = AGI_RESULT_SUCCESS_ASYNC;
2063 goto async_agi_done;
2064 default:
2065 break;
2066 }
2067 }
2068
2069 if (!hungup) {
2070 /* Wait a bit for a frame to read or to poll for a new command. */
2071 res = ast_waitfor(chan, timeout);
2072 if (res < 0) {
2073 ast_debug(1, "ast_waitfor returned <= 0 on chan %s\n", ast_channel_name(chan));
2074 returnstatus = AGI_RESULT_FAILURE;
2075 break;
2076 }
2077 } else {
2078 /*
2079 * Read the channel control queue until it is dry so we can
2080 * quit.
2081 */
2082 res = 1;
2083 }
2084 if (0 < res) {
2085 do {
2086 cmd_status = async_agi_read_frame(chan);
2087 if (cmd_status != AGI_RESULT_SUCCESS) {
2088 returnstatus = cmd_status;
2089 goto async_agi_done;
2090 }
2091 hungup = ast_check_hangup(chan);
2092 } while (hungup);
2093 } else {
2094 hungup = ast_check_hangup(chan);
2095 }
2096 }
2097async_agi_done:
2098
2099 if (async_agi.speech) {
2100 ast_speech_destroy(async_agi.speech);
2101 }
2102 /* notify manager users this channel cannot be controlled anymore by Async AGI */
2103 ast_channel_publish_cached_blob(chan, agi_async_end_type(), NULL);
2104
2105async_agi_abort:
2106 /* close the pipe */
2107 close(fds[0]);
2108 close(fds[1]);
2109
2110 /*
2111 * Intentionally do not remove the datastore added with
2112 * add_to_agi() the from channel. There might be commands still
2113 * in the queue or in-flight to us and AsyncAGI may get called
2114 * again. The datastore destructor will be called on channel
2115 * destruction anyway.
2116 */
2117
2118 if (returnstatus == AGI_RESULT_SUCCESS) {
2119 returnstatus = AGI_RESULT_SUCCESS_ASYNC;
2120 }
2121 return returnstatus;
2122
2123#undef AGI_BUF_SIZE
2124#undef AMI_BUF_SIZE
2125}
2126
2127/*!
2128 * \internal
2129 * \brief Handle the connection that was started by launch_netscript.
2130 *
2131 * \param agiurl Url that we are trying to connect to.
2132 * \param addr Address that host was resolved to.
2133 * \param netsockfd File descriptor of socket.
2134 *
2135 * \retval 0 when connection is succesful.
2136 * \retval 1 when there is an error.
2137 */
2138static int handle_connection(const char *agiurl, const struct ast_sockaddr addr, const int netsockfd)
2139{
2140 struct pollfd pfds[1];
2141 int res, conresult;
2142 socklen_t reslen;
2143
2144 reslen = sizeof(conresult);
2145
2146 pfds[0].fd = netsockfd;
2147 pfds[0].events = POLLOUT;
2148
2149 while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
2150 if (errno != EINTR) {
2151 if (!res) {
2152 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
2153 agiurl, MAX_AGI_CONNECT);
2154 } else {
2155 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
2156 }
2157
2158 return 1;
2159 }
2160 }
2161
2162 if (getsockopt(pfds[0].fd, SOL_SOCKET, SO_ERROR, &conresult, &reslen) < 0) {
2163 ast_log(LOG_WARNING, "Connection to %s failed with error: %s\n",
2164 ast_sockaddr_stringify(&addr), strerror(errno));
2165 return 1;
2166 }
2167
2168 if (conresult) {
2169 ast_log(LOG_WARNING, "Connecting to '%s' failed for url '%s': %s\n",
2170 ast_sockaddr_stringify(&addr), agiurl, strerror(conresult));
2171 return 1;
2172 }
2173
2174 return 0;
2175}
2176
2177/* launch_netscript: The fastagi handler.
2178 FastAGI defaults to port 4573 */
2179static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
2180{
2181 int s = 0;
2182 char *host, *script;
2183 int num_addrs = 0, i = 0;
2184 struct ast_sockaddr *addrs;
2185
2186 /* agiurl is "agi://host.domain[:port][/script/name]" */
2187 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
2188
2189 /* Strip off any script name */
2190 if ((script = strchr(host, '/'))) {
2191 *script++ = '\0';
2192 } else {
2193 script = "";
2194 }
2195
2196 if (!(num_addrs = ast_sockaddr_resolve(&addrs, host, 0, AST_AF_UNSPEC))) {
2197 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
2198 return AGI_RESULT_FAILURE;
2199 }
2200
2201 for (i = 0; i < num_addrs; i++) {
2202 if (!ast_sockaddr_port(&addrs[i])) {
2203 ast_sockaddr_set_port(&addrs[i], AGI_PORT);
2204 }
2205
2206 if ((s = ast_socket_nonblock(addrs[i].ss.ss_family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
2207 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
2208 continue;
2209 }
2210
2211 if (ast_connect(s, &addrs[i]) && errno == EINPROGRESS) {
2212
2213 if (handle_connection(agiurl, addrs[i], s)) {
2214 close(s);
2215 continue;
2216 }
2217
2218 } else {
2219 ast_log(LOG_WARNING, "Connection to %s failed with unexpected error: %s\n",
2220 ast_sockaddr_stringify(&addrs[i]), strerror(errno));
2221 }
2222
2223 break;
2224 }
2225
2226 ast_free(addrs);
2227
2228 if (i == num_addrs) {
2229 ast_log(LOG_WARNING, "Couldn't connect to any host. FastAGI failed.\n");
2230 return AGI_RESULT_FAILURE;
2231 }
2232
2233 if (ast_agi_send(s, NULL, "agi_network: yes\n") < 0) {
2234 if (errno != EINTR) {
2235 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
2236 close(s);
2237 return AGI_RESULT_FAILURE;
2238 }
2239 }
2240
2241 /* If we have a script parameter, relay it to the fastagi server */
2242 /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
2243 if (!ast_strlen_zero(script)) {
2244 ast_agi_send(s, NULL, "agi_network_script: %s\n", script);
2245 }
2246
2247 ast_debug(4, "Wow, connected!\n");
2248 fds[0] = s;
2249 fds[1] = s;
2251}
2252
2253/*!
2254 * \internal
2255 * \brief The HA fastagi handler.
2256 * \param agiurl The request URL as passed to Agi() in the dial plan
2257 * \param argv The parameters after the URL passed to Agi() in the dial plan
2258 * \param fds Input/output file descriptors
2259 *
2260 * Uses SRV lookups to try to connect to a list of FastAGI servers. The hostname in
2261 * the URI is prefixed with _agi._tcp. prior to the DNS resolution. For
2262 * example, if you specify the URI \a hagi://agi.example.com/foo.agi the DNS
2263 * query would be for \a _agi._tcp.agi.example.com and you'll need to make sure
2264 * this resolves.
2265 *
2266 * This function parses the URI, resolves the SRV service name, forms new URIs
2267 * with the results of the DNS lookup, and then calls launch_netscript on the
2268 * new URIs until one succeeds.
2269 *
2270 * \return the result of the AGI operation.
2271 */
2272static enum agi_result launch_ha_netscript(char *agiurl, char *argv[], int *fds)
2273{
2274 char *host, *script;
2275 enum agi_result result;
2276 struct srv_context *context = NULL;
2277 int srv_ret;
2278 char service[256];
2279 char resolved_uri[1024];
2280 const char *srvhost;
2281 unsigned short srvport;
2282
2283 /* format of agiurl is "hagi://host.domain[:port][/script/name]" */
2284 if (strlen(agiurl) < 7) { /* Remove hagi:// */
2285 ast_log(LOG_WARNING, "An error occurred parsing the AGI URI: %s", agiurl);
2286 return AGI_RESULT_FAILURE;
2287 }
2288 host = ast_strdupa(agiurl + 7);
2289
2290 /* Strip off any script name */
2291 if ((script = strchr(host, '/'))) {
2292 *script++ = '\0';
2293 } else {
2294 script = "";
2295 }
2296
2297 if (strchr(host, ':')) {
2298 ast_log(LOG_WARNING, "Specifying a port number disables SRV lookups: %s\n", agiurl);
2299 return launch_netscript(agiurl + 1, argv, fds); /* +1 to strip off leading h from hagi:// */
2300 }
2301
2302 snprintf(service, sizeof(service), "%s%s", SRV_PREFIX, host);
2303
2304 while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
2305 snprintf(resolved_uri, sizeof(resolved_uri), "agi://%s:%d/%s", srvhost, srvport, script);
2306 result = launch_netscript(resolved_uri, argv, fds);
2308 ast_log(LOG_WARNING, "AGI request failed for host '%s' (%s:%d)\n", host, srvhost, srvport);
2309 } else {
2310 /* The script launched so we must cleanup the context. */
2312 return result;
2313 }
2314 }
2315 /*
2316 * The DNS SRV lookup failed or we ran out of servers to check.
2317 * ast_srv_lookup() has already cleaned up the context for us.
2318 */
2319 if (srv_ret < 0) {
2320 ast_log(LOG_WARNING, "SRV lookup failed for %s\n", agiurl);
2321 }
2322
2323 return AGI_RESULT_FAILURE;
2324}
2325
2326static enum agi_result launch_script(struct ast_channel *chan, char *script, int argc, char *argv[], int *fds, int *efd, int *opid, int *safe_fork_called)
2327{
2328 char tmp[256];
2329 int pid, toast[2], fromast[2], audio[2], res;
2330 struct stat st;
2331
2332 /* We should not call ast_safe_fork_cleanup() if we never call ast_safe_fork(1) */
2333 *safe_fork_called = 0;
2334
2335 if (!strncasecmp(script, "agi://", 6)) {
2336 return (efd == NULL) ? launch_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
2337 }
2338 if (!strncasecmp(script, "hagi://", 7)) {
2339 return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
2340 }
2341 if (!strncasecmp(script, "agi:async", sizeof("agi:async") - 1)) {
2342 return launch_asyncagi(chan, argc, argv, efd);
2343 }
2344
2345 if (script[0] != '/') {
2346 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
2347 script = tmp;
2348 }
2349
2350 /* Before even trying let's see if the file actually exists */
2351 if (stat(script, &st)) {
2352 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
2353 return AGI_RESULT_NOTFOUND;
2354 }
2355
2356 if (pipe(toast)) {
2357 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
2358 return AGI_RESULT_FAILURE;
2359 }
2360 if (pipe(fromast)) {
2361 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
2362 close(toast[0]);
2363 close(toast[1]);
2364 return AGI_RESULT_FAILURE;
2365 }
2366 if (efd) {
2367 if (pipe(audio)) {
2368 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
2369 close(fromast[0]);
2370 close(fromast[1]);
2371 close(toast[0]);
2372 close(toast[1]);
2373 return AGI_RESULT_FAILURE;
2374 }
2375
2376 res = ast_fd_set_flags(audio[1], O_NONBLOCK);
2377 if (res < 0) {
2378 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
2379 close(fromast[0]);
2380 close(fromast[1]);
2381 close(toast[0]);
2382 close(toast[1]);
2383 close(audio[0]);
2384 close(audio[1]);
2385 return AGI_RESULT_FAILURE;
2386 }
2387 }
2388
2389 *safe_fork_called = 1;
2390
2391 if ((pid = ast_safe_fork(1)) < 0) {
2392 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
2393 return AGI_RESULT_FAILURE;
2394 }
2395 if (!pid) {
2396 /* Pass paths to AGI via environmental variables */
2397 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
2398 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
2399 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
2400 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
2401 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
2402 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
2403 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
2404 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
2405 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
2406 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
2407 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
2408
2409 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
2411
2412 /* Redirect stdin and out, provide enhanced audio channel if desired */
2413 dup2(fromast[0], STDIN_FILENO);
2414 dup2(toast[1], STDOUT_FILENO);
2415 if (efd)
2416 dup2(audio[0], STDERR_FILENO + 1);
2417 else
2418 close(STDERR_FILENO + 1);
2419
2420 /* Close everything but stdin/out/error */
2421 ast_close_fds_above_n(STDERR_FILENO + 1);
2422
2423 /* Execute script */
2424 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
2425 execv(script, argv);
2426 /* Can't use ast_log since FD's are closed */
2427 ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
2428 /* Special case to set status of AGI to failure */
2429 fprintf(stdout, "failure\n");
2430 fflush(stdout);
2431 _exit(1);
2432 }
2433 ast_verb(3, "Launched AGI Script %s\n", script);
2434 fds[0] = toast[0];
2435 fds[1] = fromast[1];
2436 if (efd)
2437 *efd = audio[1];
2438 /* close what we're not using in the parent */
2439 close(toast[1]);
2440 close(fromast[0]);
2441
2442 if (efd)
2443 close(audio[0]);
2444
2445 *opid = pid;
2446 return AGI_RESULT_SUCCESS;
2447}
2448
2449static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
2450{
2451 int count;
2452
2453 /* Print initial environment, with agi_request always being the first
2454 thing */
2455 ast_agi_send(fd, chan, "agi_request: %s\n", request);
2456 ast_agi_send(fd, chan, "agi_channel: %s\n", ast_channel_name(chan));
2457 ast_agi_send(fd, chan, "agi_language: %s\n", ast_channel_language(chan));
2458 ast_agi_send(fd, chan, "agi_type: %s\n", ast_channel_tech(chan)->type);
2459 ast_agi_send(fd, chan, "agi_uniqueid: %s\n", ast_channel_uniqueid(chan));
2460 ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version());
2461
2462 /* ANI/DNIS */
2463 ast_agi_send(fd, chan, "agi_callerid: %s\n",
2464 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "unknown"));
2465 ast_agi_send(fd, chan, "agi_calleridname: %s\n",
2466 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "unknown"));
2467 ast_agi_send(fd, chan, "agi_callingpres: %d\n",
2469 ast_agi_send(fd, chan, "agi_callingani2: %d\n", ast_channel_caller(chan)->ani2);
2470 ast_agi_send(fd, chan, "agi_callington: %d\n", ast_channel_caller(chan)->id.number.plan);
2471 ast_agi_send(fd, chan, "agi_callingtns: %d\n", ast_channel_dialed(chan)->transit_network_select);
2472 ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(ast_channel_dialed(chan)->number.str, "unknown"));
2473 ast_agi_send(fd, chan, "agi_rdnis: %s\n",
2474 S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "unknown"));
2475
2476 /* Context information */
2477 ast_agi_send(fd, chan, "agi_context: %s\n", ast_channel_context(chan));
2478 ast_agi_send(fd, chan, "agi_extension: %s\n", ast_channel_exten(chan));
2479 ast_agi_send(fd, chan, "agi_priority: %d\n", ast_channel_priority(chan));
2480 ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
2481
2482 /* User information */
2483 ast_agi_send(fd, chan, "agi_accountcode: %s\n", ast_channel_accountcode(chan) ? ast_channel_accountcode(chan) : "");
2484 ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self());
2485
2486 /* Send any parameters to the fastagi server that have been passed via the agi application */
2487 /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
2488 for(count = 1; count < argc; count++)
2489 ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]);
2490
2491 /* End with empty return */
2492 ast_agi_send(fd, chan, "\n");
2493}
2494
2495static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2496{
2497 int res = 0;
2498
2499 /* Answer the channel */
2500 if (ast_channel_state(chan) != AST_STATE_UP)
2501 res = ast_answer(chan);
2502
2503 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2504 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2505}
2506
2507static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2508{
2509 ast_agi_send(agi->fd, chan, "200 result=0\n");
2510 return ASYNC_AGI_BREAK;
2511}
2512
2513static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2514{
2515 int res, to;
2516
2517 if (argc != 4)
2518 return RESULT_SHOWUSAGE;
2519 if (sscanf(argv[3], "%30d", &to) != 1)
2520 return RESULT_SHOWUSAGE;
2521 res = ast_waitfordigit_full(chan, to, NULL, agi->audio, agi->ctrl);
2522 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2523 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2524}
2525
2526static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2527{
2528 int res;
2529
2530 if (argc != 3)
2531 return RESULT_SHOWUSAGE;
2532
2533 /* At the moment, the parser (perhaps broken) returns with
2534 the last argument PLUS the newline at the end of the input
2535 buffer. This probably needs to be fixed, but I wont do that
2536 because other stuff may break as a result. The right way
2537 would probably be to strip off the trailing newline before
2538 parsing, then here, add a newline at the end of the string
2539 before sending it to ast_sendtext --DUDE */
2540 res = ast_sendtext(chan, argv[2]);
2541 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2542 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2543}
2544
2545static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2546{
2547 int res;
2548
2549 if (argc != 3)
2550 return RESULT_SHOWUSAGE;
2551
2552 res = ast_recvchar(chan,atoi(argv[2]));
2553 if (res == 0) {
2554 ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res);
2555 return RESULT_SUCCESS;
2556 }
2557 if (res > 0) {
2558 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2559 return RESULT_SUCCESS;
2560 }
2561 ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res);
2562 return RESULT_FAILURE;
2563}
2564
2565static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2566{
2567 char *buf;
2568
2569 if (argc != 3)
2570 return RESULT_SHOWUSAGE;
2571
2572 buf = ast_recvtext(chan, atoi(argv[2]));
2573 if (buf) {
2574 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf);
2575 ast_free(buf);
2576 } else {
2577 ast_agi_send(agi->fd, chan, "200 result=-1\n");
2578 }
2579 return RESULT_SUCCESS;
2580}
2581
2582static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2583{
2584 int res, x;
2585
2586 if (argc != 3)
2587 return RESULT_SHOWUSAGE;
2588
2589 if (!strncasecmp(argv[2],"on",2)) {
2590 x = 1;
2591 } else {
2592 x = 0;
2593 }
2594 if (!strncasecmp(argv[2],"mate",4)) {
2595 x = 2;
2596 }
2597 if (!strncasecmp(argv[2],"tdd",3)) {
2598 x = 1;
2599 }
2600 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
2601 if (res) {
2602 /* Set channel option failed */
2603 ast_agi_send(agi->fd, chan, "200 result=0\n");
2604 } else {
2605 ast_agi_send(agi->fd, chan, "200 result=1\n");
2606 }
2607 return RESULT_SUCCESS;
2608}
2609
2610static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2611{
2612 int res;
2613
2614 if (argc != 3) {
2615 return RESULT_SHOWUSAGE;
2616 }
2617
2618 res = ast_send_image(chan, argv[2]);
2619 if (!ast_check_hangup(chan)) {
2620 res = 0;
2621 }
2622 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2623 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2624}
2625
2626static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2627{
2628 int res = 0, skipms = 3000;
2629 const char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */
2630 char stopkeybuf[2];
2631 long offsetms = 0;
2632 char offsetbuf[20];
2633
2634 if (argc < 5 || argc > 10) {
2635 return RESULT_SHOWUSAGE;
2636 }
2637
2638 if (!ast_strlen_zero(argv[4])) {
2639 stop = argv[4];
2640 }
2641
2642 if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) {
2643 return RESULT_SHOWUSAGE;
2644 }
2645
2646 if (argc > 6 && !ast_strlen_zero(argv[6])) {
2647 fwd = argv[6];
2648 }
2649
2650 if (argc > 7 && !ast_strlen_zero(argv[7])) {
2651 rev = argv[7];
2652 }
2653
2654 if (argc > 8 && !ast_strlen_zero(argv[8])) {
2655 suspend = argv[8];
2656 }
2657
2658 if (argc > 9 && (sscanf(argv[9], "%30ld", &offsetms) != 1)) {
2659 return RESULT_SHOWUSAGE;
2660 }
2661
2662 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, &offsetms);
2663
2664 /* If we stopped on one of our stop keys, return 0 */
2665 if (res > 0 && stop && strchr(stop, res)) {
2666 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "USERSTOPPED");
2667 snprintf(stopkeybuf, sizeof(stopkeybuf), "%c", res);
2668 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTOPKEY", stopkeybuf);
2669 } else if (res > 0 && res == AST_CONTROL_STREAM_STOP) {
2670 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "REMOTESTOPPED");
2671 res = 0;
2672 } else {
2673 if (res < 0) {
2674 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "ERROR");
2675 } else {
2676 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "SUCCESS");
2677 }
2678 }
2679
2680 snprintf(offsetbuf, sizeof(offsetbuf), "%ld", offsetms);
2681 pbx_builtin_setvar_helper(chan, "CPLAYBACKOFFSET", offsetbuf);
2682
2683 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, offsetms);
2684
2685 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2686}
2687
2688static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2689{
2690 int res;
2691 struct ast_filestream *fs, *vfs;
2692 long sample_offset = 0, max_length;
2693 const char *edigits = "";
2694
2695 if (argc < 4 || argc > 5) {
2696 return RESULT_SHOWUSAGE;
2697 }
2698
2699 if (argv[3]) {
2700 edigits = argv[3];
2701 }
2702
2703 if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1)) {
2704 return RESULT_SHOWUSAGE;
2705 }
2706
2707 if (!(fs = ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
2708 ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
2709 return RESULT_FAILURE;
2710 }
2711
2712 if ((vfs = ast_openvstream(chan, argv[2], ast_channel_language(chan)))) {
2713 ast_debug(1, "Ooh, found a video stream, too\n");
2714 }
2715 ast_verb(3, "<%s> Playing '%s.%s' (escape_digits=%s) (sample_offset %ld) (language '%s')\n",
2717 edigits, sample_offset, S_OR(ast_channel_language(chan), "default"));
2718
2719 ast_seekstream(fs, 0, SEEK_END);
2720 max_length = ast_tellstream(fs);
2721 ast_seekstream(fs, sample_offset, SEEK_SET);
2722 res = ast_applystream(chan, fs);
2723 if (vfs) {
2724 ast_applystream(chan, vfs);
2725 }
2726 ast_playstream(fs);
2727 if (vfs) {
2729 }
2730
2731 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
2732 /* this is to check for if ast_waitstream closed the stream, we probably are at
2733 * the end of the stream, return that amount, else check for the amount */
2734 sample_offset = (ast_channel_stream(chan)) ? ast_tellstream(fs) : max_length;
2735 ast_stopstream(chan);
2736 if (res == 1) {
2737 /* Stop this command, don't print a result line, as there is a new command */
2738 return RESULT_SUCCESS;
2739 }
2740 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
2741 pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", res ? "FAILED" : "SUCCESS");
2742
2743 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2744}
2745
2746/*! \brief get option - really similar to the handle_streamfile, but with a timeout */
2747static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2748{
2749 int res;
2750 struct ast_filestream *fs, *vfs;
2751 long sample_offset = 0, max_length;
2752 int timeout = 0;
2753 const char *edigits = "";
2754
2755 if ( argc < 4 || argc > 5 )
2756 return RESULT_SHOWUSAGE;
2757
2758 if ( argv[3] )
2759 edigits = argv[3];
2760
2761 if ( argc == 5 )
2762 timeout = atoi(argv[4]);
2763 else if (ast_channel_pbx(chan)->dtimeoutms) {
2764 /* by default dtimeout is set to 5sec */
2765 timeout = ast_channel_pbx(chan)->dtimeoutms; /* in msec */
2766 }
2767
2768 if (!(fs = ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
2769 ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
2770 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
2771 return RESULT_FAILURE;
2772 }
2773
2774 if ((vfs = ast_openvstream(chan, argv[2], ast_channel_language(chan))))
2775 ast_debug(1, "Ooh, found a video stream, too\n");
2776
2777 ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
2778
2779 ast_seekstream(fs, 0, SEEK_END);
2780 max_length = ast_tellstream(fs);
2781 ast_seekstream(fs, sample_offset, SEEK_SET);
2782 res = ast_applystream(chan, fs);
2783 if (vfs)
2784 ast_applystream(chan, vfs);
2785 ast_playstream(fs);
2786 if (vfs)
2788
2789 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
2790 /* this is to check for if ast_waitstream closed the stream, we probably are at
2791 * the end of the stream, return that amount, else check for the amount */
2792 sample_offset = (ast_channel_stream(chan))?ast_tellstream(fs):max_length;
2793 ast_stopstream(chan);
2794 if (res == 1) {
2795 /* Stop this command, don't print a result line, as there is a new command */
2796 return RESULT_SUCCESS;
2797 }
2798
2799 /* If the user didnt press a key, wait for digitTimeout*/
2800 if (res == 0 ) {
2801 res = ast_waitfordigit_full(chan, timeout, NULL, agi->audio, agi->ctrl);
2802 /* Make sure the new result is in the escape digits of the GET OPTION */
2803 if ( !strchr(edigits,res) )
2804 res=0;
2805 }
2806
2807 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
2808 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2809}
2810
2811
2812
2813
2814/*! \brief Say number in various language syntaxes */
2815/* While waiting, we're sending a NULL. */
2816static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2817{
2818 int res, num;
2819
2820 if (argc < 4 || argc > 5)
2821 return RESULT_SHOWUSAGE;
2822 if (sscanf(argv[2], "%30d", &num) != 1)
2823 return RESULT_SHOWUSAGE;
2824 res = ast_say_number_full(chan, num, argv[3], ast_channel_language(chan), argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
2825 if (res == 1)
2826 return RESULT_SUCCESS;
2827 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2828 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2829}
2830
2831static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2832{
2833 int res, num;
2834
2835 if (argc != 4)
2836 return RESULT_SHOWUSAGE;
2837 if (sscanf(argv[2], "%30d", &num) != 1)
2838 return RESULT_SHOWUSAGE;
2839
2840 res = ast_say_digit_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->audio, agi->ctrl);
2841 if (res == 1) /* New command */
2842 return RESULT_SUCCESS;
2843 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2844 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2845}
2846
2847static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2848{
2849 int res;
2850 int sensitivity = AST_SAY_CASE_NONE;
2851
2852 if (argc < 4 || argc > 5) {
2853 return RESULT_SHOWUSAGE;
2854 }
2855
2856 if (argc > 4) {
2857 switch (argv[4][0]) {
2858 case 'a':
2859 case 'A':
2860 sensitivity = AST_SAY_CASE_ALL;
2861 break;
2862 case 'l':
2863 case 'L':
2864 sensitivity = AST_SAY_CASE_LOWER;
2865 break;
2866 case 'n':
2867 case 'N':
2868 sensitivity = AST_SAY_CASE_NONE;
2869 break;
2870 case 'u':
2871 case 'U':
2872 sensitivity = AST_SAY_CASE_UPPER;
2873 break;
2874 case '\0':
2875 break;
2876 default:
2877 return RESULT_SHOWUSAGE;
2878 }
2879 }
2880 res = ast_say_character_str_full(chan, argv[2], argv[3], ast_channel_language(chan), sensitivity, agi->audio, agi->ctrl);
2881 if (res == 1) /* New command */
2882 return RESULT_SUCCESS;
2883 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2884 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2885}
2886
2887static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2888{
2889 int res, num;
2890
2891 if (argc != 4)
2892 return RESULT_SHOWUSAGE;
2893 if (sscanf(argv[2], "%30d", &num) != 1)
2894 return RESULT_SHOWUSAGE;
2895 res = ast_say_date(chan, num, argv[3], ast_channel_language(chan));
2896 if (res == 1)
2897 return RESULT_SUCCESS;
2898 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2899 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2900}
2901
2902static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2903{
2904 int res, num;
2905
2906 if (argc != 4)
2907 return RESULT_SHOWUSAGE;
2908 if (sscanf(argv[2], "%30d", &num) != 1)
2909 return RESULT_SHOWUSAGE;
2910 res = ast_say_time(chan, num, argv[3], ast_channel_language(chan));
2911 if (res == 1)
2912 return RESULT_SUCCESS;
2913 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2914 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2915}
2916
2917static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2918{
2919 int res = 0;
2920 time_t unixtime;
2921 const char *format, *zone = NULL;
2922
2923 if (argc < 4)
2924 return RESULT_SHOWUSAGE;
2925
2926 if (argc > 4) {
2927 format = argv[4];
2928 } else {
2929 /* XXX this doesn't belong here, but in the 'say' module */
2930 if (!strcasecmp(ast_channel_language(chan), "de")) {
2931 format = "A dBY HMS";
2932 } else {
2933 format = "ABdY 'digits/at' IMp";
2934 }
2935 }
2936
2937 if (argc > 5 && !ast_strlen_zero(argv[5]))
2938 zone = argv[5];
2939
2940 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
2941 return RESULT_SHOWUSAGE;
2942
2943 res = ast_say_date_with_format(chan, unixtime, argv[3], ast_channel_language(chan), format, zone);
2944 if (res == 1)
2945 return RESULT_SUCCESS;
2946
2947 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2948 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2949}
2950
2951static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2952{
2953 int res;
2954
2955 if (argc != 4)
2956 return RESULT_SHOWUSAGE;
2957
2958 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->audio, agi->ctrl);
2959 if (res == 1) /* New command */
2960 return RESULT_SUCCESS;
2961 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2962 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2963}
2964
2965static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2966{
2967 int res, max, timeout;
2968 char data[1024];
2969
2970 if (argc < 3)
2971 return RESULT_SHOWUSAGE;
2972 if (argc >= 4)
2973 timeout = atoi(argv[3]);
2974 else
2975 timeout = 0;
2976 if (argc >= 5)
2977 max = atoi(argv[4]);
2978 else
2979 max = 1024;
2980 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
2981 if (res == 2) /* New command */
2982 return RESULT_SUCCESS;
2983 else if (res == 1)
2984 ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
2985 else if (res < 0 )
2986 ast_agi_send(agi->fd, chan, "200 result=-1\n");
2987 else
2988 ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
2989 return RESULT_SUCCESS;
2990}
2991
2992static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2993{
2994
2995 if (argc != 3)
2996 return RESULT_SHOWUSAGE;
2997 ast_channel_context_set(chan, argv[2]);
2998 ast_agi_send(agi->fd, chan, "200 result=0\n");
2999 return RESULT_SUCCESS;
3000}
3001
3002static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3003{
3004 if (argc != 3)
3005 return RESULT_SHOWUSAGE;
3006 ast_channel_exten_set(chan, argv[2]);
3007 ast_agi_send(agi->fd, chan, "200 result=0\n");
3008 return RESULT_SUCCESS;
3009}
3010
3011static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3012{
3013 int pri;
3014
3015 if (argc != 3)
3016 return RESULT_SHOWUSAGE;
3017
3018 if (sscanf(argv[2], "%30d", &pri) != 1) {
3019 pri = ast_findlabel_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), argv[2],
3020 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
3021 if (pri < 1)
3022 return RESULT_SHOWUSAGE;
3023 }
3024
3025 ast_explicit_goto(chan, NULL, NULL, pri);
3026 ast_agi_send(agi->fd, chan, "200 result=0\n");
3027 return RESULT_SUCCESS;
3028}
3029
3030static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3031{
3032 struct ast_filestream *fs;
3033 struct ast_frame *f;
3034 struct timeval start;
3035 long sample_offset = 0;
3036 int res = 0;
3037 int ms;
3038
3039 struct ast_dsp *sildet=NULL; /* silence detector dsp */
3040 int totalsilence = 0;
3041 int dspsilence = 0;
3042 int silence = 0; /* amount of silence to allow */
3043 int gotsilence = 0; /* did we timeout for silence? */
3044 char *silencestr = NULL;
3045 RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup);
3046 struct ast_silence_generator *silgen = NULL;
3047
3048 /* XXX EAGI FIXME XXX */
3049
3050 if (argc < 6)
3051 return RESULT_SHOWUSAGE;
3052 if (sscanf(argv[5], "%30d", &ms) != 1)
3053 return RESULT_SHOWUSAGE;
3054
3055 if (argc > 6)
3056 silencestr = strchr(argv[6],'s');
3057 if ((argc > 7) && (!silencestr))
3058 silencestr = strchr(argv[7],'s');
3059 if ((argc > 8) && (!silencestr))
3060 silencestr = strchr(argv[8],'s');
3061
3062 if (silencestr) {
3063 if (strlen(silencestr) > 2) {
3064 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
3065 silencestr++;
3066 silencestr++;
3067 if (silencestr)
3068 silence = atoi(silencestr);
3069 if (silence > 0)
3070 silence *= 1000;
3071 }
3072 }
3073 }
3074
3075 if (silence > 0) {
3076 rfmt = ao2_bump(ast_channel_readformat(chan));
3078 if (res < 0) {
3079 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
3080 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
3081 return RESULT_FAILURE;
3082 }
3083 sildet = ast_dsp_new();
3084 if (!sildet) {
3085 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
3086 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3087 return RESULT_FAILURE;
3088 }
3090 }
3091
3092 /* backward compatibility, if no offset given, arg[6] would have been
3093 * caught below and taken to be a beep, else if it is a digit then it is a
3094 * offset.
3095 *
3096 * In other words, if the argument does not look like the offset_samples
3097 * argument (a number) and it doesn't look like the silence argument (starts
3098 * with "s=") then it must be the beep argument. The beep argument has no
3099 * required value, the presence of anything in the argument slot we are
3100 * inspecting is an indication that the user wants a beep played.
3101 */
3102 if ((argc > 6 && sscanf(argv[6], "%30ld", &sample_offset) != 1 && !ast_begins_with(argv[6], "s="))
3103 || (argc > 7 && !ast_begins_with(argv[7], "s="))) {
3104 res = ast_streamfile(chan, "beep", ast_channel_language(chan));
3105 }
3106
3107 if (!res)
3108 res = ast_waitstream(chan, argv[4]);
3109 if (res) {
3110 ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
3111 } else {
3112 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
3113 if (!fs) {
3114 res = -1;
3115 ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
3116 if (sildet)
3117 ast_dsp_free(sildet);
3118 return RESULT_FAILURE;
3119 }
3120
3121 /* Request a video update */
3123
3124 ast_channel_stream_set(chan, fs);
3125 ast_applystream(chan,fs);
3126 /* really should have checks */
3127 ast_seekstream(fs, sample_offset, SEEK_SET);
3128 ast_truncstream(fs);
3129
3132 }
3133
3134 start = ast_tvnow();
3135 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
3136 res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start));
3137 if (res < 0) {
3138 ast_closestream(fs);
3139 ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
3140 if (sildet)
3141 ast_dsp_free(sildet);
3142 if (silgen)
3144 return RESULT_FAILURE;
3145 }
3146 f = ast_read(chan);
3147 if (!f) {
3148 ast_closestream(fs);
3149 ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
3150 if (sildet)
3151 ast_dsp_free(sildet);
3152 if (silgen)
3154 return RESULT_FAILURE;
3155 }
3156 switch(f->frametype) {
3157 case AST_FRAME_DTMF:
3158 if (strchr(argv[4], f->subclass.integer)) {
3159 /* This is an interrupting character, so rewind to chop off any small
3160 amount of DTMF that may have been recorded
3161 */
3162 ast_stream_rewind(fs, 200);
3163 ast_truncstream(fs);
3164 sample_offset = ast_tellstream(fs);
3165 ast_closestream(fs);
3166 ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset);
3167 ast_frfree(f);
3168 if (sildet)
3169 ast_dsp_free(sildet);
3170 if (silgen)
3172 return RESULT_SUCCESS;
3173 }
3174 break;
3175 case AST_FRAME_VOICE:
3176 ast_writestream(fs, f);
3177 /* this is a safe place to check progress since we know that fs
3178 * is valid after a write, and it will then have our current
3179 * location */
3180 sample_offset = ast_tellstream(fs);
3181 if (silence > 0) {
3182 dspsilence = 0;
3183 ast_dsp_silence(sildet, f, &dspsilence);
3184 if (dspsilence) {
3185 totalsilence = dspsilence;
3186 } else {
3187 totalsilence = 0;
3188 }
3189 if (totalsilence > silence) {
3190 /* Ended happily with silence */
3191 gotsilence = 1;
3192 break;
3193 }
3194 }
3195 break;
3196 case AST_FRAME_VIDEO:
3197 ast_writestream(fs, f);
3198 default:
3199 /* Ignore all other frames */
3200 break;
3201 }
3202 ast_frfree(f);
3203 if (gotsilence)
3204 break;
3205 }
3206
3207 if (gotsilence) {
3208 ast_stream_rewind(fs, silence-1000);
3209 ast_truncstream(fs);
3210 sample_offset = ast_tellstream(fs);
3211 }
3212 ast_closestream(fs);
3213 ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
3214 }
3215
3216 if (silence > 0) {
3217 res = ast_set_read_format(chan, rfmt);
3218 if (res)
3219 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(chan));
3220 ast_dsp_free(sildet);
3221 }
3222
3223 if (silgen) {
3225 }
3226
3227 return RESULT_SUCCESS;
3228}
3229
3230static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3231{
3232 double timeout;
3233 struct timeval whentohangup = { 0, 0 };
3234
3235 if (argc != 3)
3236 return RESULT_SHOWUSAGE;
3237 if (sscanf(argv[2], "%30lf", &timeout) != 1)
3238 return RESULT_SHOWUSAGE;
3239 if (timeout < 0)
3240 timeout = 0;
3241 if (timeout) {
3242 whentohangup.tv_sec = timeout;
3243 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
3244 }
3245 ast_channel_lock(chan);
3246 ast_channel_setwhentohangup_tv(chan, whentohangup);
3247 ast_channel_unlock(chan);
3248 ast_agi_send(agi->fd, chan, "200 result=0\n");
3249 return RESULT_SUCCESS;
3250}
3251
3252static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3253{
3254 struct ast_channel *c;
3255
3256 if (argc == 1) {
3257 /* no argument: hangup the current channel */
3258 ast_set_hangupsource(chan, "dialplan/agi", 0);
3260 ast_agi_send(agi->fd, chan, "200 result=1\n");
3261 return RESULT_SUCCESS;
3262 } else if (argc == 2) {
3263 /* one argument: look for info on the specified channel */
3264 if ((c = ast_channel_get_by_name(argv[1]))) {
3265 /* we have a matching channel */
3266 ast_set_hangupsource(c, "dialplan/agi", 0);
3269 ast_agi_send(agi->fd, chan, "200 result=1\n");
3270 return RESULT_SUCCESS;
3271 }
3272 /* if we get this far no channel name matched the argument given */
3273 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3274 return RESULT_SUCCESS;
3275 } else {
3276 return RESULT_SHOWUSAGE;
3277 }
3278}
3279
3280static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3281{
3282 int res, workaround;
3283 struct ast_app *app_to_exec;
3284 const char *agi_exec_full_str;
3285 int agi_exec_full;
3286 struct ast_str *data_with_var = NULL;
3287
3288 if (argc < 2)
3289 return RESULT_SHOWUSAGE;
3290
3291 ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
3292
3293 if ((app_to_exec = pbx_findapp(argv[1]))) {
3294 ast_channel_lock(chan);
3295 if (!(workaround = ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS))) {
3297 }
3298 agi_exec_full_str = pbx_builtin_getvar_helper(chan, "AGIEXECFULL");
3299 agi_exec_full = ast_true(agi_exec_full_str);
3300 ast_channel_unlock(chan);
3301
3302 if (agi_exec_full) {
3303 if ((data_with_var = ast_str_create(16))) {
3304 ast_str_substitute_variables(&data_with_var, 0, chan, argv[2]);
3305 res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : ast_str_buffer(data_with_var));
3306 ast_free(data_with_var);
3307 } else {
3308 res = -2;
3309 }
3310 } else {
3311 res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
3312 }
3313 if (!workaround) {
3315 }
3316 } else {
3317 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
3318 res = -2;
3319 }
3320 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
3321
3322 /* Even though this is wrong, users are depending upon this result. */
3323 return res;
3324}
3325
3326static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3327{
3328 char tmp[256]="";
3329 char *l = NULL, *n = NULL;
3330
3331 if (argv[2]) {
3332 ast_copy_string(tmp, argv[2], sizeof(tmp));
3333 ast_callerid_parse(tmp, &n, &l);
3334 if (l)
3336 else
3337 l = "";
3338 if (!n)
3339 n = "";
3340 ast_set_callerid(chan, l, n, NULL);
3341 }
3342
3343 ast_agi_send(agi->fd, chan, "200 result=1\n");
3344 return RESULT_SUCCESS;
3345}
3346
3347static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3348{
3349 if (argc == 2) {
3350 /* no argument: supply info on the current channel */
3351 ast_agi_send(agi->fd, chan, "200 result=%u\n", ast_channel_state(chan));
3352 return RESULT_SUCCESS;
3353 } else if (argc == 3) {
3354 struct ast_channel_snapshot *snapshot;
3355
3356 /* one argument: look for info on the specified channel */
3357 snapshot = ast_channel_snapshot_get_latest_by_name(argv[2]);
3358 if (snapshot) {
3359 ast_agi_send(agi->fd, chan, "200 result=%u\n", snapshot->state);
3360 ao2_ref(snapshot, -1);
3361 return RESULT_SUCCESS;
3362 }
3363 /* if we get this far no channel name matched the argument given */
3364 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3365 return RESULT_SUCCESS;
3366 } else {
3367 return RESULT_SHOWUSAGE;
3368 }
3369}
3370
3371static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3372{
3373 if (argc != 4) {
3374 return RESULT_SHOWUSAGE;
3375 }
3376
3377 if (argv[3])
3378 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
3379
3380 ast_agi_send(agi->fd, chan, "200 result=1\n");
3381 return RESULT_SUCCESS;
3382}
3383
3384static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3385{
3386 char *ret;
3387 char tempstr[1024] = "";
3388
3389 if (argc != 3)
3390 return RESULT_SHOWUSAGE;
3391
3392 /* check if we want to execute an ast_custom_function */
3393 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
3394 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
3395 } else {
3396 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
3397 }
3398
3399 if (ret)
3400 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
3401 else
3402 ast_agi_send(agi->fd, chan, "200 result=0\n");
3403
3404 return RESULT_SUCCESS;
3405}
3406
3407static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3408{
3409 struct ast_channel *chan2 = NULL;
3410
3411 if (argc != 4 && argc != 5) {
3412 return RESULT_SHOWUSAGE;
3413 }
3414
3415 if (argc == 5) {
3416 chan2 = ast_channel_get_by_name(argv[4]);
3417 } else {
3418 chan2 = ast_channel_ref(chan);
3419 }
3420
3421 if (chan2) {
3422 struct ast_str *str = ast_str_create(16);
3423 if (!str) {
3424 ast_agi_send(agi->fd, chan, "200 result=0\n");
3425 return RESULT_SUCCESS;
3426 }
3427 ast_str_substitute_variables(&str, 0, chan2, argv[3]);
3428 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(str));
3429 ast_free(str);
3430 } else {
3431 ast_agi_send(agi->fd, chan, "200 result=0\n");
3432 }
3433
3434 if (chan2) {
3435 chan2 = ast_channel_unref(chan2);
3436 }
3437
3438 return RESULT_SUCCESS;
3439}
3440
3441static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3442{
3443 int level = 0;
3444
3445 if (argc < 2)
3446 return RESULT_SHOWUSAGE;
3447
3448 if (argv[2])
3449 sscanf(argv[2], "%30d", &level);
3450
3451 ast_verb(level, "%s: %s\n", ast_channel_data(chan), argv[1]);
3452
3453 ast_agi_send(agi->fd, chan, "200 result=1\n");
3454
3455 return RESULT_SUCCESS;
3456}
3457
3458static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3459{
3460 int res;
3461 struct ast_str *buf;
3462
3463 if (argc != 4)
3464 return RESULT_SHOWUSAGE;
3465
3466 if (!(buf = ast_str_create(16))) {
3467 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3468 return RESULT_SUCCESS;
3469 }
3470
3471 do {
3472 res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
3474 if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
3475 break;
3476 }
3477 if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
3478 break;
3479 }
3480 } while (1);
3481
3482 if (res)
3483 ast_agi_send(agi->fd, chan, "200 result=0\n");
3484 else
3485 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
3486
3487 ast_free(buf);
3488 return RESULT_SUCCESS;
3489}
3490
3491static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3492{
3493 int res;
3494
3495 if (argc != 5)
3496 return RESULT_SHOWUSAGE;
3497 res = ast_db_put(argv[2], argv[3], argv[4]);
3498 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
3499 return RESULT_SUCCESS;
3500}
3501
3502static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3503{
3504 int res;
3505
3506 if (argc != 4)
3507 return RESULT_SHOWUSAGE;
3508 res = ast_db_del(argv[2], argv[3]);
3509 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
3510 return RESULT_SUCCESS;
3511}
3512
3513static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3514{
3515 int num_deleted;
3516
3517 if ((argc < 3) || (argc > 4)) {
3518 return RESULT_SHOWUSAGE;
3519 }
3520 if (argc == 4) {
3521 num_deleted = ast_db_deltree(argv[2], argv[3]);
3522 } else {
3523 num_deleted = ast_db_deltree(argv[2], NULL);
3524 }
3525
3526 ast_agi_send(agi->fd, chan, "200 result=%c\n", num_deleted > 0 ? '0' : '1');
3527 return RESULT_SUCCESS;
3528}
3529
3530static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3531{
3532 switch (cmd) {
3533 case CLI_INIT:
3534 e->command = "agi set debug [on|off]";
3535 e->usage =
3536 "Usage: agi set debug [on|off]\n"
3537 " Enables/disables dumping of AGI transactions for\n"
3538 " debugging purposes.\n";
3539 return NULL;
3540
3541 case CLI_GENERATE:
3542 return NULL;
3543 }
3544
3545 if (a->argc != e->args)
3546 return CLI_SHOWUSAGE;
3547
3548 if (strncasecmp(a->argv[3], "off", 3) == 0) {
3549 agidebug = 0;
3550 } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
3551 agidebug = 1;
3552 } else {
3553 return CLI_SHOWUSAGE;
3554 }
3555 ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
3556 return CLI_SUCCESS;
3557}
3558
3559static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, const char * const argv[])
3560{
3561 ast_agi_send(agi->fd, chan, "200 result=0\n");
3562 return RESULT_SUCCESS;
3563}
3564
3565static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3566{
3567 if (argc < 3) {
3568 return RESULT_SHOWUSAGE;
3569 }
3570 if (!strncasecmp(argv[2], "on", 2))
3571 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
3572 else if (!strncasecmp(argv[2], "off", 3))
3573 ast_moh_stop(chan);
3574 ast_agi_send(agi->fd, chan, "200 result=0\n");
3575 return RESULT_SUCCESS;
3576}
3577
3578static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3579{
3580 struct ast_format_cap *cap;
3581
3582 /* If a structure already exists, return an error */
3583 if (agi->speech) {
3584 ast_agi_send(agi->fd, chan, "200 result=0\n");
3585 return RESULT_SUCCESS;
3586 }
3587
3589 return RESULT_FAILURE;
3590 }
3592 if ((agi->speech = ast_speech_new(argv[2], cap))) {
3593 ast_agi_send(agi->fd, chan, "200 result=1\n");
3594 } else {
3595 ast_agi_send(agi->fd, chan, "200 result=0\n");
3596 }
3597 ao2_ref(cap, -1);
3598
3599 return RESULT_SUCCESS;
3600}
3601
3602static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3603{
3604 /* Check for minimum arguments */
3605 if (argc != 4)
3606 return RESULT_SHOWUSAGE;
3607
3608 /* Check to make sure speech structure exists */
3609 if (!agi->speech) {
3610 ast_agi_send(agi->fd, chan, "200 result=0\n");
3611 return RESULT_SUCCESS;
3612 }
3613
3614 ast_speech_change(agi->speech, argv[2], argv[3]);
3615 ast_agi_send(agi->fd, chan, "200 result=1\n");
3616
3617 return RESULT_SUCCESS;
3618}
3619
3620static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3621{
3622 if (agi->speech) {
3624 agi->speech = NULL;
3625 ast_agi_send(agi->fd, chan, "200 result=1\n");
3626 } else {
3627 ast_agi_send(agi->fd, chan, "200 result=0\n");
3628 }
3629
3630 return RESULT_SUCCESS;
3631}
3632
3633static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3634{
3635 if (argc != 5)
3636 return RESULT_SHOWUSAGE;
3637
3638 if (!agi->speech) {
3639 ast_agi_send(agi->fd, chan, "200 result=0\n");
3640 return RESULT_SUCCESS;
3641 }
3642
3643 if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
3644 ast_agi_send(agi->fd, chan, "200 result=0\n");
3645 else
3646 ast_agi_send(agi->fd, chan, "200 result=1\n");
3647
3648 return RESULT_SUCCESS;
3649}
3650
3651static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3652{
3653 if (argc != 4)
3654 return RESULT_SHOWUSAGE;
3655
3656 if (!agi->speech) {
3657 ast_agi_send(agi->fd, chan, "200 result=0\n");
3658 return RESULT_SUCCESS;
3659 }
3660
3661 if (ast_speech_grammar_unload(agi->speech, argv[3]))
3662 ast_agi_send(agi->fd, chan, "200 result=0\n");
3663 else
3664 ast_agi_send(agi->fd, chan, "200 result=1\n");
3665
3666 return RESULT_SUCCESS;
3667}
3668
3669static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3670{
3671 if (argc != 4)
3672 return RESULT_SHOWUSAGE;
3673
3674 if (!agi->speech) {
3675 ast_agi_send(agi->fd, chan, "200 result=0\n");
3676 return RESULT_SUCCESS;
3677 }
3678
3679 if (ast_speech_grammar_activate(agi->speech, argv[3]))
3680 ast_agi_send(agi->fd, chan, "200 result=0\n");
3681 else
3682 ast_agi_send(agi->fd, chan, "200 result=1\n");
3683
3684 return RESULT_SUCCESS;
3685}
3686
3687static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3688{
3689 if (argc != 4)
3690 return RESULT_SHOWUSAGE;
3691
3692 if (!agi->speech) {
3693 ast_agi_send(agi->fd, chan, "200 result=0\n");
3694 return RESULT_SUCCESS;
3695 }
3696
3697 if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
3698 ast_agi_send(agi->fd, chan, "200 result=0\n");
3699 else
3700 ast_agi_send(agi->fd, chan, "200 result=1\n");
3701
3702 return RESULT_SUCCESS;
3703}
3704
3705static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
3706{
3707 struct ast_filestream *fs = NULL;
3708
3709 if (!(fs = ast_openstream(chan, filename, preflang)))
3710 return -1;
3711
3712 if (offset)
3713 ast_seekstream(fs, offset, SEEK_SET);
3714
3715 if (ast_applystream(chan, fs))
3716 return -1;
3717
3718 if (ast_playstream(fs))
3719 return -1;
3720
3721 return 0;
3722}
3723
3724static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3725{
3726 struct ast_speech *speech = agi->speech;
3727 const char *prompt;
3728 char dtmf = 0, tmp[4096] = "", *buf = tmp;
3729 int timeout = 0, offset = 0, res = 0, i = 0;
3730 long current_offset = 0;
3731 const char *reason = NULL;
3732 struct ast_frame *fr = NULL;
3733 struct ast_speech_result *result = NULL;
3734 size_t left = sizeof(tmp);
3735 time_t start = 0, current;
3736
3737 if (argc < 4)
3738 return RESULT_SHOWUSAGE;
3739
3740 if (!speech) {
3741 ast_agi_send(agi->fd, chan, "200 result=0\n");
3742 return RESULT_SUCCESS;
3743 }
3744
3745 prompt = argv[2];
3746 timeout = atoi(argv[3]);
3747
3748 /* If offset is specified then convert from text to integer */
3749 if (argc == 5)
3750 offset = atoi(argv[4]);
3751
3752 /* We want frames coming in signed linear */
3754 ast_agi_send(agi->fd, chan, "200 result=0\n");
3755 return RESULT_SUCCESS;
3756 }
3757
3758 /* Setup speech structure */
3759 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
3761 ast_speech_start(speech);
3762 }
3763
3764 /* Start playing prompt */
3765 speech_streamfile(chan, prompt, ast_channel_language(chan), offset);
3766
3767 /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
3768 while (ast_strlen_zero(reason)) {
3769 /* Run scheduled items */
3771
3772 /* See maximum time of waiting */
3773 if ((res = ast_sched_wait(ast_channel_sched(chan))) < 0)
3774 res = 1000;
3775
3776 /* Wait for frame */
3777 if (ast_waitfor(chan, res) > 0) {
3778 if (!(fr = ast_read(chan))) {
3779 reason = "hangup";
3780 break;
3781 }
3782 }
3783
3784 /* Perform timeout check */
3785 if ((timeout > 0) && (start > 0)) {
3786 time(&current);
3787 if ((current - start) >= timeout) {
3788 reason = "timeout";
3789 if (fr) {
3790 ast_frfree(fr);
3791 fr = NULL;
3792 }
3793 break;
3794 }
3795 }
3796
3797 /* Check the speech structure for any changes */
3798 ast_mutex_lock(&speech->lock);
3799
3800 /* See if we need to quiet the audio stream playback */
3801 if (ast_test_flag(speech, AST_SPEECH_QUIET) && ast_channel_stream(chan)) {
3802 current_offset = ast_tellstream(ast_channel_stream(chan));
3803 ast_stopstream(chan);
3805 }
3806
3807 /* Check each state */
3808 switch (speech->state) {
3810 /* If the stream is done, start timeout calculation */
3811 if ((timeout > 0) && start == 0 && ((!ast_channel_stream(chan)) || (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL))) {
3812 ast_stopstream(chan);
3813 time(&start);
3814 }
3815 /* Write audio frame data into speech engine if possible */
3816 if (fr && fr->frametype == AST_FRAME_VOICE)
3817 ast_speech_write(speech, fr->data.ptr, fr->datalen);
3818 break;
3820 /* Cue waiting sound if not already playing */
3821 if ((!ast_channel_stream(chan)) || (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL)) {
3822 ast_stopstream(chan);
3823 /* If a processing sound exists, or is not none - play it */
3824 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
3826 }
3827 break;
3829 /* Get the results */
3830 speech->results = ast_speech_results_get(speech);
3831 /* Change state to not ready */
3833 reason = "speech";
3834 break;
3835 default:
3836 break;
3837 }
3838 ast_mutex_unlock(&speech->lock);
3839
3840 /* Check frame for DTMF or hangup */
3841 if (fr) {
3842 if (fr->frametype == AST_FRAME_DTMF) {
3843 reason = "dtmf";
3844 dtmf = fr->subclass.integer;
3845 } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_HANGUP) {
3846 reason = "hangup";
3847 }
3848 ast_frfree(fr);
3849 fr = NULL;
3850 }
3851 }
3852
3853 if (!strcasecmp(reason, "speech")) {
3854 /* Build string containing speech results */
3855 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
3856 /* Build result string */
3857 ast_build_string(&buf, &left, "%sscore%d=%d text%d=\"%s\" grammar%d=%s", (i > 0 ? " " : ""), i, result->score, i, result->text, i, result->grammar);
3858 /* Increment result count */
3859 i++;
3860 }
3861 /* Print out */
3862 ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
3863 } else if (!strcasecmp(reason, "dtmf")) {
3864 ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
3865 } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
3866 ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
3867 } else {
3868 ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
3869 }
3870
3871 return RESULT_SUCCESS;
3872}
3873
3874/*!
3875 * \brief AGI commands list
3876 */
3877static struct agi_command commands[] = {
3878 { { "answer", NULL }, handle_answer, NULL, NULL, 0 },
3879 { { "asyncagi", "break", NULL }, handle_asyncagi_break, NULL, NULL, 1 },
3880 { { "channel", "status", NULL }, handle_channelstatus, NULL, NULL, 0 },
3881 { { "database", "del", NULL }, handle_dbdel, NULL, NULL, 1 },
3882 { { "database", "deltree", NULL }, handle_dbdeltree, NULL, NULL, 1 },
3883 { { "database", "get", NULL }, handle_dbget, NULL, NULL, 1 },
3884 { { "database", "put", NULL }, handle_dbput, NULL, NULL, 1 },
3885 { { "exec", NULL }, handle_exec, NULL, NULL, 1 },
3886 { { "get", "data", NULL }, handle_getdata, NULL, NULL, 0 },
3887 { { "get", "full", "variable", NULL }, handle_getvariablefull, NULL, NULL, 1 },
3888 { { "get", "option", NULL }, handle_getoption, NULL, NULL, 0 },
3889 { { "get", "variable", NULL }, handle_getvariable, NULL, NULL, 1 },
3890 { { "hangup", NULL }, handle_hangup, NULL, NULL, 0 },
3891 { { "noop", NULL }, handle_noop, NULL, NULL, 1 },
3892 { { "receive", "char", NULL }, handle_recvchar, NULL, NULL, 0 },
3893 { { "receive", "text", NULL }, handle_recvtext, NULL, NULL, 0 },
3894 { { "record", "file", NULL }, handle_recordfile, NULL, NULL, 0 },
3895 { { "say", "alpha", NULL }, handle_sayalpha, NULL, NULL, 0},
3896 { { "say", "digits", NULL }, handle_saydigits, NULL, NULL, 0 },
3897 { { "say", "number", NULL }, handle_saynumber, NULL, NULL, 0 },
3898 { { "say", "phonetic", NULL }, handle_sayphonetic, NULL, NULL, 0},
3899 { { "say", "date", NULL }, handle_saydate, NULL, NULL, 0},
3900 { { "say", "time", NULL }, handle_saytime, NULL, NULL, 0},
3901 { { "say", "datetime", NULL }, handle_saydatetime, NULL, NULL, 0},
3902 { { "send", "image", NULL }, handle_sendimage, NULL, NULL, 0},
3903 { { "send", "text", NULL }, handle_sendtext, NULL, NULL, 0},
3904 { { "set", "autohangup", NULL }, handle_autohangup, NULL, NULL, 0},
3905 { { "set", "callerid", NULL }, handle_setcallerid, NULL, NULL, 0},
3906 { { "set", "context", NULL }, handle_setcontext, NULL, NULL, 0},
3907 { { "set", "extension", NULL }, handle_setextension, NULL, NULL, 0},
3908 { { "set", "music", NULL }, handle_setmusic, NULL, NULL, 0 },
3909 { { "set", "priority", NULL }, handle_setpriority, NULL, NULL, 0 },
3910 { { "set", "variable", NULL }, handle_setvariable, NULL, NULL, 1 },
3911 { { "stream", "file", NULL }, handle_streamfile, NULL, NULL, 0 },
3912 { { "control", "stream", "file", NULL }, handle_controlstreamfile, NULL, NULL, 0 },
3913 { { "tdd", "mode", NULL }, handle_tddmode, NULL, NULL, 0 },
3914 { { "verbose", NULL }, handle_verbose, NULL, NULL, 1 },
3915 { { "wait", "for", "digit", NULL }, handle_waitfordigit, NULL, NULL, 0 },
3916 { { "speech", "create", NULL }, handle_speechcreate, NULL, NULL, 0 },
3917 { { "speech", "set", NULL }, handle_speechset, NULL, NULL, 0 },
3918 { { "speech", "destroy", NULL }, handle_speechdestroy, NULL, NULL, 1 },
3919 { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, NULL, NULL, 0 },
3920 { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, NULL, NULL, 1 },
3921 { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, NULL, NULL, 0 },
3922 { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, NULL, NULL, 0 },
3923 { { "speech", "recognize", NULL }, handle_speechrecognize, NULL, NULL, 0 },
3924};
3925
3927
3928static char *help_workhorse(int fd, const char * const match[])
3929{
3930 char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
3931 struct agi_command *e;
3932
3933 if (match)
3934 ast_join(matchstr, sizeof(matchstr), match);
3935
3936 ast_cli(fd, "%5.5s %30.30s %s\n","Dead","Command","Description");
3939 if (!e->cmda[0])
3940 break;
3941 /* Hide commands that start with '_' */
3942 if ((e->cmda[0])[0] == '_')
3943 continue;
3944 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
3945 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
3946 continue;
3947 ast_cli(fd, "%5.5s %30.30s %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
3948 }
3950
3951 return CLI_SUCCESS;
3952}
3953
3955{
3956 char fullcmd[MAX_CMD_LEN];
3957
3958 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
3959
3960 if (!find_command(cmd->cmda, 1)) {
3961 *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
3962 if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
3963#ifdef AST_XML_DOCS
3964 *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd, NULL);
3965 *((char **) &cmd->since) = ast_xmldoc_build_since("agi", fullcmd, NULL);
3966 *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd, NULL);
3967 *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd, NULL);
3968 *((char **) &cmd->arguments) = ast_xmldoc_build_arguments("agi", fullcmd, NULL);
3969 *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd, NULL);
3970 *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
3971#endif
3972#ifndef HAVE_NULLSAFE_PRINTF
3973 if (!cmd->summary) {
3974 *((char **) &cmd->summary) = ast_strdup("");
3975 }
3976 if (!cmd->usage) {
3977 *((char **) &cmd->usage) = ast_strdup("");
3978 }
3979 if (!cmd->syntax) {
3980 *((char **) &cmd->syntax) = ast_strdup("");
3981 }
3982 if (!cmd->seealso) {
3983 *((char **) &cmd->seealso) = ast_strdup("");
3984 }
3985#endif
3986 }
3987
3988 cmd->mod = mod;
3992 ast_verb(5, "AGI Command '%s' registered\n",fullcmd);
3993 return 1;
3994 } else {
3995 ast_log(LOG_WARNING, "Command already registered!\n");
3996 return 0;
3997 }
3998}
3999
4001{
4002 struct agi_command *e;
4003 int unregistered = 0;
4004 char fullcmd[MAX_CMD_LEN];
4005
4006 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
4007
4010 if (cmd == e) {
4012#ifdef AST_XML_DOCS
4013 if (e->docsrc == AST_XML_DOC) {
4014 ast_free((char *) e->summary);
4015 ast_free((char *) e->since);
4016 ast_free((char *) e->usage);
4017 ast_free((char *) e->syntax);
4018 ast_free((char *) e->arguments);
4019 ast_free((char *) e->seealso);
4020 *((char **) &e->summary) = NULL;
4021 *((char **) &e->since) = NULL;
4022 *((char **) &e->usage) = NULL;
4023 *((char **) &e->syntax) = NULL;
4024 *((char **) &e->arguments) = NULL;
4025 *((char **) &e->seealso) = NULL;
4026 }
4027#endif
4028 unregistered=1;
4029 break;
4030 }
4031 }
4034 if (unregistered) {
4035 ast_verb(5, "AGI Command '%s' unregistered\n",fullcmd);
4036 }
4037 return unregistered;
4038}
4039
4041{
4042 unsigned int i, x = 0;
4043
4044 for (i = 0; i < len; i++) {
4045 if (ast_agi_register(mod, cmd + i) == 1) {
4046 x++;
4047 continue;
4048 }
4049
4050 /* registration failed, unregister everything
4051 that had been registered up to that point
4052 */
4053 for (; x > 0; x--) {
4054 /* we are intentionally ignoring the
4055 result of ast_agi_unregister() here,
4056 but it should be safe to do so since
4057 we just registered these commands and
4058 the only possible way for unregistration
4059 to fail is if the command is not
4060 registered
4061 */
4062 (void) ast_agi_unregister(cmd + x - 1);
4063 }
4064 return -1;
4065 }
4066
4067 return 0;
4068}
4069
4071{
4072 unsigned int i;
4073 int res = 0;
4074
4075 for (i = 0; i < len; i++) {
4076 /* remember whether any of the unregistration
4077 attempts failed... there is no recourse if
4078 any of them do
4079 */
4080 res |= ast_agi_unregister(cmd + i);
4081 }
4082
4083 return res;
4084}
4085
4086static agi_command *find_command(const char * const cmds[], int exact)
4087{
4088 int y, match;
4089 struct agi_command *e;
4090
4093 if (!e->cmda[0])
4094 break;
4095 /* start optimistic */
4096 match = 1;
4097 for (y = 0; match && cmds[y]; y++) {
4098 /* If there are no more words in the command (and we're looking for
4099 an exact match) or there is a difference between the two words,
4100 then this is not a match */
4101 if (!e->cmda[y] && !exact)
4102 break;
4103 /* don't segfault if the next part of a command doesn't exist */
4104 if (!e->cmda[y]) {
4106 return NULL;
4107 }
4108 if (strcasecmp(e->cmda[y], cmds[y]))
4109 match = 0;
4110 }
4111 /* If more words are needed to complete the command then this is not
4112 a candidate (unless we're looking for a really inexact answer */
4113 if ((exact > -1) && e->cmda[y])
4114 match = 0;
4115 if (match) {
4117 return e;
4118 }
4119 }
4121 return NULL;
4122}
4123
4124static int parse_args(char *s, int *max, const char *argv[])
4125{
4126 int x = 0, quoted = 0, escaped = 0, whitespace = 1;
4127 char *cur;
4128
4129 cur = s;
4130 while(*s) {
4131 switch(*s) {
4132 case '"':
4133 /* If it's escaped, put a literal quote */
4134 if (escaped)
4135 goto normal;
4136 else
4137 quoted = !quoted;
4138 if (quoted && whitespace) {
4139 /* If we're starting a quote, coming off white space start a new word, too */
4140 argv[x++] = cur;
4141 whitespace=0;
4142 }
4143 escaped = 0;
4144 break;
4145 case ' ':
4146 case '\t':
4147 if (!quoted && !escaped) {
4148 /* If we're not quoted, mark this as whitespace, and
4149 end the previous argument */
4150 whitespace = 1;
4151 *(cur++) = '\0';
4152 } else
4153 /* Otherwise, just treat it as anything else */
4154 goto normal;
4155 break;
4156 case '\\':
4157 /* If we're escaped, print a literal, otherwise enable escaping */
4158 if (escaped) {
4159 goto normal;
4160 } else {
4161 escaped=1;
4162 }
4163 break;
4164 default:
4165normal:
4166 if (whitespace) {
4167 if (x >= MAX_ARGS -1) {
4168 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
4169 break;
4170 }
4171 /* Coming off of whitespace, start the next argument */
4172 argv[x++] = cur;
4173 whitespace=0;
4174 }
4175 *(cur++) = *s;
4176 escaped=0;
4177 }
4178 s++;
4179 }
4180 /* Null terminate */
4181 *(cur++) = '\0';
4182 argv[x] = NULL;
4183 *max = x;
4184 return 0;
4185}
4186
4187static void publish_async_exec_end(struct ast_channel *chan, int command_id, const char *command, int result_code, const char *result)
4188{
4189 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4190 blob = ast_json_pack("{s: i, s: s, s: i, s: s}",
4191 "CommandId", command_id,
4192 "Command", command,
4193 "ResultCode", result_code,
4194 "Result", result);
4195 ast_channel_publish_cached_blob(chan, agi_exec_end_type(), blob);
4196}
4197
4198static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
4199{
4200 const char *argv[MAX_ARGS] = {0};
4201 int argc = MAX_ARGS;
4202 int res;
4203 agi_command *c;
4204 char *ami_cmd = ast_strdupa(buf);
4205 const char *ami_res;
4206 int command_id = ast_random();
4207 int resultcode = 0;
4208 RAII_VAR(struct ast_json *, startblob, NULL, ast_json_unref);
4209
4210 startblob = ast_json_pack("{s: i, s: s}",
4211 "CommandId", command_id,
4212 "Command", ami_cmd);
4213 ast_channel_publish_cached_blob(chan, agi_exec_start_type(), startblob);
4214
4215 parse_args(buf, &argc, argv);
4216 c = find_command(argv, 0);
4217 if (!c || !ast_module_running_ref(c->mod)) {
4218 ami_res = "Invalid or unknown command";
4219 resultcode = 510;
4220
4221 ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
4222
4223 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4224
4225 return AGI_RESULT_SUCCESS;
4226 }
4227
4228 if (!dead || (dead && c->dead)) {
4229 res = c->handler(chan, agi, argc, argv);
4230 switch (res) {
4231 case RESULT_SHOWUSAGE:
4232 ami_res = "Usage";
4233 resultcode = 520;
4234
4235 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4236
4237 if (ast_strlen_zero(c->usage)) {
4238 ast_agi_send(agi->fd, chan, "520 Invalid command syntax. Proper usage not available.\n");
4239 } else {
4240 ast_agi_send(agi->fd, chan, "520-Invalid command syntax. Proper usage follows:\n");
4241 ast_agi_send(agi->fd, chan, "%s\n", c->usage);
4242 ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
4243 }
4244
4245 break;
4246 case RESULT_FAILURE:
4247 ami_res = "Failure";
4248 resultcode = -1;
4249
4250 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4251
4252 /* The RESULT_FAILURE code is usually because the channel hungup. */
4253 return AGI_RESULT_FAILURE;
4254 case ASYNC_AGI_BREAK:
4255 ami_res = "Success";
4256 resultcode = 200;
4257
4258 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4259
4261 case RESULT_SUCCESS:
4262 ami_res = "Success";
4263 resultcode = 200;
4264
4265 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4266
4267 break;
4268 default:
4269 ami_res = "Unknown Result";
4270 resultcode = 200;
4271
4272 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4273
4274 break;
4275 }
4276 } else {
4277 ami_res = "Command Not Permitted on a dead channel or intercept routine";
4278 resultcode = 511;
4279
4280 ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
4281
4282 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4283 }
4284 ast_module_unref(c->mod);
4285
4286 return AGI_RESULT_SUCCESS;
4287}
4288
4289static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
4290{
4291 struct ast_channel *c;
4292 int outfd;
4293 int ms;
4294 int needhup = 0;
4295 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
4296 struct ast_frame *f;
4297 char buf[AGI_BUF_LEN];
4298 char *res = NULL;
4299 FILE *readf;
4300 /* how many times we'll retry if ast_waitfor_nandfs will return without either
4301 channel or file descriptor in case select is interrupted by a system call (EINTR) */
4302 int retry = AGI_NANDFS_RETRY;
4303 int send_sighup;
4304 const char *sighup_str;
4305 const char *exit_on_hangup_str;
4306 int exit_on_hangup;
4307 /*! Running in an interception routine is like when channel is hung up. No touchy the channel frames. */
4308 int in_intercept = ast_channel_get_intercept_mode();
4309
4310 ast_channel_lock(chan);
4311 sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
4312 send_sighup = !ast_false(sighup_str);
4313 exit_on_hangup_str = pbx_builtin_getvar_helper(chan, "AGIEXITONHANGUP");
4314 exit_on_hangup = ast_true(exit_on_hangup_str);
4315 ast_channel_unlock(chan);
4316
4317 if (!(readf = fdopen(agi->ctrl, "r"))) {
4318 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
4319 if (send_sighup && pid > -1)
4320 kill(pid, SIGHUP);
4321 close(agi->ctrl);
4322 return AGI_RESULT_FAILURE;
4323 }
4324
4325 setlinebuf(readf);
4326 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
4327 for (;;) {
4328 if (needhup) {
4329 needhup = 0;
4330 dead = 1;
4331 if (send_sighup) {
4332 if (pid > -1) {
4333 kill(pid, SIGHUP);
4334 } else if (agi->fast) {
4335 ast_agi_send(agi->fd, chan, "HANGUP\n");
4336 }
4337 }
4338 if (exit_on_hangup) {
4339 break;
4340 }
4341 }
4342 ms = -1;
4343 if (dead || in_intercept) {
4344 c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
4345 } else if (!ast_check_hangup(chan)) {
4346 c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
4347 } else {
4348 /*
4349 * Read the channel control queue until it is dry so we can
4350 * switch to dead mode.
4351 */
4352 c = chan;
4353 }
4354 if (c) {
4355 retry = AGI_NANDFS_RETRY;
4356 /* Idle the channel until we get a command */
4357 f = ast_read(c);
4358 if (!f) {
4359 ast_debug(1, "%s hungup\n", ast_channel_name(chan));
4360 needhup = 1;
4361 if (!returnstatus) {
4362 returnstatus = AGI_RESULT_HANGUP;
4363 }
4364 } else {
4365 /* If it's voice, write it to the audio pipe */
4366 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
4367 /* Write, ignoring errors */
4368 if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
4369 }
4370 }
4371 ast_frfree(f);
4372 }
4373 } else if (outfd > -1) {
4374 size_t len = sizeof(buf);
4375 size_t buflen = 0;
4376 enum agi_result cmd_status;
4377
4378 retry = AGI_NANDFS_RETRY;
4379 buf[0] = '\0';
4380
4381 while (len > 1) {
4382 res = fgets(buf + buflen, len, readf);
4383 if (feof(readf))
4384 break;
4385 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
4386 break;
4387 if (res != NULL && !agi->fast)
4388 break;
4389 buflen = strlen(buf);
4390 if (buflen && buf[buflen - 1] == '\n')
4391 break;
4392 len = sizeof(buf) - buflen;
4393 if (agidebug)
4394 ast_verbose("AGI Rx << temp buffer %s - errno %s\nNo \\n received, checking again.\n", buf, strerror(errno));
4395 }
4396
4397 if (!buf[0]) {
4398 /* Program terminated */
4399 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", ast_channel_name(chan), request, returnstatus);
4400 if (pid > 0)
4401 waitpid(pid, status, 0);
4402 /* No need to kill the pid anymore, since they closed us */
4403 pid = -1;
4404 break;
4405 }
4406
4407 /* Special case for inability to execute child process */
4408 if (*buf && strncasecmp(buf, "failure", 7) == 0) {
4409 returnstatus = AGI_RESULT_FAILURE;
4410 break;
4411 }
4412
4413 /* get rid of trailing newline, if any */
4414 buflen = strlen(buf);
4415 if (buflen && buf[buflen - 1] == '\n') {
4416 buf[buflen - 1] = '\0';
4417 }
4418
4419 if (agidebug)
4420 ast_verbose("<%s>AGI Rx << %s\n", ast_channel_name(chan), buf);
4421 cmd_status = agi_handle_command(chan, agi, buf, dead || in_intercept);
4422 switch (cmd_status) {
4423 case AGI_RESULT_FAILURE:
4424 if (dead || in_intercept || !ast_check_hangup(chan)) {
4425 /* The failure was not because of a hangup. */
4426 returnstatus = AGI_RESULT_FAILURE;
4427 }
4428 break;
4429 default:
4430 break;
4431 }
4432 } else {
4433 if (--retry <= 0) {
4434 ast_log(LOG_WARNING, "No channel, no fd?\n");
4435 returnstatus = AGI_RESULT_FAILURE;
4436 break;
4437 }
4438 }
4439 }
4440
4441 if (agi->speech) {
4443 }
4444 /* Notify process */
4445 if (send_sighup) {
4446 if (pid > -1) {
4447 if (kill(pid, SIGHUP)) {
4448 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
4449 } else { /* Give the process a chance to die */
4450 usleep(1);
4451 }
4452 waitpid(pid, status, WNOHANG);
4453 } else if (agi->fast) {
4454 ast_agi_send(agi->fd, chan, "HANGUP\n");
4455 }
4456 }
4457 fclose(readf);
4458 return returnstatus;
4459}
4460
4461static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4462{
4463 struct agi_command *command;
4464 char fullcmd[MAX_CMD_LEN];
4465 int error = 0;
4466
4467 switch (cmd) {
4468 case CLI_INIT:
4469 e->command = "agi show commands [topic]";
4470 e->usage =
4471 "Usage: agi show commands [topic] <topic>\n"
4472 " When called with a topic as an argument, displays usage\n"
4473 " information on the given command. If called without a\n"
4474 " topic, it provides a list of AGI commands.\n";
4475 case CLI_GENERATE:
4476 return NULL;
4477 }
4478 if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
4479 return CLI_SHOWUSAGE;
4480 if (a->argc > e->args - 1) {
4481 command = find_command(a->argv + e->args, 1);
4482 if (command) {
4483 char *synopsis = NULL, *since = NULL, *description = NULL, *syntax = NULL, *arguments = NULL, *seealso = NULL;
4484
4485 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
4486
4487#ifdef AST_XML_DOCS
4488 if (command->docsrc == AST_XML_DOC) {
4489 synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
4490 since = ast_xmldoc_printable(S_OR(command->since, "Not available"), 1);
4491 description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
4492 syntax = ast_xmldoc_printable(S_OR(command->syntax, "Not available"), 1);
4493 arguments = ast_xmldoc_printable(S_OR(command->arguments, "Not available"), 1);
4494 seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
4495 } else
4496#endif
4497 {
4498 synopsis = ast_strdup(S_OR(command->summary, "Not Available"));
4499 since = ast_strdup(S_OR(command->since, "Not Available"));
4500 description = ast_strdup(S_OR(command->usage, "Not Available"));
4501 syntax = ast_strdup(S_OR(command->syntax, "Not Available"));
4502 arguments = ast_strdup(S_OR(command->arguments, "Not Available"));
4503 seealso = ast_strdup(S_OR(command->seealso, "Not Available"));
4504 }
4505
4506 if (!synopsis || !since || !description || !syntax || !arguments || !seealso) {
4507 error = 1;
4508 goto return_cleanup;
4509 }
4510
4511 ast_cli(a->fd, "\n"
4512 "%s -= Info about AGI '%s' =- %s\n\n"
4513 COLORIZE_FMT "\n"
4514 "%s\n\n"
4515 COLORIZE_FMT "\n"
4516 "%s\n\n"
4517 COLORIZE_FMT "\n"
4518 "%s\n\n"
4519 COLORIZE_FMT "\n"
4520 "%s\n\n"
4521 COLORIZE_FMT "\n"
4522 "%s\n\n"
4523 COLORIZE_FMT "\n"
4524 "%s\n\n"
4525 COLORIZE_FMT "\n"
4526 "%s\n\n",
4528 COLORIZE(COLOR_MAGENTA, 0, "[Synopsis]"), synopsis,
4529 COLORIZE(COLOR_MAGENTA, 0, "[Since]"), since,
4530 COLORIZE(COLOR_MAGENTA, 0, "[Description]"), description,
4531 COLORIZE(COLOR_MAGENTA, 0, "[Syntax]"), syntax,
4532 COLORIZE(COLOR_MAGENTA, 0, "[Arguments]"), arguments,
4533 COLORIZE(COLOR_MAGENTA, 0, "[Runs Dead]"), command->dead ? "Yes" : "No",
4534 COLORIZE(COLOR_MAGENTA, 0, "[See Also]"), seealso
4535 );
4536
4537return_cleanup:
4539 ast_free(since);
4540 ast_free(description);
4544 } else {
4545 if (find_command(a->argv + e->args, -1)) {
4546 return help_workhorse(a->fd, a->argv + e->args);
4547 } else {
4548 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
4549 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
4550 }
4551 }
4552 } else {
4553 return help_workhorse(a->fd, NULL);
4554 }
4555 return (error ? CLI_FAILURE : CLI_SUCCESS);
4556}
4557
4558/*! \brief Convert string to use HTML escaped characters
4559 \note Maybe this should be a generic function?
4560*/
4561static void write_html_escaped(FILE *htmlfile, char *str)
4562{
4563 char *cur = str;
4564
4565 while(*cur) {
4566 switch (*cur) {
4567 case '<':
4568 fprintf(htmlfile, "%s", "&lt;");
4569 break;
4570 case '>':
4571 fprintf(htmlfile, "%s", "&gt;");
4572 break;
4573 case '&':
4574 fprintf(htmlfile, "%s", "&amp;");
4575 break;
4576 case '"':
4577 fprintf(htmlfile, "%s", "&quot;");
4578 break;
4579 default:
4580 fprintf(htmlfile, "%c", *cur);
4581 break;
4582 }
4583 cur++;
4584 }
4585
4586 return;
4587}
4588
4589static int write_htmldump(const char *filename)
4590{
4591 struct agi_command *command;
4592 char fullcmd[MAX_CMD_LEN];
4593 FILE *htmlfile;
4594
4595 if (!(htmlfile = fopen(filename, "wt")))
4596 return -1;
4597
4598 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
4599 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
4600 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
4601
4604 char *tempstr, *stringp;
4605
4606 if (!command->cmda[0]) /* end ? */
4607 break;
4608 /* Hide commands that start with '_' */
4609 if ((command->cmda[0])[0] == '_')
4610 continue;
4611 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
4612
4613 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
4614 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
4615#ifdef AST_XML_DOCS
4616 stringp = ast_xmldoc_printable(command->usage, 0);
4617#else
4618 stringp = ast_strdup(command->usage);
4619#endif
4620 tempstr = strsep(&stringp, "\n");
4621
4622 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
4623 write_html_escaped(htmlfile, tempstr);
4624 fprintf(htmlfile, "</TD></TR>\n");
4625 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
4626
4627 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
4628 write_html_escaped(htmlfile, tempstr);
4629 fprintf(htmlfile, "<BR>\n");
4630 }
4631 fprintf(htmlfile, "</TD></TR>\n");
4632 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
4633 ast_free(stringp);
4634 }
4636 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
4637 fclose(htmlfile);
4638 return 0;
4639}
4640
4641static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4642{
4643 switch (cmd) {
4644 case CLI_INIT:
4645 e->command = "agi dump html";
4646 e->usage =
4647 "Usage: agi dump html <filename>\n"
4648 " Dumps the AGI command list in HTML format to the given\n"
4649 " file.\n";
4650 return NULL;
4651 case CLI_GENERATE:
4652 return NULL;
4653 }
4654 if (a->argc != e->args + 1)
4655 return CLI_SHOWUSAGE;
4656
4657 if (write_htmldump(a->argv[e->args]) < 0) {
4658 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
4659 return CLI_SHOWUSAGE;
4660 }
4661 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
4662 return CLI_SUCCESS;
4663}
4664
4665static int agi_exec_full(struct ast_channel *chan, const char *data, int enhanced, int dead)
4666{
4667 enum agi_result res;
4668 char *buf;
4669 int fds[2], efd = -1, pid = -1;
4670 int safe_fork_called = 0;
4672 AST_APP_ARG(arg)[MAX_ARGS];
4673 );
4674 AGI agi;
4675
4676 if (ast_strlen_zero(data)) {
4677 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
4678 return -1;
4679 }
4680 if (dead)
4681 ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
4682 memset(&agi, 0, sizeof(agi));
4683 buf = ast_strdupa(data);
4685 args.arg[args.argc] = NULL;
4686#if 0
4687 /* Answer if need be */
4688 if (chan->_state != AST_STATE_UP) {
4689 if (ast_answer(chan))
4690 return -1;
4691 }
4692#endif
4693 res = launch_script(chan, args.arg[0], args.argc, args.arg, fds, enhanced ? &efd : NULL, &pid, &safe_fork_called);
4694 /* Async AGI do not require run_agi(), so just proceed if normal AGI
4695 or Fast AGI are setup with success. */
4696 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
4697 int status = 0;
4698 agi.fd = fds[1];
4699 agi.ctrl = fds[0];
4700 agi.audio = efd;
4701 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
4702 res = run_agi(chan, args.arg[0], &agi, pid, &status, dead, args.argc, args.arg);
4703 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
4704 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
4705 res = AGI_RESULT_FAILURE;
4706 if (fds[1] != fds[0])
4707 close(fds[1]);
4708 if (efd > -1)
4709 close(efd);
4710 }
4711 if (safe_fork_called) {
4713 }
4714
4715 switch (res) {
4716 case AGI_RESULT_SUCCESS:
4719 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
4720 break;
4721 case AGI_RESULT_FAILURE:
4722 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
4723 break;
4725 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
4726 break;
4727 case AGI_RESULT_HANGUP:
4728 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
4729 return -1;
4730 }
4731
4732 return 0;
4733}
4734
4735static int agi_exec(struct ast_channel *chan, const char *data)
4736{
4737 if (!ast_check_hangup(chan))
4738 return agi_exec_full(chan, data, 0, 0);
4739 else
4740 return agi_exec_full(chan, data, 0, 1);
4741}
4742
4743static int eagi_exec(struct ast_channel *chan, const char *data)
4744{
4745 int res;
4746 struct ast_format *readformat;
4747 struct ast_format *requested_format = NULL;
4748 const char *requested_format_name;
4749
4750 if (ast_check_hangup(chan)) {
4751 ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
4752 return 0;
4753 }
4754
4755 requested_format_name = pbx_builtin_getvar_helper(chan, "EAGI_AUDIO_FORMAT");
4756 if (requested_format_name) {
4757 requested_format = ast_format_cache_get(requested_format_name);
4758 if (requested_format) {
4759 ast_verb(3, "<%s> Setting EAGI audio pipe format to %s\n",
4760 ast_channel_name(chan), ast_format_get_name(requested_format));
4761 } else {
4762 ast_log(LOG_ERROR, "Could not find requested format: %s\n", requested_format_name);
4763 }
4764 }
4765
4766 readformat = ao2_bump(ast_channel_readformat(chan));
4767 if (ast_set_read_format(chan, requested_format ?: ast_format_slin)) {
4768 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", ast_channel_name(chan));
4769 ao2_cleanup(requested_format);
4770 ao2_cleanup(readformat);
4771 return -1;
4772 }
4773 res = agi_exec_full(chan, data, 1, 0);
4774 if (!res) {
4775 if (ast_set_read_format(chan, readformat)) {
4776 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", ast_channel_name(chan),
4777 ast_format_get_name(readformat));
4778 }
4779 }
4780 ao2_cleanup(requested_format);
4781 ao2_cleanup(readformat);
4782 return res;
4783}
4784
4785static struct ast_cli_entry cli_agi[] = {
4786 AST_CLI_DEFINE(handle_cli_agi_add_cmd, "Add AGI command to a channel in Async AGI"),
4787 AST_CLI_DEFINE(handle_cli_agi_debug, "Enable/Disable AGI debugging"),
4788 AST_CLI_DEFINE(handle_cli_agi_show, "List AGI commands or specific help"),
4789 AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format")
4790};
4791
4792#ifdef TEST_FRAMEWORK
4793AST_TEST_DEFINE(test_agi_null_docs)
4794{
4795 int res = AST_TEST_PASS;
4796 struct agi_command noop_command =
4797 { { "testnoop", NULL }, handle_noop, NULL, NULL, 0 };
4798
4799 switch (cmd) {
4800 case TEST_INIT:
4801 info->name = "null_agi_docs";
4802 info->category = "/res/agi/";
4803 info->summary = "AGI command with no documentation";
4804 info->description = "Test whether an AGI command with no documentation will crash Asterisk";
4805 return AST_TEST_NOT_RUN;
4806 case TEST_EXECUTE:
4807 break;
4808 }
4809
4810 if (ast_agi_register(ast_module_info->self, &noop_command) == 0) {
4811 ast_test_status_update(test, "Unable to register testnoop command, because res_agi is not loaded.\n");
4812 return AST_TEST_NOT_RUN;
4813 }
4814
4815#ifndef HAVE_NULLSAFE_PRINTF
4816 /* Test for condition without actually crashing Asterisk */
4817 if (noop_command.usage == NULL) {
4818 ast_test_status_update(test, "AGI testnoop usage was not updated properly.\n");
4819 res = AST_TEST_FAIL;
4820 }
4821 if (noop_command.syntax == NULL) {
4822 ast_test_status_update(test, "AGI testnoop syntax was not updated properly.\n");
4823 res = AST_TEST_FAIL;
4824 }
4825#endif
4826
4827 ast_agi_unregister(&noop_command);
4828 return res;
4829}
4830#endif
4831
4832static int unload_module(void)
4833{
4834 STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_start_type);
4835 STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_end_type);
4836 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_start_type);
4837 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_exec_type);
4838 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_end_type);
4839
4845 AST_TEST_UNREGISTER(test_agi_null_docs);
4846 return 0;
4847}
4848
4849static int load_module(void)
4850{
4851 int err = 0;
4852
4853 err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_start_type);
4854 err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_end_type);
4855 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_start_type);
4856 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_exec_type);
4857 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_end_type);
4858
4864
4865 AST_TEST_REGISTER(test_agi_null_docs);
4866
4867 if (err) {
4868 unload_module();
4870 }
4871
4873}
4874
4876 .support_level = AST_MODULE_SUPPORT_CORE,
4877 .load = load_module,
4878 .unload = unload_module,
4879 .load_pri = AST_MODPRI_APP_DEPEND,
4880 .requires = "res_speech",
AGI Extension interfaces - Asterisk Gateway Interface.
jack_status_t status
Definition: app_jack.c:149
const char * str
Definition: app_jack.c:150
unsigned int stop
Definition: app_sla.c:342
static int skipms
Asterisk version information.
const char * ast_get_version(void)
Retrieve the Asterisk version string.
Persistent data storage (akin to *doze registry)
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: db.c:335
int ast_db_get(const char *family, const char *key, char *value, int valuelen)
Get key value specified by family/key.
Definition: db.c:421
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: db.c:472
int ast_db_deltree(const char *family, const char *keytree)
Delete one or more entries in astdb.
Definition: db.c:559
int setenv(const char *name, const char *value, int overwrite)
char * strsep(char **str, const char *delims)
static struct ast_str * prompt
Definition: asterisk.c:2795
Asterisk main include file. File version handling, generic pbx functions.
#define AST_FILE_MODE
Definition: asterisk.h:32
int ast_set_priority(int)
We set ourselves to a high priority, that we might pre-empt everything else. If your PBX has heavy ac...
Definition: asterisk.c:1853
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)
Definition: callerid.c:1162
void ast_shrink_phone_number(char *n)
Shrink a phone number in place to just digits (more accurately it just removes ()'s,...
Definition: callerid.c:1101
enum ast_cc_service_type service
Definition: ccss.c:389
static void suspend(struct cc_core_instance *core_instance)
Definition: ccss.c:3166
static PGresult * result
Definition: cel_pgsql.c:84
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2388
static const char type[]
Definition: chan_ooh323.c:109
static int request(void *obj)
Definition: chan_pjsip.c:2619
General Asterisk PBX channel definitions.
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
const char * ast_channel_name(const struct ast_channel *chan)
char * ast_recvtext(struct ast_channel *chan, int timeout)
Receives a text string from a channel Read a string of text from a channel.
Definition: channel.c:4685
void ast_channel_stream_set(struct ast_channel *chan, struct ast_filestream *value)
struct ast_channel * ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds, int *exception, int *outfd, int *ms)
Waits for activity on a group of channels.
Definition: channel.c:2958
const char * ast_channel_data(const struct ast_channel *chan)
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition: channel.c:11048
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2355
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1789
#define ast_channel_lock(chan)
Definition: channel.h:2972
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8178
int ast_recvchar(struct ast_channel *chan, int timeout)
Receives a text character from a channel.
Definition: channel.c:4674
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3132
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
int ast_channel_get_intercept_mode(void)
Am I currently running an intercept dialplan routine.
Definition: channel.c:10347
int ast_channel_priority(const struct ast_channel *chan)
void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
Stops a previously-started silence generator on the given channel.
Definition: channel.c:8224
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2997
@ AST_FLAG_DISABLE_WORKAROUNDS
Definition: channel.h:1042
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_accountcode(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
int ast_check_hangup_locked(struct ast_channel *chan)
Definition: channel.c:459
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4223
int ast_sendtext(struct ast_channel *chan, const char *text)
Sends text to a channel.
Definition: channel.c:4777
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition: channel.c:7316
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition: channel.c:1398
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5730
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
@ AST_SOFTHANGUP_EXPLICIT
Definition: channel.h:1168
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force)
Set the source of the hangup in this channel and it's bridge.
Definition: channel.c:2469
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2441
ast_timing_func_t ast_channel_timingfunc(const struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3008
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
void ast_channel_setwhentohangup_tv(struct ast_channel *chan, struct timeval offset)
Set when to hang a channel up.
Definition: channel.c:510
const char * ast_channel_language(const struct ast_channel *chan)
void ast_channel_context_set(struct ast_channel *chan, const char *value)
int ast_channel_streamid(const struct ast_channel *chan)
struct ast_sched_context * ast_channel_sched(const struct ast_channel *chan)
struct ast_filestream * ast_channel_stream(const struct ast_channel *chan)
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7404
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2776
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4243
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2973
int ast_waitfordigit_full(struct ast_channel *c, int ms, const char *breakon, int audiofd, int ctrlfd)
Wait for a digit Same as ast_waitfordigit() with audio fd for outputting read audio and ctrlfd to mon...
Definition: channel.c:3209
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2369
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
size_t current
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
#define RESULT_SHOWUSAGE
Definition: cli.h:41
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define RESULT_SUCCESS
Definition: cli.h:40
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Definition: main/cli.c:1842
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define RESULT_FAILURE
Definition: cli.h:42
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
Convenient Signal Processing routines.
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set the minimum average magnitude threshold to determine talking by the DSP.
Definition: dsp.c:1790
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1785
@ THRESHOLD_SILENCE
Definition: dsp.h:73
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
Definition: dsp.c:1490
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:2011
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1760
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2204
#define max(a, b)
Definition: f2c.h:198
Generic File Format Support. Should be included by clients of the file handling routines....
off_t ast_tellstream(struct ast_filestream *fs)
Tell where we are in a stream.
Definition: file.c:1104
struct ast_filestream * ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
Opens stream for use in seeking, playing.
Definition: file.c:856
int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int monfd)
Definition: file.c:1883
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:223
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition: file.c:255
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
Definition: file.c:1094
int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
Rewind stream ms.
Definition: file.c:1119
int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
Applies a open stream to a channel.
Definition: file.c:1076
struct ast_filestream * ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
Opens stream for use in seeking, playing.
Definition: file.c:867
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1312
struct ast_filestream * ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts writing a file.
Definition: file.c:1457
int ast_truncstream(struct ast_filestream *fs)
Trunc stream at current location.
Definition: file.c:1099
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1130
int ast_playstream(struct ast_filestream *s)
Play a open stream on a channel.
Definition: file.c:1082
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1874
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
Media Format Cache API.
#define ast_format_cache_get(name)
Retrieve a named format from the cache.
Definition: format_cache.h:278
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
static const char name[]
Definition: format_mp3.c:68
static char * synopsis
Definition: func_enum.c:166
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1982
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2014
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition: manager.c:551
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1643
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7695
void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message using the latest snapshot from the cache.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest_by_name(const char *name)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
General Asterisk channel definitions for image handling.
int ast_send_image(struct ast_channel *chan, const char *filename)
Sends an image.
Definition: image.c:158
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
Full version with audiofd and controlfd. NOTE: returns '2' on ctrlfd available, not '1' like other fu...
Definition: main/app.c:247
void ast_safe_fork_cleanup(void)
Common routine to cleanup after fork'ed process is complete (if reaping was stopped)
Definition: main/app.c:3268
int ast_control_streamfile(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *pause, const char *restart, int skipms, long *offsetms)
Stream a file with fast forward, pause, reverse, restart.
Definition: main/app.c:1465
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child.
Definition: main/app.c:3207
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
Definition: main/app.c:3202
#define AST_FRAME_DTMF
#define ast_frfree(fr)
#define AST_OPTION_TDD
@ AST_FRAME_VIDEO
@ AST_FRAME_VOICE
@ AST_FRAME_CONTROL
@ AST_CONTROL_VIDUPDATE
@ AST_CONTROL_HANGUP
@ AST_CONTROL_STREAM_STOP
#define ast_debug(level,...)
Log a DEBUG message.
void ast_child_verbose(int level, const char *fmt,...)
Definition: logger.c:913
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:278
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:414
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:570
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:545
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
Definition: linkedlists.h:333
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:617
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:173
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
Asterisk locking-related definitions:
#define ast_mutex_unlock(a)
Definition: lock.h:197
#define ast_mutex_lock(a)
Definition: lock.h:196
int errno
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:192
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:10141
#define EVENT_FLAG_AGI
Definition: manager.h:88
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:330
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:483
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_APP_DEPEND
Definition: module.h:342
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
#define ast_module_running_ref(mod)
Hold a reference to the module if it is running.
Definition: module.h:469
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
Music on hold handling.
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7748
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7758
def info(msg)
Network socket handling.
int ast_connect(int sockfd, const struct ast_sockaddr *addr)
Wrapper around connect(2) that uses struct ast_sockaddr.
Definition: netsock2.c:595
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:256
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition: netsock2.h:517
int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, int flags, int family)
Parses a string with an IPv4 or IPv6 address and place results into an array.
Definition: netsock2.c:280
@ AST_AF_UNSPEC
Definition: netsock2.h:54
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:532
Wrapper for network related headers, masking differences between various operating systems....
#define AST_OPTIONAL_API_NAME(name)
Expands to the name of the implementation function.
Definition: optional_api.h:228
#define ast_opt_transmit_silence
Definition: options.h:134
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_KEY_DIR
Definition: options.c:162
const char * ast_config_AST_MODULE_DIR
Definition: options.c:154
const char * ast_config_AST_RUN_DIR
Definition: options.c:163
const char * ast_config_AST_DATA_DIR
Definition: options.c:159
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:152
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:155
const char * ast_config_AST_AGI_DIR
Definition: options.c:161
const char * ast_config_AST_VAR_DIR
Definition: options.c:158
const char * ast_config_AST_CONFIG_FILE
Definition: options.c:153
const char * ast_config_AST_MONITOR_DIR
Definition: options.c:156
const char * ast_config_AST_LOG_DIR
Definition: options.c:160
Core PBX routines and definitions.
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
Definition: pbx.c:4201
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:6966
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
Retrieve the value of a builtin variable or variable from the channel variable stack.
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3578
static char * eapp
Definition: res_agi.c:1524
static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3011
static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2917
static int parse_args(char *s, int *max, const char *argv[])
Definition: res_agi.c:4124
static struct ast_cli_entry cli_agi[]
Definition: res_agi.c:4785
static struct ast_manager_event_blob * agi_exec_start_to_ami(struct stasis_message *message)
Definition: res_agi.c:1566
static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2965
static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3252
static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2507
static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3441
static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
Definition: res_agi.c:2449
#define AMI_BUF_SIZE
#define MAX_CMD_LEN
Definition: res_agi.c:1517
#define MAX_ARGS
Definition: res_agi.c:1516
static agi_command * find_command(const char *const cmds[], int exact)
Definition: res_agi.c:4086
static void agi_destroy_commands_cb(void *data)
Definition: res_agi.c:1656
static struct ast_manager_event_blob * agi_async_end_to_ami(struct stasis_message *message)
Definition: res_agi.c:1586
int AST_OPTIONAL_API_NAME() ast_agi_unregister_multiple(struct agi_command *cmd, unsigned int len)
Unregisters a group of AGI commands, provided as an array of struct agi_command entries.
Definition: res_agi.c:4070
static enum agi_result launch_ha_netscript(char *agiurl, char *argv[], int *fds)
Definition: res_agi.c:2272
static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3513
static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2565
static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3669
static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2992
static char * handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: res_agi.c:4461
static enum agi_result async_agi_read_frame(struct ast_channel *chan)
Definition: res_agi.c:1885
static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3651
static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3491
static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3371
static struct ast_manager_event_blob * agi_exec_end_to_ami(struct stasis_message *message)
Definition: res_agi.c:1571
static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2951
int AST_OPTIONAL_API_NAME() ast_agi_unregister(agi_command *cmd)
Unregisters an AGI command.
Definition: res_agi.c:4000
static int eagi_exec(struct ast_channel *chan, const char *data)
Definition: res_agi.c:4743
#define ASYNC_AGI_BREAK
Definition: res_agi.c:1536
static struct ast_manager_event_blob * agi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: res_agi.c:1547
static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
Definition: res_agi.c:2179
static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, const char *const argv[])
Definition: res_agi.c:3559
static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2831
static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2582
static int write_htmldump(const char *filename)
Definition: res_agi.c:4589
static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3633
static enum agi_result launch_script(struct ast_channel *chan, char *script, int argc, char *argv[], int *fds, int *efd, int *opid, int *safe_fork_called)
Definition: res_agi.c:2326
static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2513
static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
Definition: res_agi.c:1706
static struct ast_manager_event_blob * agi_async_exec_to_ami(struct stasis_message *message)
Definition: res_agi.c:1581
static int agi_exec_full(struct ast_channel *chan, const char *data, int enhanced, int dead)
Definition: res_agi.c:4665
#define MAX_AGI_CONNECT
Definition: res_agi.c:1531
static struct ast_threadstorage agi_buf
Definition: res_agi.c:1609
static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3502
static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3602
static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
Definition: res_agi.c:3705
static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
Definition: res_agi.c:4289
static char * handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: res_agi.c:4641
static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2610
static int add_to_agi(struct ast_channel *chan)
Definition: res_agi.c:1739
static int agi_exec(struct ast_channel *chan, const char *data)
Definition: res_agi.c:4735
static int get_agi_cmd(struct ast_channel *chan, struct agi_cmd **cmd)
Retrieve the list head to the requested channel's AGI datastore.
Definition: res_agi.c:1684
static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
get option - really similar to the handle_streamfile, but with a timeout
Definition: res_agi.c:2747
int AST_OPTIONAL_API_NAME() ast_agi_register(struct ast_module *mod, agi_command *cmd)
Registers an AGI command.
Definition: res_agi.c:3954
static int agidebug
Definition: res_agi.c:1526
static char * app
Definition: res_agi.c:1522
static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3230
static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3565
static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3002
static int action_add_agi_cmd(struct mansession *s, const struct message *m)
Add a new command to execute by the Async AGI application.
Definition: res_agi.c:1835
static struct ast_manager_event_blob * agi_async_start_to_ami(struct stasis_message *message)
Definition: res_agi.c:1576
#define AGI_BUF_SIZE
static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3458
static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3280
static struct agi_command commands[]
AGI commands list.
Definition: res_agi.c:3877
static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Say number in various language syntaxes.
Definition: res_agi.c:2816
#define AGI_BUF_INITSIZE
Definition: res_agi.c:1610
#define AGI_NANDFS_RETRY
Definition: res_agi.c:1518
static char * handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: res_agi.c:3530
static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3724
static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2626
static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3407
static int handle_connection(const char *agiurl, const struct ast_sockaddr addr, const int netsockfd)
Definition: res_agi.c:2138
static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3326
agi_result
Definition: res_agi.c:1538
@ AGI_RESULT_HANGUP
Definition: res_agi.c:1544
@ AGI_RESULT_SUCCESS
Definition: res_agi.c:1540
@ AGI_RESULT_FAILURE
Definition: res_agi.c:1539
@ AGI_RESULT_SUCCESS_ASYNC
Definition: res_agi.c:1542
@ AGI_RESULT_SUCCESS_FAST
Definition: res_agi.c:1541
@ AGI_RESULT_NOTFOUND
Definition: res_agi.c:1543
static void publish_async_exec_end(struct ast_channel *chan, int command_id, const char *command, int result_code, const char *result)
Definition: res_agi.c:4187
static int load_module(void)
Definition: res_agi.c:4849
static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2688
static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char *argv[], int *efd)
Definition: res_agi.c:1913
static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3620
static struct agi_commands agi_commands
#define SRV_PREFIX
Definition: res_agi.c:1520
static char * handle_cli_agi_add_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command to add applications to execute in Async AGI.
Definition: res_agi.c:1783
#define AGI_BUF_LEN
Definition: res_agi.c:1519
#define AGI_PORT
Definition: res_agi.c:1533
static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3030
static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2495
static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3384
STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_exec_start_type,.to_ami=agi_exec_start_to_ami,)
static int unload_module(void)
Definition: res_agi.c:4832
static char * help_workhorse(int fd, const char *const match[])
Definition: res_agi.c:3928
static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2526
static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2545
static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
Definition: res_agi.c:4198
static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2902
int AST_OPTIONAL_API_NAME() ast_agi_send(int fd, struct ast_channel *chan, char *fmt,...)
Sends a string of text to an application connected via AGI.
Definition: res_agi.c:1612
static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2887
int AST_OPTIONAL_API_NAME() ast_agi_register_multiple(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
Registers a group of AGI commands, provided as an array of struct agi_command entries.
Definition: res_agi.c:4040
static const struct ast_datastore_info agi_commands_datastore_info
Definition: res_agi.c:1670
static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3687
static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3347
static void free_agi_cmd(struct agi_cmd *cmd)
Definition: res_agi.c:1648
static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2847
static void write_html_escaped(FILE *htmlfile, char *str)
Convert string to use HTML escaped characters.
Definition: res_agi.c:4561
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
#define NULL
Definition: resample.c:96
Say numbers and dates (maybe words one day too)
SAY_EXTERN int(* ast_say_date)(struct ast_channel *chan, time_t t, const char *ints, const char *lang) SAY_INIT(ast_say_date)
Definition: say.h:204
SAY_EXTERN int(* ast_say_number_full)(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) SAY_INIT(ast_say_number_full)
Same as ast_say_number() with audiofd for received audio and returns 1 on ctrlfd being readable.
Definition: say.h:86
SAY_EXTERN int(* ast_say_character_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity, int audiofd, int ctrlfd) SAY_INIT(ast_say_character_str_full)
Definition: say.h:194
SAY_EXTERN int(* ast_say_date_with_format)(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *timezone) SAY_INIT(ast_say_date_with_format)
Definition: say.h:208
SAY_EXTERN int(* ast_say_digit_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, int audiofd, int ctrlfd) SAY_INIT(ast_say_digit_str_full)
Same as ast_say_digit_str() with audiofd for received audio and returns 1 on ctrlfd being readable.
Definition: say.h:162
@ AST_SAY_CASE_LOWER
Definition: say.h:183
@ AST_SAY_CASE_ALL
Definition: say.h:185
@ AST_SAY_CASE_UPPER
Definition: say.h:184
@ AST_SAY_CASE_NONE
Definition: say.h:182
SAY_EXTERN int(* ast_say_time)(struct ast_channel *chan, time_t t, const char *ints, const char *lang) SAY_INIT(ast_say_time)
Definition: say.h:202
SAY_EXTERN int(* ast_say_phonetic_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, int audiofd, int ctrlfd) SAY_INIT(ast_say_phonetic_str_full)
Definition: say.h:199
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Definition: sched.c:786
int ast_sched_wait(struct ast_sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place.
Definition: sched.c:433
Generic Speech Recognition API.
int ast_speech_grammar_deactivate(struct ast_speech *speech, const char *grammar_name)
Deactivate a grammar on a speech structure.
Definition: res_speech.c:72
int ast_speech_grammar_unload(struct ast_speech *speech, const char *grammar_name)
Unload a grammar.
Definition: res_speech.c:84
void ast_speech_start(struct ast_speech *speech)
Indicate to the speech engine that audio is now going to start being written.
Definition: res_speech.c:122
int ast_speech_write(struct ast_speech *speech, void *data, int len)
Write audio to the speech engine.
Definition: res_speech.c:144
int ast_speech_change(struct ast_speech *speech, const char *name, const char *value)
Change an engine specific attribute.
Definition: res_speech.c:169
struct ast_speech * ast_speech_new(const char *engine_name, const struct ast_format_cap *formats)
Create a new speech structure.
Definition: res_speech.c:181
int ast_speech_destroy(struct ast_speech *speech)
Destroy a speech structure.
Definition: res_speech.c:251
int ast_speech_grammar_load(struct ast_speech *speech, const char *grammar_name, const char *grammar)
Load a grammar on a speech structure (not globally)
Definition: res_speech.c:78
int ast_speech_grammar_activate(struct ast_speech *speech, const char *grammar_name)
Activate a grammar on a speech structure.
Definition: res_speech.c:66
int ast_speech_change_state(struct ast_speech *speech, int state)
Change state of a speech structure.
Definition: res_speech.c:278
@ AST_SPEECH_STATE_DONE
Definition: speech.h:42
@ AST_SPEECH_STATE_READY
Definition: speech.h:40
@ AST_SPEECH_STATE_NOT_READY
Definition: speech.h:39
@ AST_SPEECH_STATE_WAIT
Definition: speech.h:41
struct ast_speech_result * ast_speech_results_get(struct ast_speech *speech)
Get speech recognition results.
Definition: res_speech.c:90
@ AST_SPEECH_QUIET
Definition: speech.h:32
Support for DNS SRV records, used in to locate SIP services.
void ast_srv_cleanup(struct srv_context **context)
Cleanup resources associated with ast_srv_lookup.
Definition: srv.c:248
int ast_srv_lookup(struct srv_context **context, const char *service, const char **host, unsigned short *port)
Retrieve set of SRV lookups, in order.
Definition: srv.c:202
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
String manipulation functions.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
Definition: strings.h:1030
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2235
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
Parse a time (integer) string.
Definition: utils.c:2482
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
int ast_build_string(char **buffer, size_t *space, const char *fmt,...)
Build a string in a buffer, designed to be called repeatedly.
Definition: utils.c:2203
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2252
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
#define ast_str_make_space(buf, new_len)
Definition: strings.h:828
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
Definition: strings.h:703
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Definition: strings.h:97
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:742
#define ast_join(s, len, w)
Join an array of strings into a single string.
Definition: strings.h:520
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:909
struct agi_cmd::@429 entry
char * cmd_buffer
Definition: res_agi.c:1643
char * cmd_id
Definition: res_agi.c:1644
struct agi_command::@184 list
const char *const since
Definition: agi.h:64
const char *const summary
Definition: agi.h:48
const char *const arguments
Definition: agi.h:66
struct ast_module * mod
Definition: agi.h:60
enum ast_doc_src docsrc
Definition: agi.h:58
const char *const usage
Definition: agi.h:50
const int dead
Definition: agi.h:52
const char *const seealso
Definition: agi.h:56
const char *const syntax
Definition: agi.h:54
const char *const cmda[AST_MAX_CMD_LEN]
Definition: agi.h:43
Definition: agi.h:34
int ctrl
Definition: agi.h:37
int audio
Definition: agi.h:36
int fd
Definition: agi.h:35
unsigned int fast
Definition: agi.h:38
struct ast_speech * speech
Definition: agi.h:39
ast_app: A registered application
Definition: pbx_app.c:45
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot
struct ast_json * blob
Structure representing a snapshot of channel state.
enum ast_channel_state state
Main Channel structure associated with a channel.
descriptor for a cli entry.
Definition: cli.h:171
int args
This gets set in ast_cli_register()
Definition: cli.h:185
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
struct ast_datastore::@219 entry
void * data
Definition: datastore.h:66
Definition: dsp.c:407
int totalsilence
Definition: dsp.c:411
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition: mod_format.h:101
struct ast_filestream * vfs
Definition: mod_format.h:110
char * filename
Definition: mod_format.h:107
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Definition of a media format.
Definition: format.c:43
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
union ast_frame::@231 data
Abstract JSON element (object, array, string, int, ...).
Struct containing info for an AMI event to send out.
Definition: manager.h:503
struct ast_module * self
Definition: module.h:356
int dtimeoutms
Definition: pbx.h:216
Socket address structure.
Definition: netsock2.h:97
struct sockaddr_storage ss
Definition: netsock2.h:98
char * processing_sound
Definition: speech.h:60
int state
Definition: speech.h:62
ast_mutex_t lock
Definition: speech.h:56
struct ast_speech_result * results
Definition: speech.h:68
Support for dynamic strings.
Definition: strings.h:623
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:323
Number structure.
Definition: app_followme.c:157
Handy terminal functions for vt* terms.
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:357
#define COLOR_MAGENTA
Definition: term.h:60
const char * ast_term_color(int fgcolor, int bgcolor)
Return a color sequence string.
Definition: term.c:341
#define COLORIZE(fg, bg, str)
Definition: term.h:72
#define COLORIZE_FMT
Shortcut macros for coloring a set of text.
Definition: term.h:71
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
#define AST_TEST_DEFINE(hdr)
Definition: test.h:126
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_FAIL
Definition: test.h:196
@ AST_TEST_NOT_RUN
Definition: test.h:194
const char * args
static struct test_val a
static struct test_val c
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:86
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
int error(const char *format,...)
Definition: utils/frame.c:999
Utility functions.
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:978
int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
Try to write string, but wait no more than ms milliseconds before timing out.
Definition: utils.c:1807
char * ast_uri_encode(const char *string, char *outbuf, int buflen, struct ast_flags spec)
Turn text string to URI-encoded XX version.
Definition: utils.c:723
#define ast_socket_nonblock(domain, type, protocol)
Create a non-blocking socket.
Definition: utils.h:1110
#define ast_clear_flag(p, flag)
Definition: utils.h:77
long int ast_random(void)
Definition: utils.c:2348
const struct ast_flags ast_uri_http
Definition: utils.c:719
#define ast_fd_set_flags(fd, flags)
Set flags on the given file descriptor.
Definition: utils.h:1076
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:703
Asterisk XML Documentation API.
char * ast_xmldoc_build_description(const char *type, const char *name, const char *module)
Generate description documentation from XML.
Definition: xmldoc.c:2361
char * ast_xmldoc_build_syntax(const char *type, const char *name, const char *module)
Get the syntax for a specified application or function.
Definition: xmldoc.c:1252
char * ast_xmldoc_build_arguments(const char *type, const char *name, const char *module)
Generate the [arguments] tag based on type of node ('application', 'function' or 'agi') and name.
Definition: xmldoc.c:2174
char * ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module)
Generate synopsis documentation from XML.
Definition: xmldoc.c:2338
char * ast_xmldoc_build_since(const char *type, const char *name, const char *module)
Parse the <since> node content.
Definition: xmldoc.c:1792
ast_doc_src
From where the documentation come from, this structure is useful for use it inside application/functi...
Definition: xmldoc.h:30
@ AST_XML_DOC
Definition: xmldoc.h:31
@ AST_STATIC_DOC
Definition: xmldoc.h:32
char * ast_xmldoc_build_seealso(const char *type, const char *name, const char *module)
Parse the <see-also> node content.
Definition: xmldoc.c:1707
char * ast_xmldoc_printable(const char *bwinput, int withcolors)
Colorize and put delimiters (instead of tags) to the xmldoc output.
Definition: xmldoc.c:241