Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 using <literal>DeadAGI</literal>
1320 (or when the channel is already hungup). A fast AGI server will
1321 correspondingly receive a <literal>HANGUP</literal> inline with the command dialog.
1322 Both of these signals may be disabled by setting the <variable>AGISIGHUP</variable>
1323 channel variable to <literal>no</literal> before executing the AGI application.
1324 Alternatively, if you would like the AGI application to exit immediately
1325 after a channel hangup is detected, set the <variable>AGIEXITONHANGUP</variable>
1326 variable to <literal>yes</literal>.</para>
1327 </note>
1328 <example title="Start the AGI script /tmp/my-cool-script.sh, passing it the contents of the channel variable FOO">
1329 same => n,AGI(/tmp/my-cool-script.sh,${FOO})
1330 </example>
1331 <example title="Start the AGI script my-cool-script.sh located in the astagidir directory, specified in asterisk.conf">
1332 same => n,AGI(my-cool-script.sh)
1333 </example>
1334 <example title="Connect to the FastAGI server located at 127.0.0.1 and start the script awesome-script">
1335 same => n,AGI(agi://127.0.0.1/awesome-script)
1336 </example>
1337 <example title="Start AsyncAGI">
1338 same => n,AGI(agi:async)
1339 </example>
1340 <para>This application sets the following channel variable upon completion:</para>
1341 <variablelist>
1342 <variable name="AGISTATUS">
1343 <para>The status of the attempt to the run the AGI script
1344 text string, one of:</para>
1345 <value name="SUCCESS" />
1346 <value name="FAILURE" />
1347 <value name="NOTFOUND" />
1348 <value name="HANGUP" />
1349 </variable>
1350 </variablelist>
1351 </description>
1352 <see-also>
1353 <ref type="manager">AGI</ref>
1354 <ref type="managerEvent">AsyncAGIStart</ref>
1355 <ref type="managerEvent">AsyncAGIEnd</ref>
1356 <ref type="application">EAGI</ref>
1357 <ref type="application">DeadAGI</ref>
1358 <ref type="filename">asterisk.conf</ref>
1359 </see-also>
1360 </application>
1361 <application name="EAGI" language="en_US">
1362 <since>
1363 <version>0.4.0</version>
1364 </since>
1365 <synopsis>
1366 Executes an EAGI compliant application.
1367 </synopsis>
1368 <syntax>
1369 <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='command'])" />
1370 <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='args'])" />
1371 </syntax>
1372 <description>
1373 <para>Using 'EAGI' provides enhanced AGI, with incoming audio available out of band
1374 on file descriptor 3. In all other respects, it behaves in the same fashion as
1375 AGI. See the documentation for the <literal>AGI</literal> dialplan application for
1376 more information on invoking AGI on a channel.</para>
1377 <para>This application sets the following channel variable upon completion:</para>
1378 <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/variablelist)" />
1379 </description>
1380 <see-also>
1381 <ref type="application">AGI</ref>
1382 <ref type="application">DeadAGI</ref>
1383 </see-also>
1384 </application>
1385 <application name="DeadAGI" language="en_US">
1386 <since>
1387 <version>1.0.0</version>
1388 </since>
1389 <synopsis>
1390 Executes AGI on a hungup channel.
1391 </synopsis>
1392 <syntax>
1393 <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='command'])" />
1394 <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='args'])" />
1395 </syntax>
1396 <description>
1397 <warning>
1398 <para>This application is deprecated and may be removed in a future version
1399 of Asterisk. Use the replacement application <literal>AGI</literal> instead
1400 of <literal>DeadAGI</literal>.
1401 </para>
1402 </warning>
1403 <para>Execute AGI on a 'dead' or hungup channel. See the documentation for the
1404 <literal>AGI</literal> dialplan application for more information on invoking
1405 AGI on a channel.</para>
1406 <para>This application sets the following channel variable upon completion:</para>
1407 <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/variablelist)" />
1408 </description>
1409 <see-also>
1410 <ref type="application">AGI</ref>
1411 <ref type="application">EAGI</ref>
1412 </see-also>
1413 </application>
1414 <manager name="AGI" language="en_US">
1415 <since>
1416 <version>1.6.0</version>
1417 </since>
1418 <synopsis>
1419 Add an AGI command to execute by Async AGI.
1420 </synopsis>
1421 <syntax>
1422 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1423 <parameter name="Channel" required="true">
1424 <para>Channel that is currently in Async AGI.</para>
1425 </parameter>
1426 <parameter name="Command" required="true">
1427 <para>Application to execute.</para>
1428 </parameter>
1429 <parameter name="CommandID">
1430 <para>This will be sent back in CommandID header of AsyncAGI exec
1431 event notification.</para>
1432 </parameter>
1433 </syntax>
1434 <description>
1435 <para>Add an AGI command to the execute queue of the channel in Async AGI.</para>
1436 </description>
1437 <see-also>
1438 <ref type="managerEvent">AsyncAGIStart</ref>
1439 <ref type="managerEvent">AsyncAGIExec</ref>
1440 <ref type="managerEvent">AsyncAGIEnd</ref>
1441 </see-also>
1442 </manager>
1443 <managerEvent language="en_US" name="AsyncAGIStart">
1444 <managerEventInstance class="EVENT_FLAG_AGI">
1445 <since>
1446 <version>12.0.0</version>
1447 </since>
1448 <synopsis>Raised when a channel starts AsyncAGI command processing.</synopsis>
1449 <syntax>
1450 <channel_snapshot/>
1451 <parameter name="Env">
1452 <para>URL encoded string read from the AsyncAGI server.</para>
1453 </parameter>
1454 </syntax>
1455 <see-also>
1456 <ref type="managerEvent">AsyncAGIEnd</ref>
1457 <ref type="managerEvent">AsyncAGIExec</ref>
1458 <ref type="application">AGI</ref>
1459 <ref type="manager">AGI</ref>
1460 </see-also>
1461 </managerEventInstance>
1462 </managerEvent>
1463 <managerEvent language="en_US" name="AsyncAGIEnd">
1464 <managerEventInstance class="EVENT_FLAG_AGI">
1465 <since>
1466 <version>12.0.0</version>
1467 </since>
1468 <synopsis>Raised when a channel stops AsyncAGI command processing.</synopsis>
1469 <syntax>
1470 <channel_snapshot/>
1471 </syntax>
1472 <see-also>
1473 <ref type="managerEvent">AsyncAGIStart</ref>
1474 <ref type="managerEvent">AsyncAGIExec</ref>
1475 <ref type="application">AGI</ref>
1476 <ref type="manager">AGI</ref>
1477 </see-also>
1478 </managerEventInstance>
1479 </managerEvent>
1480 <managerEvent language="en_US" name="AsyncAGIExec">
1481 <managerEventInstance class="EVENT_FLAG_AGI">
1482 <since>
1483 <version>12.0.0</version>
1484 </since>
1485 <synopsis>Raised when AsyncAGI completes an AGI command.</synopsis>
1486 <syntax>
1487 <channel_snapshot/>
1488 <parameter name="CommandID" required="false">
1489 <para>Optional command ID sent by the AsyncAGI server to identify the command.</para>
1490 </parameter>
1491 <parameter name="Result">
1492 <para>URL encoded result string from the executed AGI command.</para>
1493 </parameter>
1494 </syntax>
1495 <see-also>
1496 <ref type="managerEvent">AsyncAGIStart</ref>
1497 <ref type="managerEvent">AsyncAGIEnd</ref>
1498 <ref type="application">AGI</ref>
1499 <ref type="manager">AGI</ref>
1500 </see-also>
1501 </managerEventInstance>
1502 </managerEvent>
1503 <managerEvent language="en_US" name="AGIExecStart">
1504 <managerEventInstance class="EVENT_FLAG_AGI">
1505 <since>
1506 <version>12.0.0</version>
1507 </since>
1508 <synopsis>Raised when a received AGI command starts processing.</synopsis>
1509 <syntax>
1510 <channel_snapshot/>
1511 <parameter name="Command">
1512 <para>The AGI command as received from the external source.</para>
1513 </parameter>
1514 <parameter name="CommandId">
1515 <para>Random identification number assigned to the execution of this command.</para>
1516 </parameter>
1517 </syntax>
1518 <see-also>
1519 <ref type="managerEvent">AGIExecEnd</ref>
1520 <ref type="application">AGI</ref>
1521 </see-also>
1522 </managerEventInstance>
1523 </managerEvent>
1524 <managerEvent language="en_US" name="AGIExecEnd">
1525 <managerEventInstance class="EVENT_FLAG_AGI">
1526 <since>
1527 <version>12.0.0</version>
1528 </since>
1529 <synopsis>Raised when a received AGI command completes processing.</synopsis>
1530 <syntax>
1531 <channel_snapshot/>
1532 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AGIExecStart']/managerEventInstance/syntax/parameter)" />
1533 <parameter name="ResultCode">
1534 <para>The numeric result code from AGI</para>
1535 </parameter>
1536 <parameter name="Result">
1537 <para>The text result reason from AGI</para>
1538 </parameter>
1539 </syntax>
1540 <see-also>
1541 <ref type="managerEvent">AGIExecStart</ref>
1542 <ref type="application">AGI</ref>
1543 </see-also>
1544 </managerEventInstance>
1545 </managerEvent>
1546 ***/
1547
1548#define MAX_ARGS 128
1549#define MAX_CMD_LEN 80
1550#define AGI_NANDFS_RETRY 3
1551#define AGI_BUF_LEN 2048
1552#define SRV_PREFIX "_agi._tcp."
1553
1554static char *app = "AGI";
1555
1556static char *eapp = "EAGI";
1557
1558static char *deadapp = "DeadAGI";
1559
1560static int agidebug = 0;
1561
1562#define TONE_BLOCK_SIZE 200
1563
1564/* Max time to connect to an AGI remote host */
1565#define MAX_AGI_CONNECT 2000
1566
1567#define AGI_PORT 4573
1568
1569/*! Special return code for "asyncagi break" command. */
1570#define ASYNC_AGI_BREAK 3
1571
1579};
1580
1582{
1584 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
1585 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
1586
1587 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1588 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
1589 if (!channel_string || !event_string) {
1590 return NULL;
1591 }
1592
1594 "%s"
1595 "%s",
1596 ast_str_buffer(channel_string),
1597 ast_str_buffer(event_string));
1598}
1599
1601{
1602 return agi_channel_to_ami("AGIExecStart", message);
1603}
1604
1606{
1607 return agi_channel_to_ami("AGIExecEnd", message);
1608}
1609
1611{
1612 return agi_channel_to_ami("AsyncAGIStart", message);
1613}
1614
1616{
1617 return agi_channel_to_ami("AsyncAGIExec", message);
1618}
1619
1621{
1622 return agi_channel_to_ami("AsyncAGIEnd", message);
1623}
1624
1627 );
1630 );
1633 );
1636 );
1639 );
1640
1641static agi_command *find_command(const char * const cmds[], int exact);
1642
1644#define AGI_BUF_INITSIZE 256
1645
1646int AST_OPTIONAL_API_NAME(ast_agi_send)(int fd, struct ast_channel *chan, char *fmt, ...)
1647{
1648 int res = 0;
1649 va_list ap;
1650 struct ast_str *buf;
1651
1653 return -1;
1654
1655 va_start(ap, fmt);
1656 res = ast_str_set_va(&buf, 0, fmt, ap);
1657 va_end(ap);
1658
1659 if (res == -1) {
1660 ast_log(LOG_ERROR, "Out of memory\n");
1661 return -1;
1662 }
1663
1664 if (agidebug) {
1665 if (chan) {
1666 ast_verbose("<%s>AGI Tx >> %s", ast_channel_name(chan), ast_str_buffer(buf));
1667 } else {
1668 ast_verbose("AGI Tx >> %s", ast_str_buffer(buf));
1669 }
1670 }
1671
1673}
1674
1675/* linked list of AGI commands ready to be executed by Async AGI */
1676struct agi_cmd {
1678 char *cmd_id;
1680};
1681
1682static void free_agi_cmd(struct agi_cmd *cmd)
1683{
1684 ast_free(cmd->cmd_buffer);
1685 ast_free(cmd->cmd_id);
1686 ast_free(cmd);
1687}
1688
1689/* AGI datastore destructor */
1690static void agi_destroy_commands_cb(void *data)
1691{
1692 struct agi_cmd *cmd;
1693 AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
1694 AST_LIST_LOCK(chan_cmds);
1695 while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
1696 free_agi_cmd(cmd);
1697 }
1698 AST_LIST_UNLOCK(chan_cmds);
1699 AST_LIST_HEAD_DESTROY(chan_cmds);
1700 ast_free(chan_cmds);
1701}
1702
1703/* channel datastore to keep the queue of AGI commands in the channel */
1705 .type = "AsyncAGI",
1706 .destroy = agi_destroy_commands_cb
1707};
1708
1709/*!
1710 * \brief Retrieve the list head to the requested channel's AGI datastore
1711 * \param chan Channel datastore is requested for
1712 * \param cmd Pointer to the struct pointer which will reference the head of the agi command list.
1713 *
1714 * \retval 0 if the datastore was valid and the list head was retrieved appropriately (even if it's
1715 * NULL and the list is empty)
1716 * \retval -1 if the datastore could not be retrieved causing an error
1717*/
1718static int get_agi_cmd(struct ast_channel *chan, struct agi_cmd **cmd)
1719{
1720 struct ast_datastore *store;
1722
1723 ast_channel_lock(chan);
1725 ast_channel_unlock(chan);
1726 if (!store) {
1727 ast_log(LOG_ERROR, "Huh? Async AGI datastore disappeared on Channel %s!\n",
1728 ast_channel_name(chan));
1729 *cmd = NULL;
1730 return -1;
1731 }
1732 agi_commands = store->data;
1736 return 0;
1737}
1738
1739/* channel is locked when calling this one either from the CLI or manager thread */
1740static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
1741{
1742 struct ast_datastore *store;
1743 struct agi_cmd *cmd;
1745
1747 if (!store) {
1748 ast_log(LOG_WARNING, "Channel %s is not setup for Async AGI.\n", ast_channel_name(chan));
1749 return -1;
1750 }
1751 agi_commands = store->data;
1752 cmd = ast_calloc(1, sizeof(*cmd));
1753 if (!cmd) {
1754 return -1;
1755 }
1756 cmd->cmd_buffer = ast_strdup(cmd_buff);
1757 if (!cmd->cmd_buffer) {
1758 ast_free(cmd);
1759 return -1;
1760 }
1761 cmd->cmd_id = ast_strdup(cmd_id);
1762 if (!cmd->cmd_id) {
1763 ast_free(cmd->cmd_buffer);
1764 ast_free(cmd);
1765 return -1;
1766 }
1770 return 0;
1771}
1772
1773static int add_to_agi(struct ast_channel *chan)
1774{
1775 struct ast_datastore *datastore;
1776 AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
1777
1778 /* check if already on AGI */
1779 ast_channel_lock(chan);
1781 ast_channel_unlock(chan);
1782 if (datastore) {
1783 /* we already have an AGI datastore, let's just
1784 return success */
1785 return 0;
1786 }
1787
1788 /* the channel has never been on Async AGI,
1789 let's allocate it's datastore */
1791 if (!datastore) {
1792 return -1;
1793 }
1794 agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
1795 if (!agi_cmds_list) {
1796 ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
1797 ast_datastore_free(datastore);
1798 return -1;
1799 }
1800 datastore->data = agi_cmds_list;
1801 AST_LIST_HEAD_INIT(agi_cmds_list);
1802 ast_channel_lock(chan);
1803 ast_channel_datastore_add(chan, datastore);
1804 ast_channel_unlock(chan);
1805 return 0;
1806}
1807
1808/*!
1809 * \brief CLI command to add applications to execute in Async AGI
1810 * \param e
1811 * \param cmd
1812 * \param a
1813 *
1814 * \retval CLI_SUCCESS on success
1815 * \retval NULL when init or tab completion is used
1816*/
1817static char *handle_cli_agi_add_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1818{
1819 struct ast_channel *chan;
1820 switch (cmd) {
1821 case CLI_INIT:
1822 e->command = "agi exec";
1823 e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
1824 " Add AGI command to the execute queue of the specified channel in Async AGI\n";
1825 return NULL;
1826 case CLI_GENERATE:
1827 if (a->pos == 2)
1828 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1829 return NULL;
1830 }
1831
1832 if (a->argc < 4) {
1833 return CLI_SHOWUSAGE;
1834 }
1835
1836 if (!(chan = ast_channel_get_by_name(a->argv[2]))) {
1837 ast_cli(a->fd, "Channel %s does not exist.\n", a->argv[2]);
1838 return CLI_FAILURE;
1839 }
1840
1841 ast_channel_lock(chan);
1842
1843 if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
1844 ast_cli(a->fd, "Failed to add AGI command to queue of channel %s\n", ast_channel_name(chan));
1845 ast_channel_unlock(chan);
1846 chan = ast_channel_unref(chan);
1847 return CLI_FAILURE;
1848 }
1849
1850 ast_debug(1, "Added AGI command to channel %s queue\n", ast_channel_name(chan));
1851
1852 ast_channel_unlock(chan);
1853 chan = ast_channel_unref(chan);
1854
1855 return CLI_SUCCESS;
1856}
1857
1858/*!
1859 * \brief Add a new command to execute by the Async AGI application
1860 * \param s
1861 * \param m
1862 *
1863 * It will append the application to the specified channel's queue
1864 * if the channel is not inside Async AGI application it will return an error
1865 * \retval 0 on success or incorrect use
1866 * \retval 1 on failure to add the command ( most likely because the channel
1867 * is not in Async AGI loop )
1868*/
1869static int action_add_agi_cmd(struct mansession *s, const struct message *m)
1870{
1871 const char *channel = astman_get_header(m, "Channel");
1872 const char *cmdbuff = astman_get_header(m, "Command");
1873 const char *cmdid = astman_get_header(m, "CommandID");
1874 struct ast_channel *chan;
1875 char buf[256];
1876
1877 if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
1878 astman_send_error(s, m, "Both, Channel and Command are *required*");
1879 return 0;
1880 }
1881
1882 if (!(chan = ast_channel_get_by_name(channel))) {
1883 snprintf(buf, sizeof(buf), "Channel %s does not exist.", channel);
1884 astman_send_error(s, m, buf);
1885 return 0;
1886 }
1887
1888 ast_channel_lock(chan);
1889
1890 if (add_agi_cmd(chan, cmdbuff, cmdid)) {
1891 snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", ast_channel_name(chan));
1892 astman_send_error(s, m, buf);
1893 ast_channel_unlock(chan);
1894 chan = ast_channel_unref(chan);
1895 return 0;
1896 }
1897
1898 ast_channel_unlock(chan);
1899 chan = ast_channel_unref(chan);
1900
1901 astman_send_ack(s, m, "Added AGI command to queue");
1902
1903 return 0;
1904}
1905
1906static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead);
1907static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[]);
1908
1909/*!
1910 * \internal
1911 * \brief Read and handle a channel frame for Async AGI.
1912 *
1913 * \param chan Channel to read a frame from.
1914 *
1915 * \retval AGI_RESULT_SUCCESS on success.
1916 * \retval AGI_RESULT_HANGUP on hangup.
1917 * \retval AGI_RESULT_FAILURE on error.
1918 */
1920{
1921 struct ast_frame *f;
1922
1923 f = ast_read(chan);
1924 if (!f) {
1925 ast_debug(3, "No frame read on channel %s, going out ...\n", ast_channel_name(chan));
1926 return AGI_RESULT_HANGUP;
1927 }
1928 if (f->frametype == AST_FRAME_CONTROL) {
1929 /*
1930 * Is there any other frame we should care about besides
1931 * AST_CONTROL_HANGUP?
1932 */
1933 switch (f->subclass.integer) {
1934 case AST_CONTROL_HANGUP:
1935 ast_debug(3, "Got HANGUP frame on channel %s, going out ...\n", ast_channel_name(chan));
1936 ast_frfree(f);
1937 return AGI_RESULT_HANGUP;
1938 default:
1939 break;
1940 }
1941 }
1942 ast_frfree(f);
1943
1944 return AGI_RESULT_SUCCESS;
1945}
1946
1947static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char *argv[], int *efd)
1948{
1949/* This buffer sizes might cause truncation if the AGI command writes more data
1950 than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command
1951 that writes a response larger than 1024 bytes?, I don't think so, most of
1952 them are just result=blah stuff. However probably if GET VARIABLE is called
1953 and the variable has large amount of data, that could be a problem. We could
1954 make this buffers dynamic, but let's leave that as a second step.
1955
1956 AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe
1957 number. Some characters of AGI buf will be url encoded to be sent to manager
1958 clients. An URL encoded character will take 3 bytes, but again, to cause
1959 truncation more than about 70% of the AGI buffer should be URL encoded for
1960 that to happen. Not likely at all.
1961
1962 On the other hand. I wonder if read() could eventually return less data than
1963 the amount already available in the pipe? If so, how to deal with that?
1964 So far, my tests on Linux have not had any problems.
1965 */
1966#define AGI_BUF_SIZE 1024
1967#define AMI_BUF_SIZE 2048
1968 enum agi_result cmd_status;
1969 struct agi_cmd *cmd;
1970 int res;
1971 int fds[2];
1972 int hungup;
1973 int timeout = 100;
1974 char agi_buffer[AGI_BUF_SIZE + 1];
1975 char ami_buffer[AMI_BUF_SIZE];
1976 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
1977 AGI async_agi;
1978 RAII_VAR(struct ast_json *, startblob, NULL, ast_json_unref);
1979
1980 if (efd) {
1981 ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
1982 return AGI_RESULT_FAILURE;
1983 }
1984
1985 /* add AsyncAGI datastore to the channel */
1986 if (add_to_agi(chan)) {
1987 ast_log(LOG_ERROR, "Failed to start Async AGI on channel %s\n", ast_channel_name(chan));
1988 return AGI_RESULT_FAILURE;
1989 }
1990
1991 /* this pipe allows us to create a "fake" AGI struct to use
1992 the AGI commands */
1993 res = pipe(fds);
1994 if (res) {
1995 ast_log(LOG_ERROR, "Failed to create Async AGI pipe\n");
1996 /*
1997 * Intentionally do not remove the datastore added with
1998 * add_to_agi() the from channel. It will be removed when the
1999 * channel is hung up anyway.
2000 */
2001 return AGI_RESULT_FAILURE;
2002 }
2003
2004 /* handlers will get the pipe write fd and we read the AGI responses
2005 from the pipe read fd */
2006 async_agi.fd = fds[1];
2007 async_agi.ctrl = fds[1];
2008 async_agi.audio = -1; /* no audio support */
2009 async_agi.fast = 0;
2010 async_agi.speech = NULL;
2011
2012 /* notify possible manager users of a new channel ready to
2013 receive commands */
2014 setup_env(chan, "async", fds[1], 0, argc, argv);
2015 /* read the environment */
2016 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
2017 if (res <= 0) {
2018 ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
2019 ast_channel_name(chan), res < 0 ? strerror(errno) : "EOF");
2020 returnstatus = AGI_RESULT_FAILURE;
2021 goto async_agi_abort;
2022 }
2023 agi_buffer[res] = '\0';
2024 /* encode it and send it thru the manager so whoever is going to take
2025 care of AGI commands on this channel can decide which AGI commands
2026 to execute based on the setup info */
2027 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, ast_uri_http);
2028 startblob = ast_json_pack("{s: s}", "Env", ami_buffer);
2029
2030 ast_channel_publish_cached_blob(chan, agi_async_start_type(), startblob);
2031
2032 hungup = ast_check_hangup_locked(chan);
2033
2034 for (;;) {
2035 /*
2036 * Process as many commands as we can. Commands are added via
2037 * the manager or the cli threads.
2038 */
2039 while (!hungup) {
2040 RAII_VAR(struct ast_json *, execblob, NULL, ast_json_unref);
2041 res = get_agi_cmd(chan, &cmd);
2042
2043 if (res) {
2044 returnstatus = AGI_RESULT_FAILURE;
2045 goto async_agi_done;
2046 } else if (!cmd) {
2047 break;
2048 }
2049
2050 /* OK, we have a command, let's call the command handler. */
2051 cmd_status = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
2052
2053 /*
2054 * The command handler must have written to our fake AGI struct
2055 * fd (the pipe), let's read the response.
2056 */
2057 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
2058 if (res <= 0) {
2059 ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
2060 ast_channel_name(chan), res < 0 ? strerror(errno) : "EOF");
2061 free_agi_cmd(cmd);
2062 returnstatus = AGI_RESULT_FAILURE;
2063 goto async_agi_done;
2064 }
2065 /*
2066 * We have a response, let's send the response thru the manager.
2067 * Include the CommandID if it was specified when the command
2068 * was added.
2069 */
2070 agi_buffer[res] = '\0';
2071 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, ast_uri_http);
2072
2073 execblob = ast_json_pack("{s: s}", "Result", ami_buffer);
2074 if (execblob && !ast_strlen_zero(cmd->cmd_id)) {
2075 ast_json_object_set(execblob, "CommandId", ast_json_string_create(cmd->cmd_id));
2076 }
2077 ast_channel_publish_cached_blob(chan, agi_async_exec_type(), execblob);
2078
2079 free_agi_cmd(cmd);
2080
2081 /*
2082 * Check the command status to determine if we should continue
2083 * executing more commands.
2084 */
2085 hungup = ast_check_hangup(chan);
2086 switch (cmd_status) {
2087 case AGI_RESULT_FAILURE:
2088 if (!hungup) {
2089 /* The failure was not because of a hangup. */
2090 returnstatus = AGI_RESULT_FAILURE;
2091 goto async_agi_done;
2092 }
2093 break;
2095 /* Only the "asyncagi break" command does this. */
2096 returnstatus = AGI_RESULT_SUCCESS_ASYNC;
2097 goto async_agi_done;
2098 default:
2099 break;
2100 }
2101 }
2102
2103 if (!hungup) {
2104 /* Wait a bit for a frame to read or to poll for a new command. */
2105 res = ast_waitfor(chan, timeout);
2106 if (res < 0) {
2107 ast_debug(1, "ast_waitfor returned <= 0 on chan %s\n", ast_channel_name(chan));
2108 returnstatus = AGI_RESULT_FAILURE;
2109 break;
2110 }
2111 } else {
2112 /*
2113 * Read the channel control queue until it is dry so we can
2114 * quit.
2115 */
2116 res = 1;
2117 }
2118 if (0 < res) {
2119 do {
2120 cmd_status = async_agi_read_frame(chan);
2121 if (cmd_status != AGI_RESULT_SUCCESS) {
2122 returnstatus = cmd_status;
2123 goto async_agi_done;
2124 }
2125 hungup = ast_check_hangup(chan);
2126 } while (hungup);
2127 } else {
2128 hungup = ast_check_hangup(chan);
2129 }
2130 }
2131async_agi_done:
2132
2133 if (async_agi.speech) {
2134 ast_speech_destroy(async_agi.speech);
2135 }
2136 /* notify manager users this channel cannot be controlled anymore by Async AGI */
2137 ast_channel_publish_cached_blob(chan, agi_async_end_type(), NULL);
2138
2139async_agi_abort:
2140 /* close the pipe */
2141 close(fds[0]);
2142 close(fds[1]);
2143
2144 /*
2145 * Intentionally do not remove the datastore added with
2146 * add_to_agi() the from channel. There might be commands still
2147 * in the queue or in-flight to us and AsyncAGI may get called
2148 * again. The datastore destructor will be called on channel
2149 * destruction anyway.
2150 */
2151
2152 if (returnstatus == AGI_RESULT_SUCCESS) {
2153 returnstatus = AGI_RESULT_SUCCESS_ASYNC;
2154 }
2155 return returnstatus;
2156
2157#undef AGI_BUF_SIZE
2158#undef AMI_BUF_SIZE
2159}
2160
2161/*!
2162 * \internal
2163 * \brief Handle the connection that was started by launch_netscript.
2164 *
2165 * \param agiurl Url that we are trying to connect to.
2166 * \param addr Address that host was resolved to.
2167 * \param netsockfd File descriptor of socket.
2168 *
2169 * \retval 0 when connection is succesful.
2170 * \retval 1 when there is an error.
2171 */
2172static int handle_connection(const char *agiurl, const struct ast_sockaddr addr, const int netsockfd)
2173{
2174 struct pollfd pfds[1];
2175 int res, conresult;
2176 socklen_t reslen;
2177
2178 reslen = sizeof(conresult);
2179
2180 pfds[0].fd = netsockfd;
2181 pfds[0].events = POLLOUT;
2182
2183 while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
2184 if (errno != EINTR) {
2185 if (!res) {
2186 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
2187 agiurl, MAX_AGI_CONNECT);
2188 } else {
2189 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
2190 }
2191
2192 return 1;
2193 }
2194 }
2195
2196 if (getsockopt(pfds[0].fd, SOL_SOCKET, SO_ERROR, &conresult, &reslen) < 0) {
2197 ast_log(LOG_WARNING, "Connection to %s failed with error: %s\n",
2198 ast_sockaddr_stringify(&addr), strerror(errno));
2199 return 1;
2200 }
2201
2202 if (conresult) {
2203 ast_log(LOG_WARNING, "Connecting to '%s' failed for url '%s': %s\n",
2204 ast_sockaddr_stringify(&addr), agiurl, strerror(conresult));
2205 return 1;
2206 }
2207
2208 return 0;
2209}
2210
2211/* launch_netscript: The fastagi handler.
2212 FastAGI defaults to port 4573 */
2213static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
2214{
2215 int s = 0;
2216 char *host, *script;
2217 int num_addrs = 0, i = 0;
2218 struct ast_sockaddr *addrs;
2219
2220 /* agiurl is "agi://host.domain[:port][/script/name]" */
2221 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
2222
2223 /* Strip off any script name */
2224 if ((script = strchr(host, '/'))) {
2225 *script++ = '\0';
2226 } else {
2227 script = "";
2228 }
2229
2230 if (!(num_addrs = ast_sockaddr_resolve(&addrs, host, 0, AST_AF_UNSPEC))) {
2231 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
2232 return AGI_RESULT_FAILURE;
2233 }
2234
2235 for (i = 0; i < num_addrs; i++) {
2236 if (!ast_sockaddr_port(&addrs[i])) {
2237 ast_sockaddr_set_port(&addrs[i], AGI_PORT);
2238 }
2239
2240 if ((s = ast_socket_nonblock(addrs[i].ss.ss_family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
2241 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
2242 continue;
2243 }
2244
2245 if (ast_connect(s, &addrs[i]) && errno == EINPROGRESS) {
2246
2247 if (handle_connection(agiurl, addrs[i], s)) {
2248 close(s);
2249 continue;
2250 }
2251
2252 } else {
2253 ast_log(LOG_WARNING, "Connection to %s failed with unexpected error: %s\n",
2254 ast_sockaddr_stringify(&addrs[i]), strerror(errno));
2255 }
2256
2257 break;
2258 }
2259
2260 ast_free(addrs);
2261
2262 if (i == num_addrs) {
2263 ast_log(LOG_WARNING, "Couldn't connect to any host. FastAGI failed.\n");
2264 return AGI_RESULT_FAILURE;
2265 }
2266
2267 if (ast_agi_send(s, NULL, "agi_network: yes\n") < 0) {
2268 if (errno != EINTR) {
2269 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
2270 close(s);
2271 return AGI_RESULT_FAILURE;
2272 }
2273 }
2274
2275 /* If we have a script parameter, relay it to the fastagi server */
2276 /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
2277 if (!ast_strlen_zero(script)) {
2278 ast_agi_send(s, NULL, "agi_network_script: %s\n", script);
2279 }
2280
2281 ast_debug(4, "Wow, connected!\n");
2282 fds[0] = s;
2283 fds[1] = s;
2285}
2286
2287/*!
2288 * \internal
2289 * \brief The HA fastagi handler.
2290 * \param agiurl The request URL as passed to Agi() in the dial plan
2291 * \param argv The parameters after the URL passed to Agi() in the dial plan
2292 * \param fds Input/output file descriptors
2293 *
2294 * Uses SRV lookups to try to connect to a list of FastAGI servers. The hostname in
2295 * the URI is prefixed with _agi._tcp. prior to the DNS resolution. For
2296 * example, if you specify the URI \a hagi://agi.example.com/foo.agi the DNS
2297 * query would be for \a _agi._tcp.agi.example.com and you'll need to make sure
2298 * this resolves.
2299 *
2300 * This function parses the URI, resolves the SRV service name, forms new URIs
2301 * with the results of the DNS lookup, and then calls launch_netscript on the
2302 * new URIs until one succeeds.
2303 *
2304 * \return the result of the AGI operation.
2305 */
2306static enum agi_result launch_ha_netscript(char *agiurl, char *argv[], int *fds)
2307{
2308 char *host, *script;
2309 enum agi_result result;
2310 struct srv_context *context = NULL;
2311 int srv_ret;
2312 char service[256];
2313 char resolved_uri[1024];
2314 const char *srvhost;
2315 unsigned short srvport;
2316
2317 /* format of agiurl is "hagi://host.domain[:port][/script/name]" */
2318 if (strlen(agiurl) < 7) { /* Remove hagi:// */
2319 ast_log(LOG_WARNING, "An error occurred parsing the AGI URI: %s", agiurl);
2320 return AGI_RESULT_FAILURE;
2321 }
2322 host = ast_strdupa(agiurl + 7);
2323
2324 /* Strip off any script name */
2325 if ((script = strchr(host, '/'))) {
2326 *script++ = '\0';
2327 } else {
2328 script = "";
2329 }
2330
2331 if (strchr(host, ':')) {
2332 ast_log(LOG_WARNING, "Specifying a port number disables SRV lookups: %s\n", agiurl);
2333 return launch_netscript(agiurl + 1, argv, fds); /* +1 to strip off leading h from hagi:// */
2334 }
2335
2336 snprintf(service, sizeof(service), "%s%s", SRV_PREFIX, host);
2337
2338 while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
2339 snprintf(resolved_uri, sizeof(resolved_uri), "agi://%s:%d/%s", srvhost, srvport, script);
2340 result = launch_netscript(resolved_uri, argv, fds);
2342 ast_log(LOG_WARNING, "AGI request failed for host '%s' (%s:%d)\n", host, srvhost, srvport);
2343 } else {
2344 /* The script launched so we must cleanup the context. */
2346 return result;
2347 }
2348 }
2349 /*
2350 * The DNS SRV lookup failed or we ran out of servers to check.
2351 * ast_srv_lookup() has already cleaned up the context for us.
2352 */
2353 if (srv_ret < 0) {
2354 ast_log(LOG_WARNING, "SRV lookup failed for %s\n", agiurl);
2355 }
2356
2357 return AGI_RESULT_FAILURE;
2358}
2359
2360static 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)
2361{
2362 char tmp[256];
2363 int pid, toast[2], fromast[2], audio[2], res;
2364 struct stat st;
2365
2366 /* We should not call ast_safe_fork_cleanup() if we never call ast_safe_fork(1) */
2367 *safe_fork_called = 0;
2368
2369 if (!strncasecmp(script, "agi://", 6)) {
2370 return (efd == NULL) ? launch_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
2371 }
2372 if (!strncasecmp(script, "hagi://", 7)) {
2373 return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
2374 }
2375 if (!strncasecmp(script, "agi:async", sizeof("agi:async") - 1)) {
2376 return launch_asyncagi(chan, argc, argv, efd);
2377 }
2378
2379 if (script[0] != '/') {
2380 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
2381 script = tmp;
2382 }
2383
2384 /* Before even trying let's see if the file actually exists */
2385 if (stat(script, &st)) {
2386 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
2387 return AGI_RESULT_NOTFOUND;
2388 }
2389
2390 if (pipe(toast)) {
2391 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
2392 return AGI_RESULT_FAILURE;
2393 }
2394 if (pipe(fromast)) {
2395 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
2396 close(toast[0]);
2397 close(toast[1]);
2398 return AGI_RESULT_FAILURE;
2399 }
2400 if (efd) {
2401 if (pipe(audio)) {
2402 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
2403 close(fromast[0]);
2404 close(fromast[1]);
2405 close(toast[0]);
2406 close(toast[1]);
2407 return AGI_RESULT_FAILURE;
2408 }
2409
2410 res = ast_fd_set_flags(audio[1], O_NONBLOCK);
2411 if (res < 0) {
2412 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
2413 close(fromast[0]);
2414 close(fromast[1]);
2415 close(toast[0]);
2416 close(toast[1]);
2417 close(audio[0]);
2418 close(audio[1]);
2419 return AGI_RESULT_FAILURE;
2420 }
2421 }
2422
2423 *safe_fork_called = 1;
2424
2425 if ((pid = ast_safe_fork(1)) < 0) {
2426 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
2427 return AGI_RESULT_FAILURE;
2428 }
2429 if (!pid) {
2430 /* Pass paths to AGI via environmental variables */
2431 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
2432 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
2433 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
2434 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
2435 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
2436 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
2437 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
2438 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
2439 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
2440 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
2441 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
2442
2443 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
2445
2446 /* Redirect stdin and out, provide enhanced audio channel if desired */
2447 dup2(fromast[0], STDIN_FILENO);
2448 dup2(toast[1], STDOUT_FILENO);
2449 if (efd)
2450 dup2(audio[0], STDERR_FILENO + 1);
2451 else
2452 close(STDERR_FILENO + 1);
2453
2454 /* Close everything but stdin/out/error */
2455 ast_close_fds_above_n(STDERR_FILENO + 1);
2456
2457 /* Execute script */
2458 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
2459 execv(script, argv);
2460 /* Can't use ast_log since FD's are closed */
2461 ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
2462 /* Special case to set status of AGI to failure */
2463 fprintf(stdout, "failure\n");
2464 fflush(stdout);
2465 _exit(1);
2466 }
2467 ast_verb(3, "Launched AGI Script %s\n", script);
2468 fds[0] = toast[0];
2469 fds[1] = fromast[1];
2470 if (efd)
2471 *efd = audio[1];
2472 /* close what we're not using in the parent */
2473 close(toast[1]);
2474 close(fromast[0]);
2475
2476 if (efd)
2477 close(audio[0]);
2478
2479 *opid = pid;
2480 return AGI_RESULT_SUCCESS;
2481}
2482
2483static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
2484{
2485 int count;
2486
2487 /* Print initial environment, with agi_request always being the first
2488 thing */
2489 ast_agi_send(fd, chan, "agi_request: %s\n", request);
2490 ast_agi_send(fd, chan, "agi_channel: %s\n", ast_channel_name(chan));
2491 ast_agi_send(fd, chan, "agi_language: %s\n", ast_channel_language(chan));
2492 ast_agi_send(fd, chan, "agi_type: %s\n", ast_channel_tech(chan)->type);
2493 ast_agi_send(fd, chan, "agi_uniqueid: %s\n", ast_channel_uniqueid(chan));
2494 ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version());
2495
2496 /* ANI/DNIS */
2497 ast_agi_send(fd, chan, "agi_callerid: %s\n",
2498 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "unknown"));
2499 ast_agi_send(fd, chan, "agi_calleridname: %s\n",
2500 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "unknown"));
2501 ast_agi_send(fd, chan, "agi_callingpres: %d\n",
2503 ast_agi_send(fd, chan, "agi_callingani2: %d\n", ast_channel_caller(chan)->ani2);
2504 ast_agi_send(fd, chan, "agi_callington: %d\n", ast_channel_caller(chan)->id.number.plan);
2505 ast_agi_send(fd, chan, "agi_callingtns: %d\n", ast_channel_dialed(chan)->transit_network_select);
2506 ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(ast_channel_dialed(chan)->number.str, "unknown"));
2507 ast_agi_send(fd, chan, "agi_rdnis: %s\n",
2508 S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "unknown"));
2509
2510 /* Context information */
2511 ast_agi_send(fd, chan, "agi_context: %s\n", ast_channel_context(chan));
2512 ast_agi_send(fd, chan, "agi_extension: %s\n", ast_channel_exten(chan));
2513 ast_agi_send(fd, chan, "agi_priority: %d\n", ast_channel_priority(chan));
2514 ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
2515
2516 /* User information */
2517 ast_agi_send(fd, chan, "agi_accountcode: %s\n", ast_channel_accountcode(chan) ? ast_channel_accountcode(chan) : "");
2518 ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self());
2519
2520 /* Send any parameters to the fastagi server that have been passed via the agi application */
2521 /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
2522 for(count = 1; count < argc; count++)
2523 ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]);
2524
2525 /* End with empty return */
2526 ast_agi_send(fd, chan, "\n");
2527}
2528
2529static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2530{
2531 int res = 0;
2532
2533 /* Answer the channel */
2534 if (ast_channel_state(chan) != AST_STATE_UP)
2535 res = ast_answer(chan);
2536
2537 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2538 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2539}
2540
2541static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2542{
2543 ast_agi_send(agi->fd, chan, "200 result=0\n");
2544 return ASYNC_AGI_BREAK;
2545}
2546
2547static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2548{
2549 int res, to;
2550
2551 if (argc != 4)
2552 return RESULT_SHOWUSAGE;
2553 if (sscanf(argv[3], "%30d", &to) != 1)
2554 return RESULT_SHOWUSAGE;
2555 res = ast_waitfordigit_full(chan, to, NULL, agi->audio, agi->ctrl);
2556 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2557 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2558}
2559
2560static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2561{
2562 int res;
2563
2564 if (argc != 3)
2565 return RESULT_SHOWUSAGE;
2566
2567 /* At the moment, the parser (perhaps broken) returns with
2568 the last argument PLUS the newline at the end of the input
2569 buffer. This probably needs to be fixed, but I wont do that
2570 because other stuff may break as a result. The right way
2571 would probably be to strip off the trailing newline before
2572 parsing, then here, add a newline at the end of the string
2573 before sending it to ast_sendtext --DUDE */
2574 res = ast_sendtext(chan, argv[2]);
2575 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2576 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2577}
2578
2579static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2580{
2581 int res;
2582
2583 if (argc != 3)
2584 return RESULT_SHOWUSAGE;
2585
2586 res = ast_recvchar(chan,atoi(argv[2]));
2587 if (res == 0) {
2588 ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res);
2589 return RESULT_SUCCESS;
2590 }
2591 if (res > 0) {
2592 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2593 return RESULT_SUCCESS;
2594 }
2595 ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res);
2596 return RESULT_FAILURE;
2597}
2598
2599static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2600{
2601 char *buf;
2602
2603 if (argc != 3)
2604 return RESULT_SHOWUSAGE;
2605
2606 buf = ast_recvtext(chan, atoi(argv[2]));
2607 if (buf) {
2608 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf);
2609 ast_free(buf);
2610 } else {
2611 ast_agi_send(agi->fd, chan, "200 result=-1\n");
2612 }
2613 return RESULT_SUCCESS;
2614}
2615
2616static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2617{
2618 int res, x;
2619
2620 if (argc != 3)
2621 return RESULT_SHOWUSAGE;
2622
2623 if (!strncasecmp(argv[2],"on",2)) {
2624 x = 1;
2625 } else {
2626 x = 0;
2627 }
2628 if (!strncasecmp(argv[2],"mate",4)) {
2629 x = 2;
2630 }
2631 if (!strncasecmp(argv[2],"tdd",3)) {
2632 x = 1;
2633 }
2634 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
2635 if (res) {
2636 /* Set channel option failed */
2637 ast_agi_send(agi->fd, chan, "200 result=0\n");
2638 } else {
2639 ast_agi_send(agi->fd, chan, "200 result=1\n");
2640 }
2641 return RESULT_SUCCESS;
2642}
2643
2644static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2645{
2646 int res;
2647
2648 if (argc != 3) {
2649 return RESULT_SHOWUSAGE;
2650 }
2651
2652 res = ast_send_image(chan, argv[2]);
2653 if (!ast_check_hangup(chan)) {
2654 res = 0;
2655 }
2656 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2657 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2658}
2659
2660static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2661{
2662 int res = 0, skipms = 3000;
2663 const char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */
2664 char stopkeybuf[2];
2665 long offsetms = 0;
2666 char offsetbuf[20];
2667
2668 if (argc < 5 || argc > 10) {
2669 return RESULT_SHOWUSAGE;
2670 }
2671
2672 if (!ast_strlen_zero(argv[4])) {
2673 stop = argv[4];
2674 }
2675
2676 if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) {
2677 return RESULT_SHOWUSAGE;
2678 }
2679
2680 if (argc > 6 && !ast_strlen_zero(argv[6])) {
2681 fwd = argv[6];
2682 }
2683
2684 if (argc > 7 && !ast_strlen_zero(argv[7])) {
2685 rev = argv[7];
2686 }
2687
2688 if (argc > 8 && !ast_strlen_zero(argv[8])) {
2689 suspend = argv[8];
2690 }
2691
2692 if (argc > 9 && (sscanf(argv[9], "%30ld", &offsetms) != 1)) {
2693 return RESULT_SHOWUSAGE;
2694 }
2695
2696 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, &offsetms);
2697
2698 /* If we stopped on one of our stop keys, return 0 */
2699 if (res > 0 && stop && strchr(stop, res)) {
2700 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "USERSTOPPED");
2701 snprintf(stopkeybuf, sizeof(stopkeybuf), "%c", res);
2702 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTOPKEY", stopkeybuf);
2703 } else if (res > 0 && res == AST_CONTROL_STREAM_STOP) {
2704 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "REMOTESTOPPED");
2705 res = 0;
2706 } else {
2707 if (res < 0) {
2708 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "ERROR");
2709 } else {
2710 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "SUCCESS");
2711 }
2712 }
2713
2714 snprintf(offsetbuf, sizeof(offsetbuf), "%ld", offsetms);
2715 pbx_builtin_setvar_helper(chan, "CPLAYBACKOFFSET", offsetbuf);
2716
2717 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, offsetms);
2718
2719 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2720}
2721
2722static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2723{
2724 int res;
2725 struct ast_filestream *fs, *vfs;
2726 long sample_offset = 0, max_length;
2727 const char *edigits = "";
2728
2729 if (argc < 4 || argc > 5) {
2730 return RESULT_SHOWUSAGE;
2731 }
2732
2733 if (argv[3]) {
2734 edigits = argv[3];
2735 }
2736
2737 if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1)) {
2738 return RESULT_SHOWUSAGE;
2739 }
2740
2741 if (!(fs = ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
2742 ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
2743 return RESULT_FAILURE;
2744 }
2745
2746 if ((vfs = ast_openvstream(chan, argv[2], ast_channel_language(chan)))) {
2747 ast_debug(1, "Ooh, found a video stream, too\n");
2748 }
2749 ast_verb(3, "<%s> Playing '%s.%s' (escape_digits=%s) (sample_offset %ld) (language '%s')\n",
2751 edigits, sample_offset, S_OR(ast_channel_language(chan), "default"));
2752
2753 ast_seekstream(fs, 0, SEEK_END);
2754 max_length = ast_tellstream(fs);
2755 ast_seekstream(fs, sample_offset, SEEK_SET);
2756 res = ast_applystream(chan, fs);
2757 if (vfs) {
2758 ast_applystream(chan, vfs);
2759 }
2760 ast_playstream(fs);
2761 if (vfs) {
2763 }
2764
2765 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
2766 /* this is to check for if ast_waitstream closed the stream, we probably are at
2767 * the end of the stream, return that amount, else check for the amount */
2768 sample_offset = (ast_channel_stream(chan)) ? ast_tellstream(fs) : max_length;
2769 ast_stopstream(chan);
2770 if (res == 1) {
2771 /* Stop this command, don't print a result line, as there is a new command */
2772 return RESULT_SUCCESS;
2773 }
2774 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
2775 pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", res ? "FAILED" : "SUCCESS");
2776
2777 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2778}
2779
2780/*! \brief get option - really similar to the handle_streamfile, but with a timeout */
2781static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2782{
2783 int res;
2784 struct ast_filestream *fs, *vfs;
2785 long sample_offset = 0, max_length;
2786 int timeout = 0;
2787 const char *edigits = "";
2788
2789 if ( argc < 4 || argc > 5 )
2790 return RESULT_SHOWUSAGE;
2791
2792 if ( argv[3] )
2793 edigits = argv[3];
2794
2795 if ( argc == 5 )
2796 timeout = atoi(argv[4]);
2797 else if (ast_channel_pbx(chan)->dtimeoutms) {
2798 /* by default dtimeout is set to 5sec */
2799 timeout = ast_channel_pbx(chan)->dtimeoutms; /* in msec */
2800 }
2801
2802 if (!(fs = ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
2803 ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
2804 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
2805 return RESULT_FAILURE;
2806 }
2807
2808 if ((vfs = ast_openvstream(chan, argv[2], ast_channel_language(chan))))
2809 ast_debug(1, "Ooh, found a video stream, too\n");
2810
2811 ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
2812
2813 ast_seekstream(fs, 0, SEEK_END);
2814 max_length = ast_tellstream(fs);
2815 ast_seekstream(fs, sample_offset, SEEK_SET);
2816 res = ast_applystream(chan, fs);
2817 if (vfs)
2818 ast_applystream(chan, vfs);
2819 ast_playstream(fs);
2820 if (vfs)
2822
2823 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
2824 /* this is to check for if ast_waitstream closed the stream, we probably are at
2825 * the end of the stream, return that amount, else check for the amount */
2826 sample_offset = (ast_channel_stream(chan))?ast_tellstream(fs):max_length;
2827 ast_stopstream(chan);
2828 if (res == 1) {
2829 /* Stop this command, don't print a result line, as there is a new command */
2830 return RESULT_SUCCESS;
2831 }
2832
2833 /* If the user didnt press a key, wait for digitTimeout*/
2834 if (res == 0 ) {
2835 res = ast_waitfordigit_full(chan, timeout, NULL, agi->audio, agi->ctrl);
2836 /* Make sure the new result is in the escape digits of the GET OPTION */
2837 if ( !strchr(edigits,res) )
2838 res=0;
2839 }
2840
2841 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
2842 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2843}
2844
2845
2846
2847
2848/*! \brief Say number in various language syntaxes */
2849/* While waiting, we're sending a NULL. */
2850static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2851{
2852 int res, num;
2853
2854 if (argc < 4 || argc > 5)
2855 return RESULT_SHOWUSAGE;
2856 if (sscanf(argv[2], "%30d", &num) != 1)
2857 return RESULT_SHOWUSAGE;
2858 res = ast_say_number_full(chan, num, argv[3], ast_channel_language(chan), argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
2859 if (res == 1)
2860 return RESULT_SUCCESS;
2861 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2862 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2863}
2864
2865static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2866{
2867 int res, num;
2868
2869 if (argc != 4)
2870 return RESULT_SHOWUSAGE;
2871 if (sscanf(argv[2], "%30d", &num) != 1)
2872 return RESULT_SHOWUSAGE;
2873
2874 res = ast_say_digit_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->audio, agi->ctrl);
2875 if (res == 1) /* New command */
2876 return RESULT_SUCCESS;
2877 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2878 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2879}
2880
2881static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2882{
2883 int res;
2884 int sensitivity = AST_SAY_CASE_NONE;
2885
2886 if (argc < 4 || argc > 5) {
2887 return RESULT_SHOWUSAGE;
2888 }
2889
2890 if (argc > 4) {
2891 switch (argv[4][0]) {
2892 case 'a':
2893 case 'A':
2894 sensitivity = AST_SAY_CASE_ALL;
2895 break;
2896 case 'l':
2897 case 'L':
2898 sensitivity = AST_SAY_CASE_LOWER;
2899 break;
2900 case 'n':
2901 case 'N':
2902 sensitivity = AST_SAY_CASE_NONE;
2903 break;
2904 case 'u':
2905 case 'U':
2906 sensitivity = AST_SAY_CASE_UPPER;
2907 break;
2908 case '\0':
2909 break;
2910 default:
2911 return RESULT_SHOWUSAGE;
2912 }
2913 }
2914 res = ast_say_character_str_full(chan, argv[2], argv[3], ast_channel_language(chan), sensitivity, agi->audio, agi->ctrl);
2915 if (res == 1) /* New command */
2916 return RESULT_SUCCESS;
2917 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2918 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2919}
2920
2921static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2922{
2923 int res, num;
2924
2925 if (argc != 4)
2926 return RESULT_SHOWUSAGE;
2927 if (sscanf(argv[2], "%30d", &num) != 1)
2928 return RESULT_SHOWUSAGE;
2929 res = ast_say_date(chan, num, argv[3], ast_channel_language(chan));
2930 if (res == 1)
2931 return RESULT_SUCCESS;
2932 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2933 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2934}
2935
2936static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2937{
2938 int res, num;
2939
2940 if (argc != 4)
2941 return RESULT_SHOWUSAGE;
2942 if (sscanf(argv[2], "%30d", &num) != 1)
2943 return RESULT_SHOWUSAGE;
2944 res = ast_say_time(chan, num, argv[3], ast_channel_language(chan));
2945 if (res == 1)
2946 return RESULT_SUCCESS;
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_saydatetime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2952{
2953 int res = 0;
2954 time_t unixtime;
2955 const char *format, *zone = NULL;
2956
2957 if (argc < 4)
2958 return RESULT_SHOWUSAGE;
2959
2960 if (argc > 4) {
2961 format = argv[4];
2962 } else {
2963 /* XXX this doesn't belong here, but in the 'say' module */
2964 if (!strcasecmp(ast_channel_language(chan), "de")) {
2965 format = "A dBY HMS";
2966 } else {
2967 format = "ABdY 'digits/at' IMp";
2968 }
2969 }
2970
2971 if (argc > 5 && !ast_strlen_zero(argv[5]))
2972 zone = argv[5];
2973
2974 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
2975 return RESULT_SHOWUSAGE;
2976
2977 res = ast_say_date_with_format(chan, unixtime, argv[3], ast_channel_language(chan), format, zone);
2978 if (res == 1)
2979 return RESULT_SUCCESS;
2980
2981 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2982 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2983}
2984
2985static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2986{
2987 int res;
2988
2989 if (argc != 4)
2990 return RESULT_SHOWUSAGE;
2991
2992 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->audio, agi->ctrl);
2993 if (res == 1) /* New command */
2994 return RESULT_SUCCESS;
2995 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2996 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2997}
2998
2999static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3000{
3001 int res, max, timeout;
3002 char data[1024];
3003
3004 if (argc < 3)
3005 return RESULT_SHOWUSAGE;
3006 if (argc >= 4)
3007 timeout = atoi(argv[3]);
3008 else
3009 timeout = 0;
3010 if (argc >= 5)
3011 max = atoi(argv[4]);
3012 else
3013 max = 1024;
3014 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
3015 if (res == 2) /* New command */
3016 return RESULT_SUCCESS;
3017 else if (res == 1)
3018 ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
3019 else if (res < 0 )
3020 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3021 else
3022 ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
3023 return RESULT_SUCCESS;
3024}
3025
3026static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3027{
3028
3029 if (argc != 3)
3030 return RESULT_SHOWUSAGE;
3031 ast_channel_context_set(chan, argv[2]);
3032 ast_agi_send(agi->fd, chan, "200 result=0\n");
3033 return RESULT_SUCCESS;
3034}
3035
3036static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3037{
3038 if (argc != 3)
3039 return RESULT_SHOWUSAGE;
3040 ast_channel_exten_set(chan, argv[2]);
3041 ast_agi_send(agi->fd, chan, "200 result=0\n");
3042 return RESULT_SUCCESS;
3043}
3044
3045static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3046{
3047 int pri;
3048
3049 if (argc != 3)
3050 return RESULT_SHOWUSAGE;
3051
3052 if (sscanf(argv[2], "%30d", &pri) != 1) {
3053 pri = ast_findlabel_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), argv[2],
3054 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
3055 if (pri < 1)
3056 return RESULT_SHOWUSAGE;
3057 }
3058
3059 ast_explicit_goto(chan, NULL, NULL, pri);
3060 ast_agi_send(agi->fd, chan, "200 result=0\n");
3061 return RESULT_SUCCESS;
3062}
3063
3064static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3065{
3066 struct ast_filestream *fs;
3067 struct ast_frame *f;
3068 struct timeval start;
3069 long sample_offset = 0;
3070 int res = 0;
3071 int ms;
3072
3073 struct ast_dsp *sildet=NULL; /* silence detector dsp */
3074 int totalsilence = 0;
3075 int dspsilence = 0;
3076 int silence = 0; /* amount of silence to allow */
3077 int gotsilence = 0; /* did we timeout for silence? */
3078 char *silencestr = NULL;
3079 RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup);
3080 struct ast_silence_generator *silgen = NULL;
3081
3082 /* XXX EAGI FIXME XXX */
3083
3084 if (argc < 6)
3085 return RESULT_SHOWUSAGE;
3086 if (sscanf(argv[5], "%30d", &ms) != 1)
3087 return RESULT_SHOWUSAGE;
3088
3089 if (argc > 6)
3090 silencestr = strchr(argv[6],'s');
3091 if ((argc > 7) && (!silencestr))
3092 silencestr = strchr(argv[7],'s');
3093 if ((argc > 8) && (!silencestr))
3094 silencestr = strchr(argv[8],'s');
3095
3096 if (silencestr) {
3097 if (strlen(silencestr) > 2) {
3098 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
3099 silencestr++;
3100 silencestr++;
3101 if (silencestr)
3102 silence = atoi(silencestr);
3103 if (silence > 0)
3104 silence *= 1000;
3105 }
3106 }
3107 }
3108
3109 if (silence > 0) {
3110 rfmt = ao2_bump(ast_channel_readformat(chan));
3112 if (res < 0) {
3113 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
3114 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
3115 return RESULT_FAILURE;
3116 }
3117 sildet = ast_dsp_new();
3118 if (!sildet) {
3119 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
3120 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3121 return RESULT_FAILURE;
3122 }
3124 }
3125
3126 /* backward compatibility, if no offset given, arg[6] would have been
3127 * caught below and taken to be a beep, else if it is a digit then it is a
3128 * offset.
3129 *
3130 * In other words, if the argument does not look like the offset_samples
3131 * argument (a number) and it doesn't look like the silence argument (starts
3132 * with "s=") then it must be the beep argument. The beep argument has no
3133 * required value, the presence of anything in the argument slot we are
3134 * inspecting is an indication that the user wants a beep played.
3135 */
3136 if ((argc > 6 && sscanf(argv[6], "%30ld", &sample_offset) != 1 && !ast_begins_with(argv[6], "s="))
3137 || (argc > 7 && !ast_begins_with(argv[7], "s="))) {
3138 res = ast_streamfile(chan, "beep", ast_channel_language(chan));
3139 }
3140
3141 if (!res)
3142 res = ast_waitstream(chan, argv[4]);
3143 if (res) {
3144 ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
3145 } else {
3146 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
3147 if (!fs) {
3148 res = -1;
3149 ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
3150 if (sildet)
3151 ast_dsp_free(sildet);
3152 return RESULT_FAILURE;
3153 }
3154
3155 /* Request a video update */
3157
3158 ast_channel_stream_set(chan, fs);
3159 ast_applystream(chan,fs);
3160 /* really should have checks */
3161 ast_seekstream(fs, sample_offset, SEEK_SET);
3162 ast_truncstream(fs);
3163
3166 }
3167
3168 start = ast_tvnow();
3169 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
3170 res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start));
3171 if (res < 0) {
3172 ast_closestream(fs);
3173 ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
3174 if (sildet)
3175 ast_dsp_free(sildet);
3176 if (silgen)
3178 return RESULT_FAILURE;
3179 }
3180 f = ast_read(chan);
3181 if (!f) {
3182 ast_closestream(fs);
3183 ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
3184 if (sildet)
3185 ast_dsp_free(sildet);
3186 if (silgen)
3188 return RESULT_FAILURE;
3189 }
3190 switch(f->frametype) {
3191 case AST_FRAME_DTMF:
3192 if (strchr(argv[4], f->subclass.integer)) {
3193 /* This is an interrupting character, so rewind to chop off any small
3194 amount of DTMF that may have been recorded
3195 */
3196 ast_stream_rewind(fs, 200);
3197 ast_truncstream(fs);
3198 sample_offset = ast_tellstream(fs);
3199 ast_closestream(fs);
3200 ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset);
3201 ast_frfree(f);
3202 if (sildet)
3203 ast_dsp_free(sildet);
3204 if (silgen)
3206 return RESULT_SUCCESS;
3207 }
3208 break;
3209 case AST_FRAME_VOICE:
3210 ast_writestream(fs, f);
3211 /* this is a safe place to check progress since we know that fs
3212 * is valid after a write, and it will then have our current
3213 * location */
3214 sample_offset = ast_tellstream(fs);
3215 if (silence > 0) {
3216 dspsilence = 0;
3217 ast_dsp_silence(sildet, f, &dspsilence);
3218 if (dspsilence) {
3219 totalsilence = dspsilence;
3220 } else {
3221 totalsilence = 0;
3222 }
3223 if (totalsilence > silence) {
3224 /* Ended happily with silence */
3225 gotsilence = 1;
3226 break;
3227 }
3228 }
3229 break;
3230 case AST_FRAME_VIDEO:
3231 ast_writestream(fs, f);
3232 default:
3233 /* Ignore all other frames */
3234 break;
3235 }
3236 ast_frfree(f);
3237 if (gotsilence)
3238 break;
3239 }
3240
3241 if (gotsilence) {
3242 ast_stream_rewind(fs, silence-1000);
3243 ast_truncstream(fs);
3244 sample_offset = ast_tellstream(fs);
3245 }
3246 ast_closestream(fs);
3247 ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
3248 }
3249
3250 if (silence > 0) {
3251 res = ast_set_read_format(chan, rfmt);
3252 if (res)
3253 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(chan));
3254 ast_dsp_free(sildet);
3255 }
3256
3257 if (silgen) {
3259 }
3260
3261 return RESULT_SUCCESS;
3262}
3263
3264static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3265{
3266 double timeout;
3267 struct timeval whentohangup = { 0, 0 };
3268
3269 if (argc != 3)
3270 return RESULT_SHOWUSAGE;
3271 if (sscanf(argv[2], "%30lf", &timeout) != 1)
3272 return RESULT_SHOWUSAGE;
3273 if (timeout < 0)
3274 timeout = 0;
3275 if (timeout) {
3276 whentohangup.tv_sec = timeout;
3277 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
3278 }
3279 ast_channel_lock(chan);
3280 ast_channel_setwhentohangup_tv(chan, whentohangup);
3281 ast_channel_unlock(chan);
3282 ast_agi_send(agi->fd, chan, "200 result=0\n");
3283 return RESULT_SUCCESS;
3284}
3285
3286static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3287{
3288 struct ast_channel *c;
3289
3290 if (argc == 1) {
3291 /* no argument: hangup the current channel */
3292 ast_set_hangupsource(chan, "dialplan/agi", 0);
3294 ast_agi_send(agi->fd, chan, "200 result=1\n");
3295 return RESULT_SUCCESS;
3296 } else if (argc == 2) {
3297 /* one argument: look for info on the specified channel */
3298 if ((c = ast_channel_get_by_name(argv[1]))) {
3299 /* we have a matching channel */
3300 ast_set_hangupsource(c, "dialplan/agi", 0);
3303 ast_agi_send(agi->fd, chan, "200 result=1\n");
3304 return RESULT_SUCCESS;
3305 }
3306 /* if we get this far no channel name matched the argument given */
3307 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3308 return RESULT_SUCCESS;
3309 } else {
3310 return RESULT_SHOWUSAGE;
3311 }
3312}
3313
3314static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3315{
3316 int res, workaround;
3317 struct ast_app *app_to_exec;
3318 const char *agi_exec_full_str;
3319 int agi_exec_full;
3320 struct ast_str *data_with_var = NULL;
3321
3322 if (argc < 2)
3323 return RESULT_SHOWUSAGE;
3324
3325 ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
3326
3327 if ((app_to_exec = pbx_findapp(argv[1]))) {
3328 ast_channel_lock(chan);
3329 if (!(workaround = ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS))) {
3331 }
3332 agi_exec_full_str = pbx_builtin_getvar_helper(chan, "AGIEXECFULL");
3333 agi_exec_full = ast_true(agi_exec_full_str);
3334 ast_channel_unlock(chan);
3335
3336 if (agi_exec_full) {
3337 if ((data_with_var = ast_str_create(16))) {
3338 ast_str_substitute_variables(&data_with_var, 0, chan, argv[2]);
3339 res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : ast_str_buffer(data_with_var));
3340 ast_free(data_with_var);
3341 } else {
3342 res = -2;
3343 }
3344 } else {
3345 res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
3346 }
3347 if (!workaround) {
3349 }
3350 } else {
3351 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
3352 res = -2;
3353 }
3354 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
3355
3356 /* Even though this is wrong, users are depending upon this result. */
3357 return res;
3358}
3359
3360static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3361{
3362 char tmp[256]="";
3363 char *l = NULL, *n = NULL;
3364
3365 if (argv[2]) {
3366 ast_copy_string(tmp, argv[2], sizeof(tmp));
3367 ast_callerid_parse(tmp, &n, &l);
3368 if (l)
3370 else
3371 l = "";
3372 if (!n)
3373 n = "";
3374 ast_set_callerid(chan, l, n, NULL);
3375 }
3376
3377 ast_agi_send(agi->fd, chan, "200 result=1\n");
3378 return RESULT_SUCCESS;
3379}
3380
3381static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3382{
3383 if (argc == 2) {
3384 /* no argument: supply info on the current channel */
3385 ast_agi_send(agi->fd, chan, "200 result=%u\n", ast_channel_state(chan));
3386 return RESULT_SUCCESS;
3387 } else if (argc == 3) {
3388 struct ast_channel_snapshot *snapshot;
3389
3390 /* one argument: look for info on the specified channel */
3391 snapshot = ast_channel_snapshot_get_latest_by_name(argv[2]);
3392 if (snapshot) {
3393 ast_agi_send(agi->fd, chan, "200 result=%u\n", snapshot->state);
3394 ao2_ref(snapshot, -1);
3395 return RESULT_SUCCESS;
3396 }
3397 /* if we get this far no channel name matched the argument given */
3398 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3399 return RESULT_SUCCESS;
3400 } else {
3401 return RESULT_SHOWUSAGE;
3402 }
3403}
3404
3405static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3406{
3407 if (argc != 4) {
3408 return RESULT_SHOWUSAGE;
3409 }
3410
3411 if (argv[3])
3412 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
3413
3414 ast_agi_send(agi->fd, chan, "200 result=1\n");
3415 return RESULT_SUCCESS;
3416}
3417
3418static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3419{
3420 char *ret;
3421 char tempstr[1024] = "";
3422
3423 if (argc != 3)
3424 return RESULT_SHOWUSAGE;
3425
3426 /* check if we want to execute an ast_custom_function */
3427 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
3428 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
3429 } else {
3430 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
3431 }
3432
3433 if (ret)
3434 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
3435 else
3436 ast_agi_send(agi->fd, chan, "200 result=0\n");
3437
3438 return RESULT_SUCCESS;
3439}
3440
3441static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3442{
3443 struct ast_channel *chan2 = NULL;
3444
3445 if (argc != 4 && argc != 5) {
3446 return RESULT_SHOWUSAGE;
3447 }
3448
3449 if (argc == 5) {
3450 chan2 = ast_channel_get_by_name(argv[4]);
3451 } else {
3452 chan2 = ast_channel_ref(chan);
3453 }
3454
3455 if (chan2) {
3456 struct ast_str *str = ast_str_create(16);
3457 if (!str) {
3458 ast_agi_send(agi->fd, chan, "200 result=0\n");
3459 return RESULT_SUCCESS;
3460 }
3461 ast_str_substitute_variables(&str, 0, chan2, argv[3]);
3462 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(str));
3463 ast_free(str);
3464 } else {
3465 ast_agi_send(agi->fd, chan, "200 result=0\n");
3466 }
3467
3468 if (chan2) {
3469 chan2 = ast_channel_unref(chan2);
3470 }
3471
3472 return RESULT_SUCCESS;
3473}
3474
3475static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3476{
3477 int level = 0;
3478
3479 if (argc < 2)
3480 return RESULT_SHOWUSAGE;
3481
3482 if (argv[2])
3483 sscanf(argv[2], "%30d", &level);
3484
3485 ast_verb(level, "%s: %s\n", ast_channel_data(chan), argv[1]);
3486
3487 ast_agi_send(agi->fd, chan, "200 result=1\n");
3488
3489 return RESULT_SUCCESS;
3490}
3491
3492static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3493{
3494 int res;
3495 struct ast_str *buf;
3496
3497 if (argc != 4)
3498 return RESULT_SHOWUSAGE;
3499
3500 if (!(buf = ast_str_create(16))) {
3501 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3502 return RESULT_SUCCESS;
3503 }
3504
3505 do {
3506 res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
3508 if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
3509 break;
3510 }
3511 if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
3512 break;
3513 }
3514 } while (1);
3515
3516 if (res)
3517 ast_agi_send(agi->fd, chan, "200 result=0\n");
3518 else
3519 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
3520
3521 ast_free(buf);
3522 return RESULT_SUCCESS;
3523}
3524
3525static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3526{
3527 int res;
3528
3529 if (argc != 5)
3530 return RESULT_SHOWUSAGE;
3531 res = ast_db_put(argv[2], argv[3], argv[4]);
3532 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
3533 return RESULT_SUCCESS;
3534}
3535
3536static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3537{
3538 int res;
3539
3540 if (argc != 4)
3541 return RESULT_SHOWUSAGE;
3542 res = ast_db_del(argv[2], argv[3]);
3543 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
3544 return RESULT_SUCCESS;
3545}
3546
3547static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3548{
3549 int num_deleted;
3550
3551 if ((argc < 3) || (argc > 4)) {
3552 return RESULT_SHOWUSAGE;
3553 }
3554 if (argc == 4) {
3555 num_deleted = ast_db_deltree(argv[2], argv[3]);
3556 } else {
3557 num_deleted = ast_db_deltree(argv[2], NULL);
3558 }
3559
3560 ast_agi_send(agi->fd, chan, "200 result=%c\n", num_deleted > 0 ? '0' : '1');
3561 return RESULT_SUCCESS;
3562}
3563
3564static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3565{
3566 switch (cmd) {
3567 case CLI_INIT:
3568 e->command = "agi set debug [on|off]";
3569 e->usage =
3570 "Usage: agi set debug [on|off]\n"
3571 " Enables/disables dumping of AGI transactions for\n"
3572 " debugging purposes.\n";
3573 return NULL;
3574
3575 case CLI_GENERATE:
3576 return NULL;
3577 }
3578
3579 if (a->argc != e->args)
3580 return CLI_SHOWUSAGE;
3581
3582 if (strncasecmp(a->argv[3], "off", 3) == 0) {
3583 agidebug = 0;
3584 } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
3585 agidebug = 1;
3586 } else {
3587 return CLI_SHOWUSAGE;
3588 }
3589 ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
3590 return CLI_SUCCESS;
3591}
3592
3593static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, const char * const argv[])
3594{
3595 ast_agi_send(agi->fd, chan, "200 result=0\n");
3596 return RESULT_SUCCESS;
3597}
3598
3599static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3600{
3601 if (argc < 3) {
3602 return RESULT_SHOWUSAGE;
3603 }
3604 if (!strncasecmp(argv[2], "on", 2))
3605 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
3606 else if (!strncasecmp(argv[2], "off", 3))
3607 ast_moh_stop(chan);
3608 ast_agi_send(agi->fd, chan, "200 result=0\n");
3609 return RESULT_SUCCESS;
3610}
3611
3612static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3613{
3614 struct ast_format_cap *cap;
3615
3616 /* If a structure already exists, return an error */
3617 if (agi->speech) {
3618 ast_agi_send(agi->fd, chan, "200 result=0\n");
3619 return RESULT_SUCCESS;
3620 }
3621
3623 return RESULT_FAILURE;
3624 }
3626 if ((agi->speech = ast_speech_new(argv[2], cap))) {
3627 ast_agi_send(agi->fd, chan, "200 result=1\n");
3628 } else {
3629 ast_agi_send(agi->fd, chan, "200 result=0\n");
3630 }
3631 ao2_ref(cap, -1);
3632
3633 return RESULT_SUCCESS;
3634}
3635
3636static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3637{
3638 /* Check for minimum arguments */
3639 if (argc != 4)
3640 return RESULT_SHOWUSAGE;
3641
3642 /* Check to make sure speech structure exists */
3643 if (!agi->speech) {
3644 ast_agi_send(agi->fd, chan, "200 result=0\n");
3645 return RESULT_SUCCESS;
3646 }
3647
3648 ast_speech_change(agi->speech, argv[2], argv[3]);
3649 ast_agi_send(agi->fd, chan, "200 result=1\n");
3650
3651 return RESULT_SUCCESS;
3652}
3653
3654static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3655{
3656 if (agi->speech) {
3658 agi->speech = NULL;
3659 ast_agi_send(agi->fd, chan, "200 result=1\n");
3660 } else {
3661 ast_agi_send(agi->fd, chan, "200 result=0\n");
3662 }
3663
3664 return RESULT_SUCCESS;
3665}
3666
3667static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3668{
3669 if (argc != 5)
3670 return RESULT_SHOWUSAGE;
3671
3672 if (!agi->speech) {
3673 ast_agi_send(agi->fd, chan, "200 result=0\n");
3674 return RESULT_SUCCESS;
3675 }
3676
3677 if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
3678 ast_agi_send(agi->fd, chan, "200 result=0\n");
3679 else
3680 ast_agi_send(agi->fd, chan, "200 result=1\n");
3681
3682 return RESULT_SUCCESS;
3683}
3684
3685static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3686{
3687 if (argc != 4)
3688 return RESULT_SHOWUSAGE;
3689
3690 if (!agi->speech) {
3691 ast_agi_send(agi->fd, chan, "200 result=0\n");
3692 return RESULT_SUCCESS;
3693 }
3694
3695 if (ast_speech_grammar_unload(agi->speech, argv[3]))
3696 ast_agi_send(agi->fd, chan, "200 result=0\n");
3697 else
3698 ast_agi_send(agi->fd, chan, "200 result=1\n");
3699
3700 return RESULT_SUCCESS;
3701}
3702
3703static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3704{
3705 if (argc != 4)
3706 return RESULT_SHOWUSAGE;
3707
3708 if (!agi->speech) {
3709 ast_agi_send(agi->fd, chan, "200 result=0\n");
3710 return RESULT_SUCCESS;
3711 }
3712
3713 if (ast_speech_grammar_activate(agi->speech, argv[3]))
3714 ast_agi_send(agi->fd, chan, "200 result=0\n");
3715 else
3716 ast_agi_send(agi->fd, chan, "200 result=1\n");
3717
3718 return RESULT_SUCCESS;
3719}
3720
3721static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3722{
3723 if (argc != 4)
3724 return RESULT_SHOWUSAGE;
3725
3726 if (!agi->speech) {
3727 ast_agi_send(agi->fd, chan, "200 result=0\n");
3728 return RESULT_SUCCESS;
3729 }
3730
3731 if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
3732 ast_agi_send(agi->fd, chan, "200 result=0\n");
3733 else
3734 ast_agi_send(agi->fd, chan, "200 result=1\n");
3735
3736 return RESULT_SUCCESS;
3737}
3738
3739static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
3740{
3741 struct ast_filestream *fs = NULL;
3742
3743 if (!(fs = ast_openstream(chan, filename, preflang)))
3744 return -1;
3745
3746 if (offset)
3747 ast_seekstream(fs, offset, SEEK_SET);
3748
3749 if (ast_applystream(chan, fs))
3750 return -1;
3751
3752 if (ast_playstream(fs))
3753 return -1;
3754
3755 return 0;
3756}
3757
3758static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3759{
3760 struct ast_speech *speech = agi->speech;
3761 const char *prompt;
3762 char dtmf = 0, tmp[4096] = "", *buf = tmp;
3763 int timeout = 0, offset = 0, res = 0, i = 0;
3764 long current_offset = 0;
3765 const char *reason = NULL;
3766 struct ast_frame *fr = NULL;
3767 struct ast_speech_result *result = NULL;
3768 size_t left = sizeof(tmp);
3769 time_t start = 0, current;
3770
3771 if (argc < 4)
3772 return RESULT_SHOWUSAGE;
3773
3774 if (!speech) {
3775 ast_agi_send(agi->fd, chan, "200 result=0\n");
3776 return RESULT_SUCCESS;
3777 }
3778
3779 prompt = argv[2];
3780 timeout = atoi(argv[3]);
3781
3782 /* If offset is specified then convert from text to integer */
3783 if (argc == 5)
3784 offset = atoi(argv[4]);
3785
3786 /* We want frames coming in signed linear */
3788 ast_agi_send(agi->fd, chan, "200 result=0\n");
3789 return RESULT_SUCCESS;
3790 }
3791
3792 /* Setup speech structure */
3793 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
3795 ast_speech_start(speech);
3796 }
3797
3798 /* Start playing prompt */
3799 speech_streamfile(chan, prompt, ast_channel_language(chan), offset);
3800
3801 /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
3802 while (ast_strlen_zero(reason)) {
3803 /* Run scheduled items */
3805
3806 /* See maximum time of waiting */
3807 if ((res = ast_sched_wait(ast_channel_sched(chan))) < 0)
3808 res = 1000;
3809
3810 /* Wait for frame */
3811 if (ast_waitfor(chan, res) > 0) {
3812 if (!(fr = ast_read(chan))) {
3813 reason = "hangup";
3814 break;
3815 }
3816 }
3817
3818 /* Perform timeout check */
3819 if ((timeout > 0) && (start > 0)) {
3820 time(&current);
3821 if ((current - start) >= timeout) {
3822 reason = "timeout";
3823 if (fr) {
3824 ast_frfree(fr);
3825 fr = NULL;
3826 }
3827 break;
3828 }
3829 }
3830
3831 /* Check the speech structure for any changes */
3832 ast_mutex_lock(&speech->lock);
3833
3834 /* See if we need to quiet the audio stream playback */
3835 if (ast_test_flag(speech, AST_SPEECH_QUIET) && ast_channel_stream(chan)) {
3836 current_offset = ast_tellstream(ast_channel_stream(chan));
3837 ast_stopstream(chan);
3839 }
3840
3841 /* Check each state */
3842 switch (speech->state) {
3844 /* If the stream is done, start timeout calculation */
3845 if ((timeout > 0) && start == 0 && ((!ast_channel_stream(chan)) || (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL))) {
3846 ast_stopstream(chan);
3847 time(&start);
3848 }
3849 /* Write audio frame data into speech engine if possible */
3850 if (fr && fr->frametype == AST_FRAME_VOICE)
3851 ast_speech_write(speech, fr->data.ptr, fr->datalen);
3852 break;
3854 /* Cue waiting sound if not already playing */
3855 if ((!ast_channel_stream(chan)) || (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL)) {
3856 ast_stopstream(chan);
3857 /* If a processing sound exists, or is not none - play it */
3858 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
3860 }
3861 break;
3863 /* Get the results */
3864 speech->results = ast_speech_results_get(speech);
3865 /* Change state to not ready */
3867 reason = "speech";
3868 break;
3869 default:
3870 break;
3871 }
3872 ast_mutex_unlock(&speech->lock);
3873
3874 /* Check frame for DTMF or hangup */
3875 if (fr) {
3876 if (fr->frametype == AST_FRAME_DTMF) {
3877 reason = "dtmf";
3878 dtmf = fr->subclass.integer;
3879 } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_HANGUP) {
3880 reason = "hangup";
3881 }
3882 ast_frfree(fr);
3883 fr = NULL;
3884 }
3885 }
3886
3887 if (!strcasecmp(reason, "speech")) {
3888 /* Build string containing speech results */
3889 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
3890 /* Build result string */
3891 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);
3892 /* Increment result count */
3893 i++;
3894 }
3895 /* Print out */
3896 ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
3897 } else if (!strcasecmp(reason, "dtmf")) {
3898 ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
3899 } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
3900 ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
3901 } else {
3902 ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
3903 }
3904
3905 return RESULT_SUCCESS;
3906}
3907
3908/*!
3909 * \brief AGI commands list
3910 */
3911static struct agi_command commands[] = {
3912 { { "answer", NULL }, handle_answer, NULL, NULL, 0 },
3913 { { "asyncagi", "break", NULL }, handle_asyncagi_break, NULL, NULL, 1 },
3914 { { "channel", "status", NULL }, handle_channelstatus, NULL, NULL, 0 },
3915 { { "database", "del", NULL }, handle_dbdel, NULL, NULL, 1 },
3916 { { "database", "deltree", NULL }, handle_dbdeltree, NULL, NULL, 1 },
3917 { { "database", "get", NULL }, handle_dbget, NULL, NULL, 1 },
3918 { { "database", "put", NULL }, handle_dbput, NULL, NULL, 1 },
3919 { { "exec", NULL }, handle_exec, NULL, NULL, 1 },
3920 { { "get", "data", NULL }, handle_getdata, NULL, NULL, 0 },
3921 { { "get", "full", "variable", NULL }, handle_getvariablefull, NULL, NULL, 1 },
3922 { { "get", "option", NULL }, handle_getoption, NULL, NULL, 0 },
3923 { { "get", "variable", NULL }, handle_getvariable, NULL, NULL, 1 },
3924 { { "hangup", NULL }, handle_hangup, NULL, NULL, 0 },
3925 { { "noop", NULL }, handle_noop, NULL, NULL, 1 },
3926 { { "receive", "char", NULL }, handle_recvchar, NULL, NULL, 0 },
3927 { { "receive", "text", NULL }, handle_recvtext, NULL, NULL, 0 },
3928 { { "record", "file", NULL }, handle_recordfile, NULL, NULL, 0 },
3929 { { "say", "alpha", NULL }, handle_sayalpha, NULL, NULL, 0},
3930 { { "say", "digits", NULL }, handle_saydigits, NULL, NULL, 0 },
3931 { { "say", "number", NULL }, handle_saynumber, NULL, NULL, 0 },
3932 { { "say", "phonetic", NULL }, handle_sayphonetic, NULL, NULL, 0},
3933 { { "say", "date", NULL }, handle_saydate, NULL, NULL, 0},
3934 { { "say", "time", NULL }, handle_saytime, NULL, NULL, 0},
3935 { { "say", "datetime", NULL }, handle_saydatetime, NULL, NULL, 0},
3936 { { "send", "image", NULL }, handle_sendimage, NULL, NULL, 0},
3937 { { "send", "text", NULL }, handle_sendtext, NULL, NULL, 0},
3938 { { "set", "autohangup", NULL }, handle_autohangup, NULL, NULL, 0},
3939 { { "set", "callerid", NULL }, handle_setcallerid, NULL, NULL, 0},
3940 { { "set", "context", NULL }, handle_setcontext, NULL, NULL, 0},
3941 { { "set", "extension", NULL }, handle_setextension, NULL, NULL, 0},
3942 { { "set", "music", NULL }, handle_setmusic, NULL, NULL, 0 },
3943 { { "set", "priority", NULL }, handle_setpriority, NULL, NULL, 0 },
3944 { { "set", "variable", NULL }, handle_setvariable, NULL, NULL, 1 },
3945 { { "stream", "file", NULL }, handle_streamfile, NULL, NULL, 0 },
3946 { { "control", "stream", "file", NULL }, handle_controlstreamfile, NULL, NULL, 0 },
3947 { { "tdd", "mode", NULL }, handle_tddmode, NULL, NULL, 0 },
3948 { { "verbose", NULL }, handle_verbose, NULL, NULL, 1 },
3949 { { "wait", "for", "digit", NULL }, handle_waitfordigit, NULL, NULL, 0 },
3950 { { "speech", "create", NULL }, handle_speechcreate, NULL, NULL, 0 },
3951 { { "speech", "set", NULL }, handle_speechset, NULL, NULL, 0 },
3952 { { "speech", "destroy", NULL }, handle_speechdestroy, NULL, NULL, 1 },
3953 { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, NULL, NULL, 0 },
3954 { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, NULL, NULL, 1 },
3955 { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, NULL, NULL, 0 },
3956 { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, NULL, NULL, 0 },
3957 { { "speech", "recognize", NULL }, handle_speechrecognize, NULL, NULL, 0 },
3958};
3959
3961
3962static char *help_workhorse(int fd, const char * const match[])
3963{
3964 char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
3965 struct agi_command *e;
3966
3967 if (match)
3968 ast_join(matchstr, sizeof(matchstr), match);
3969
3970 ast_cli(fd, "%5.5s %30.30s %s\n","Dead","Command","Description");
3973 if (!e->cmda[0])
3974 break;
3975 /* Hide commands that start with '_' */
3976 if ((e->cmda[0])[0] == '_')
3977 continue;
3978 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
3979 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
3980 continue;
3981 ast_cli(fd, "%5.5s %30.30s %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
3982 }
3984
3985 return CLI_SUCCESS;
3986}
3987
3989{
3990 char fullcmd[MAX_CMD_LEN];
3991
3992 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
3993
3994 if (!find_command(cmd->cmda, 1)) {
3995 *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
3996 if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
3997#ifdef AST_XML_DOCS
3998 *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd, NULL);
3999 *((char **) &cmd->since) = ast_xmldoc_build_since("agi", fullcmd, NULL);
4000 *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd, NULL);
4001 *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd, NULL);
4002 *((char **) &cmd->arguments) = ast_xmldoc_build_arguments("agi", fullcmd, NULL);
4003 *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd, NULL);
4004 *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
4005#endif
4006#ifndef HAVE_NULLSAFE_PRINTF
4007 if (!cmd->summary) {
4008 *((char **) &cmd->summary) = ast_strdup("");
4009 }
4010 if (!cmd->usage) {
4011 *((char **) &cmd->usage) = ast_strdup("");
4012 }
4013 if (!cmd->syntax) {
4014 *((char **) &cmd->syntax) = ast_strdup("");
4015 }
4016 if (!cmd->seealso) {
4017 *((char **) &cmd->seealso) = ast_strdup("");
4018 }
4019#endif
4020 }
4021
4022 cmd->mod = mod;
4026 ast_verb(5, "AGI Command '%s' registered\n",fullcmd);
4027 return 1;
4028 } else {
4029 ast_log(LOG_WARNING, "Command already registered!\n");
4030 return 0;
4031 }
4032}
4033
4035{
4036 struct agi_command *e;
4037 int unregistered = 0;
4038 char fullcmd[MAX_CMD_LEN];
4039
4040 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
4041
4044 if (cmd == e) {
4046#ifdef AST_XML_DOCS
4047 if (e->docsrc == AST_XML_DOC) {
4048 ast_free((char *) e->summary);
4049 ast_free((char *) e->since);
4050 ast_free((char *) e->usage);
4051 ast_free((char *) e->syntax);
4052 ast_free((char *) e->arguments);
4053 ast_free((char *) e->seealso);
4054 *((char **) &e->summary) = NULL;
4055 *((char **) &e->since) = NULL;
4056 *((char **) &e->usage) = NULL;
4057 *((char **) &e->syntax) = NULL;
4058 *((char **) &e->arguments) = NULL;
4059 *((char **) &e->seealso) = NULL;
4060 }
4061#endif
4062 unregistered=1;
4063 break;
4064 }
4065 }
4068 if (unregistered) {
4069 ast_verb(5, "AGI Command '%s' unregistered\n",fullcmd);
4070 }
4071 return unregistered;
4072}
4073
4075{
4076 unsigned int i, x = 0;
4077
4078 for (i = 0; i < len; i++) {
4079 if (ast_agi_register(mod, cmd + i) == 1) {
4080 x++;
4081 continue;
4082 }
4083
4084 /* registration failed, unregister everything
4085 that had been registered up to that point
4086 */
4087 for (; x > 0; x--) {
4088 /* we are intentionally ignoring the
4089 result of ast_agi_unregister() here,
4090 but it should be safe to do so since
4091 we just registered these commands and
4092 the only possible way for unregistration
4093 to fail is if the command is not
4094 registered
4095 */
4096 (void) ast_agi_unregister(cmd + x - 1);
4097 }
4098 return -1;
4099 }
4100
4101 return 0;
4102}
4103
4105{
4106 unsigned int i;
4107 int res = 0;
4108
4109 for (i = 0; i < len; i++) {
4110 /* remember whether any of the unregistration
4111 attempts failed... there is no recourse if
4112 any of them do
4113 */
4114 res |= ast_agi_unregister(cmd + i);
4115 }
4116
4117 return res;
4118}
4119
4120static agi_command *find_command(const char * const cmds[], int exact)
4121{
4122 int y, match;
4123 struct agi_command *e;
4124
4127 if (!e->cmda[0])
4128 break;
4129 /* start optimistic */
4130 match = 1;
4131 for (y = 0; match && cmds[y]; y++) {
4132 /* If there are no more words in the command (and we're looking for
4133 an exact match) or there is a difference between the two words,
4134 then this is not a match */
4135 if (!e->cmda[y] && !exact)
4136 break;
4137 /* don't segfault if the next part of a command doesn't exist */
4138 if (!e->cmda[y]) {
4140 return NULL;
4141 }
4142 if (strcasecmp(e->cmda[y], cmds[y]))
4143 match = 0;
4144 }
4145 /* If more words are needed to complete the command then this is not
4146 a candidate (unless we're looking for a really inexact answer */
4147 if ((exact > -1) && e->cmda[y])
4148 match = 0;
4149 if (match) {
4151 return e;
4152 }
4153 }
4155 return NULL;
4156}
4157
4158static int parse_args(char *s, int *max, const char *argv[])
4159{
4160 int x = 0, quoted = 0, escaped = 0, whitespace = 1;
4161 char *cur;
4162
4163 cur = s;
4164 while(*s) {
4165 switch(*s) {
4166 case '"':
4167 /* If it's escaped, put a literal quote */
4168 if (escaped)
4169 goto normal;
4170 else
4171 quoted = !quoted;
4172 if (quoted && whitespace) {
4173 /* If we're starting a quote, coming off white space start a new word, too */
4174 argv[x++] = cur;
4175 whitespace=0;
4176 }
4177 escaped = 0;
4178 break;
4179 case ' ':
4180 case '\t':
4181 if (!quoted && !escaped) {
4182 /* If we're not quoted, mark this as whitespace, and
4183 end the previous argument */
4184 whitespace = 1;
4185 *(cur++) = '\0';
4186 } else
4187 /* Otherwise, just treat it as anything else */
4188 goto normal;
4189 break;
4190 case '\\':
4191 /* If we're escaped, print a literal, otherwise enable escaping */
4192 if (escaped) {
4193 goto normal;
4194 } else {
4195 escaped=1;
4196 }
4197 break;
4198 default:
4199normal:
4200 if (whitespace) {
4201 if (x >= MAX_ARGS -1) {
4202 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
4203 break;
4204 }
4205 /* Coming off of whitespace, start the next argument */
4206 argv[x++] = cur;
4207 whitespace=0;
4208 }
4209 *(cur++) = *s;
4210 escaped=0;
4211 }
4212 s++;
4213 }
4214 /* Null terminate */
4215 *(cur++) = '\0';
4216 argv[x] = NULL;
4217 *max = x;
4218 return 0;
4219}
4220
4221static void publish_async_exec_end(struct ast_channel *chan, int command_id, const char *command, int result_code, const char *result)
4222{
4223 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4224 blob = ast_json_pack("{s: i, s: s, s: i, s: s}",
4225 "CommandId", command_id,
4226 "Command", command,
4227 "ResultCode", result_code,
4228 "Result", result);
4229 ast_channel_publish_cached_blob(chan, agi_exec_end_type(), blob);
4230}
4231
4232static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
4233{
4234 const char *argv[MAX_ARGS] = {0};
4235 int argc = MAX_ARGS;
4236 int res;
4237 agi_command *c;
4238 char *ami_cmd = ast_strdupa(buf);
4239 const char *ami_res;
4240 int command_id = ast_random();
4241 int resultcode = 0;
4242 RAII_VAR(struct ast_json *, startblob, NULL, ast_json_unref);
4243
4244 startblob = ast_json_pack("{s: i, s: s}",
4245 "CommandId", command_id,
4246 "Command", ami_cmd);
4247 ast_channel_publish_cached_blob(chan, agi_exec_start_type(), startblob);
4248
4249 parse_args(buf, &argc, argv);
4250 c = find_command(argv, 0);
4251 if (!c || !ast_module_running_ref(c->mod)) {
4252 ami_res = "Invalid or unknown command";
4253 resultcode = 510;
4254
4255 ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
4256
4257 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4258
4259 return AGI_RESULT_SUCCESS;
4260 }
4261
4262 if (!dead || (dead && c->dead)) {
4263 res = c->handler(chan, agi, argc, argv);
4264 switch (res) {
4265 case RESULT_SHOWUSAGE:
4266 ami_res = "Usage";
4267 resultcode = 520;
4268
4269 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4270
4271 if (ast_strlen_zero(c->usage)) {
4272 ast_agi_send(agi->fd, chan, "520 Invalid command syntax. Proper usage not available.\n");
4273 } else {
4274 ast_agi_send(agi->fd, chan, "520-Invalid command syntax. Proper usage follows:\n");
4275 ast_agi_send(agi->fd, chan, "%s\n", c->usage);
4276 ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
4277 }
4278
4279 break;
4280 case RESULT_FAILURE:
4281 ami_res = "Failure";
4282 resultcode = -1;
4283
4284 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4285
4286 /* The RESULT_FAILURE code is usually because the channel hungup. */
4287 return AGI_RESULT_FAILURE;
4288 case ASYNC_AGI_BREAK:
4289 ami_res = "Success";
4290 resultcode = 200;
4291
4292 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4293
4295 case RESULT_SUCCESS:
4296 ami_res = "Success";
4297 resultcode = 200;
4298
4299 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4300
4301 break;
4302 default:
4303 ami_res = "Unknown Result";
4304 resultcode = 200;
4305
4306 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4307
4308 break;
4309 }
4310 } else {
4311 ami_res = "Command Not Permitted on a dead channel or intercept routine";
4312 resultcode = 511;
4313
4314 ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
4315
4316 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4317 }
4318 ast_module_unref(c->mod);
4319
4320 return AGI_RESULT_SUCCESS;
4321}
4322
4323static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
4324{
4325 struct ast_channel *c;
4326 int outfd;
4327 int ms;
4328 int needhup = 0;
4329 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
4330 struct ast_frame *f;
4331 char buf[AGI_BUF_LEN];
4332 char *res = NULL;
4333 FILE *readf;
4334 /* how many times we'll retry if ast_waitfor_nandfs will return without either
4335 channel or file descriptor in case select is interrupted by a system call (EINTR) */
4336 int retry = AGI_NANDFS_RETRY;
4337 int send_sighup;
4338 const char *sighup_str;
4339 const char *exit_on_hangup_str;
4340 int exit_on_hangup;
4341 /*! Running in an interception routine is like DeadAGI mode. No touchy the channel frames. */
4342 int in_intercept = ast_channel_get_intercept_mode();
4343
4344 ast_channel_lock(chan);
4345 sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
4346 send_sighup = !ast_false(sighup_str);
4347 exit_on_hangup_str = pbx_builtin_getvar_helper(chan, "AGIEXITONHANGUP");
4348 exit_on_hangup = ast_true(exit_on_hangup_str);
4349 ast_channel_unlock(chan);
4350
4351 if (!(readf = fdopen(agi->ctrl, "r"))) {
4352 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
4353 if (send_sighup && pid > -1)
4354 kill(pid, SIGHUP);
4355 close(agi->ctrl);
4356 return AGI_RESULT_FAILURE;
4357 }
4358
4359 setlinebuf(readf);
4360 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
4361 for (;;) {
4362 if (needhup) {
4363 needhup = 0;
4364 dead = 1;
4365 if (send_sighup) {
4366 if (pid > -1) {
4367 kill(pid, SIGHUP);
4368 } else if (agi->fast) {
4369 ast_agi_send(agi->fd, chan, "HANGUP\n");
4370 }
4371 }
4372 if (exit_on_hangup) {
4373 break;
4374 }
4375 }
4376 ms = -1;
4377 if (dead || in_intercept) {
4378 c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
4379 } else if (!ast_check_hangup(chan)) {
4380 c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
4381 } else {
4382 /*
4383 * Read the channel control queue until it is dry so we can
4384 * switch to dead mode.
4385 */
4386 c = chan;
4387 }
4388 if (c) {
4389 retry = AGI_NANDFS_RETRY;
4390 /* Idle the channel until we get a command */
4391 f = ast_read(c);
4392 if (!f) {
4393 ast_debug(1, "%s hungup\n", ast_channel_name(chan));
4394 needhup = 1;
4395 if (!returnstatus) {
4396 returnstatus = AGI_RESULT_HANGUP;
4397 }
4398 } else {
4399 /* If it's voice, write it to the audio pipe */
4400 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
4401 /* Write, ignoring errors */
4402 if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
4403 }
4404 }
4405 ast_frfree(f);
4406 }
4407 } else if (outfd > -1) {
4408 size_t len = sizeof(buf);
4409 size_t buflen = 0;
4410 enum agi_result cmd_status;
4411
4412 retry = AGI_NANDFS_RETRY;
4413 buf[0] = '\0';
4414
4415 while (len > 1) {
4416 res = fgets(buf + buflen, len, readf);
4417 if (feof(readf))
4418 break;
4419 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
4420 break;
4421 if (res != NULL && !agi->fast)
4422 break;
4423 buflen = strlen(buf);
4424 if (buflen && buf[buflen - 1] == '\n')
4425 break;
4426 len = sizeof(buf) - buflen;
4427 if (agidebug)
4428 ast_verbose("AGI Rx << temp buffer %s - errno %s\nNo \\n received, checking again.\n", buf, strerror(errno));
4429 }
4430
4431 if (!buf[0]) {
4432 /* Program terminated */
4433 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", ast_channel_name(chan), request, returnstatus);
4434 if (pid > 0)
4435 waitpid(pid, status, 0);
4436 /* No need to kill the pid anymore, since they closed us */
4437 pid = -1;
4438 break;
4439 }
4440
4441 /* Special case for inability to execute child process */
4442 if (*buf && strncasecmp(buf, "failure", 7) == 0) {
4443 returnstatus = AGI_RESULT_FAILURE;
4444 break;
4445 }
4446
4447 /* get rid of trailing newline, if any */
4448 buflen = strlen(buf);
4449 if (buflen && buf[buflen - 1] == '\n') {
4450 buf[buflen - 1] = '\0';
4451 }
4452
4453 if (agidebug)
4454 ast_verbose("<%s>AGI Rx << %s\n", ast_channel_name(chan), buf);
4455 cmd_status = agi_handle_command(chan, agi, buf, dead || in_intercept);
4456 switch (cmd_status) {
4457 case AGI_RESULT_FAILURE:
4458 if (dead || in_intercept || !ast_check_hangup(chan)) {
4459 /* The failure was not because of a hangup. */
4460 returnstatus = AGI_RESULT_FAILURE;
4461 }
4462 break;
4463 default:
4464 break;
4465 }
4466 } else {
4467 if (--retry <= 0) {
4468 ast_log(LOG_WARNING, "No channel, no fd?\n");
4469 returnstatus = AGI_RESULT_FAILURE;
4470 break;
4471 }
4472 }
4473 }
4474
4475 if (agi->speech) {
4477 }
4478 /* Notify process */
4479 if (send_sighup) {
4480 if (pid > -1) {
4481 if (kill(pid, SIGHUP)) {
4482 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
4483 } else { /* Give the process a chance to die */
4484 usleep(1);
4485 }
4486 waitpid(pid, status, WNOHANG);
4487 } else if (agi->fast) {
4488 ast_agi_send(agi->fd, chan, "HANGUP\n");
4489 }
4490 }
4491 fclose(readf);
4492 return returnstatus;
4493}
4494
4495static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4496{
4497 struct agi_command *command;
4498 char fullcmd[MAX_CMD_LEN];
4499 int error = 0;
4500
4501 switch (cmd) {
4502 case CLI_INIT:
4503 e->command = "agi show commands [topic]";
4504 e->usage =
4505 "Usage: agi show commands [topic] <topic>\n"
4506 " When called with a topic as an argument, displays usage\n"
4507 " information on the given command. If called without a\n"
4508 " topic, it provides a list of AGI commands.\n";
4509 case CLI_GENERATE:
4510 return NULL;
4511 }
4512 if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
4513 return CLI_SHOWUSAGE;
4514 if (a->argc > e->args - 1) {
4515 command = find_command(a->argv + e->args, 1);
4516 if (command) {
4517 char *synopsis = NULL, *since = NULL, *description = NULL, *syntax = NULL, *arguments = NULL, *seealso = NULL;
4518
4519 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
4520
4521#ifdef AST_XML_DOCS
4522 if (command->docsrc == AST_XML_DOC) {
4523 synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
4524 since = ast_xmldoc_printable(S_OR(command->since, "Not available"), 1);
4525 description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
4526 syntax = ast_xmldoc_printable(S_OR(command->syntax, "Not available"), 1);
4527 arguments = ast_xmldoc_printable(S_OR(command->arguments, "Not available"), 1);
4528 seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
4529 } else
4530#endif
4531 {
4532 synopsis = ast_strdup(S_OR(command->summary, "Not Available"));
4533 since = ast_strdup(S_OR(command->since, "Not Available"));
4534 description = ast_strdup(S_OR(command->usage, "Not Available"));
4535 syntax = ast_strdup(S_OR(command->syntax, "Not Available"));
4536 arguments = ast_strdup(S_OR(command->arguments, "Not Available"));
4537 seealso = ast_strdup(S_OR(command->seealso, "Not Available"));
4538 }
4539
4540 if (!synopsis || !since || !description || !syntax || !arguments || !seealso) {
4541 error = 1;
4542 goto return_cleanup;
4543 }
4544
4545 ast_cli(a->fd, "\n"
4546 "%s -= Info about AGI '%s' =- %s\n\n"
4547 COLORIZE_FMT "\n"
4548 "%s\n\n"
4549 COLORIZE_FMT "\n"
4550 "%s\n\n"
4551 COLORIZE_FMT "\n"
4552 "%s\n\n"
4553 COLORIZE_FMT "\n"
4554 "%s\n\n"
4555 COLORIZE_FMT "\n"
4556 "%s\n\n"
4557 COLORIZE_FMT "\n"
4558 "%s\n\n"
4559 COLORIZE_FMT "\n"
4560 "%s\n\n",
4562 COLORIZE(COLOR_MAGENTA, 0, "[Synopsis]"), synopsis,
4563 COLORIZE(COLOR_MAGENTA, 0, "[Since]"), since,
4564 COLORIZE(COLOR_MAGENTA, 0, "[Description]"), description,
4565 COLORIZE(COLOR_MAGENTA, 0, "[Syntax]"), syntax,
4566 COLORIZE(COLOR_MAGENTA, 0, "[Arguments]"), arguments,
4567 COLORIZE(COLOR_MAGENTA, 0, "[Runs Dead]"), command->dead ? "Yes" : "No",
4568 COLORIZE(COLOR_MAGENTA, 0, "[See Also]"), seealso
4569 );
4570
4571return_cleanup:
4573 ast_free(since);
4574 ast_free(description);
4578 } else {
4579 if (find_command(a->argv + e->args, -1)) {
4580 return help_workhorse(a->fd, a->argv + e->args);
4581 } else {
4582 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
4583 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
4584 }
4585 }
4586 } else {
4587 return help_workhorse(a->fd, NULL);
4588 }
4589 return (error ? CLI_FAILURE : CLI_SUCCESS);
4590}
4591
4592/*! \brief Convert string to use HTML escaped characters
4593 \note Maybe this should be a generic function?
4594*/
4595static void write_html_escaped(FILE *htmlfile, char *str)
4596{
4597 char *cur = str;
4598
4599 while(*cur) {
4600 switch (*cur) {
4601 case '<':
4602 fprintf(htmlfile, "%s", "&lt;");
4603 break;
4604 case '>':
4605 fprintf(htmlfile, "%s", "&gt;");
4606 break;
4607 case '&':
4608 fprintf(htmlfile, "%s", "&amp;");
4609 break;
4610 case '"':
4611 fprintf(htmlfile, "%s", "&quot;");
4612 break;
4613 default:
4614 fprintf(htmlfile, "%c", *cur);
4615 break;
4616 }
4617 cur++;
4618 }
4619
4620 return;
4621}
4622
4623static int write_htmldump(const char *filename)
4624{
4625 struct agi_command *command;
4626 char fullcmd[MAX_CMD_LEN];
4627 FILE *htmlfile;
4628
4629 if (!(htmlfile = fopen(filename, "wt")))
4630 return -1;
4631
4632 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
4633 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
4634 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
4635
4638 char *tempstr, *stringp;
4639
4640 if (!command->cmda[0]) /* end ? */
4641 break;
4642 /* Hide commands that start with '_' */
4643 if ((command->cmda[0])[0] == '_')
4644 continue;
4645 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
4646
4647 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
4648 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
4649#ifdef AST_XML_DOCS
4650 stringp = ast_xmldoc_printable(command->usage, 0);
4651#else
4652 stringp = ast_strdup(command->usage);
4653#endif
4654 tempstr = strsep(&stringp, "\n");
4655
4656 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
4657 write_html_escaped(htmlfile, tempstr);
4658 fprintf(htmlfile, "</TD></TR>\n");
4659 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
4660
4661 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
4662 write_html_escaped(htmlfile, tempstr);
4663 fprintf(htmlfile, "<BR>\n");
4664 }
4665 fprintf(htmlfile, "</TD></TR>\n");
4666 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
4667 ast_free(stringp);
4668 }
4670 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
4671 fclose(htmlfile);
4672 return 0;
4673}
4674
4675static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4676{
4677 switch (cmd) {
4678 case CLI_INIT:
4679 e->command = "agi dump html";
4680 e->usage =
4681 "Usage: agi dump html <filename>\n"
4682 " Dumps the AGI command list in HTML format to the given\n"
4683 " file.\n";
4684 return NULL;
4685 case CLI_GENERATE:
4686 return NULL;
4687 }
4688 if (a->argc != e->args + 1)
4689 return CLI_SHOWUSAGE;
4690
4691 if (write_htmldump(a->argv[e->args]) < 0) {
4692 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
4693 return CLI_SHOWUSAGE;
4694 }
4695 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
4696 return CLI_SUCCESS;
4697}
4698
4699static int agi_exec_full(struct ast_channel *chan, const char *data, int enhanced, int dead)
4700{
4701 enum agi_result res;
4702 char *buf;
4703 int fds[2], efd = -1, pid = -1;
4704 int safe_fork_called = 0;
4706 AST_APP_ARG(arg)[MAX_ARGS];
4707 );
4708 AGI agi;
4709
4710 if (ast_strlen_zero(data)) {
4711 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
4712 return -1;
4713 }
4714 if (dead)
4715 ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
4716 memset(&agi, 0, sizeof(agi));
4717 buf = ast_strdupa(data);
4719 args.arg[args.argc] = NULL;
4720#if 0
4721 /* Answer if need be */
4722 if (chan->_state != AST_STATE_UP) {
4723 if (ast_answer(chan))
4724 return -1;
4725 }
4726#endif
4727 res = launch_script(chan, args.arg[0], args.argc, args.arg, fds, enhanced ? &efd : NULL, &pid, &safe_fork_called);
4728 /* Async AGI do not require run_agi(), so just proceed if normal AGI
4729 or Fast AGI are setup with success. */
4730 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
4731 int status = 0;
4732 agi.fd = fds[1];
4733 agi.ctrl = fds[0];
4734 agi.audio = efd;
4735 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
4736 res = run_agi(chan, args.arg[0], &agi, pid, &status, dead, args.argc, args.arg);
4737 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
4738 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
4739 res = AGI_RESULT_FAILURE;
4740 if (fds[1] != fds[0])
4741 close(fds[1]);
4742 if (efd > -1)
4743 close(efd);
4744 }
4745 if (safe_fork_called) {
4747 }
4748
4749 switch (res) {
4750 case AGI_RESULT_SUCCESS:
4753 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
4754 break;
4755 case AGI_RESULT_FAILURE:
4756 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
4757 break;
4759 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
4760 break;
4761 case AGI_RESULT_HANGUP:
4762 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
4763 return -1;
4764 }
4765
4766 return 0;
4767}
4768
4769static int agi_exec(struct ast_channel *chan, const char *data)
4770{
4771 if (!ast_check_hangup(chan))
4772 return agi_exec_full(chan, data, 0, 0);
4773 else
4774 return agi_exec_full(chan, data, 0, 1);
4775}
4776
4777static int eagi_exec(struct ast_channel *chan, const char *data)
4778{
4779 int res;
4780 struct ast_format *readformat;
4781 struct ast_format *requested_format = NULL;
4782 const char *requested_format_name;
4783
4784 if (ast_check_hangup(chan)) {
4785 ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
4786 return 0;
4787 }
4788
4789 requested_format_name = pbx_builtin_getvar_helper(chan, "EAGI_AUDIO_FORMAT");
4790 if (requested_format_name) {
4791 requested_format = ast_format_cache_get(requested_format_name);
4792 if (requested_format) {
4793 ast_verb(3, "<%s> Setting EAGI audio pipe format to %s\n",
4794 ast_channel_name(chan), ast_format_get_name(requested_format));
4795 } else {
4796 ast_log(LOG_ERROR, "Could not find requested format: %s\n", requested_format_name);
4797 }
4798 }
4799
4800 readformat = ao2_bump(ast_channel_readformat(chan));
4801 if (ast_set_read_format(chan, requested_format ?: ast_format_slin)) {
4802 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", ast_channel_name(chan));
4803 ao2_cleanup(requested_format);
4804 ao2_cleanup(readformat);
4805 return -1;
4806 }
4807 res = agi_exec_full(chan, data, 1, 0);
4808 if (!res) {
4809 if (ast_set_read_format(chan, readformat)) {
4810 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", ast_channel_name(chan),
4811 ast_format_get_name(readformat));
4812 }
4813 }
4814 ao2_cleanup(requested_format);
4815 ao2_cleanup(readformat);
4816 return res;
4817}
4818
4819static int deadagi_exec(struct ast_channel *chan, const char *data)
4820{
4821 ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
4822 return agi_exec(chan, data);
4823}
4824
4825static struct ast_cli_entry cli_agi[] = {
4826 AST_CLI_DEFINE(handle_cli_agi_add_cmd, "Add AGI command to a channel in Async AGI"),
4827 AST_CLI_DEFINE(handle_cli_agi_debug, "Enable/Disable AGI debugging"),
4828 AST_CLI_DEFINE(handle_cli_agi_show, "List AGI commands or specific help"),
4829 AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format")
4830};
4831
4832#ifdef TEST_FRAMEWORK
4833AST_TEST_DEFINE(test_agi_null_docs)
4834{
4835 int res = AST_TEST_PASS;
4836 struct agi_command noop_command =
4837 { { "testnoop", NULL }, handle_noop, NULL, NULL, 0 };
4838
4839 switch (cmd) {
4840 case TEST_INIT:
4841 info->name = "null_agi_docs";
4842 info->category = "/res/agi/";
4843 info->summary = "AGI command with no documentation";
4844 info->description = "Test whether an AGI command with no documentation will crash Asterisk";
4845 return AST_TEST_NOT_RUN;
4846 case TEST_EXECUTE:
4847 break;
4848 }
4849
4850 if (ast_agi_register(ast_module_info->self, &noop_command) == 0) {
4851 ast_test_status_update(test, "Unable to register testnoop command, because res_agi is not loaded.\n");
4852 return AST_TEST_NOT_RUN;
4853 }
4854
4855#ifndef HAVE_NULLSAFE_PRINTF
4856 /* Test for condition without actually crashing Asterisk */
4857 if (noop_command.usage == NULL) {
4858 ast_test_status_update(test, "AGI testnoop usage was not updated properly.\n");
4859 res = AST_TEST_FAIL;
4860 }
4861 if (noop_command.syntax == NULL) {
4862 ast_test_status_update(test, "AGI testnoop syntax was not updated properly.\n");
4863 res = AST_TEST_FAIL;
4864 }
4865#endif
4866
4867 ast_agi_unregister(&noop_command);
4868 return res;
4869}
4870#endif
4871
4872static int unload_module(void)
4873{
4874 STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_start_type);
4875 STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_end_type);
4876 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_start_type);
4877 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_exec_type);
4878 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_end_type);
4879
4886 AST_TEST_UNREGISTER(test_agi_null_docs);
4887 return 0;
4888}
4889
4890static int load_module(void)
4891{
4892 int err = 0;
4893
4894 err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_start_type);
4895 err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_end_type);
4896 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_start_type);
4897 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_exec_type);
4898 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_end_type);
4899
4906
4907 AST_TEST_REGISTER(test_agi_null_docs);
4908
4909 if (err) {
4910 unload_module();
4912 }
4913
4915}
4916
4918 .support_level = AST_MODULE_SUPPORT_CORE,
4919 .load = load_module,
4920 .unload = unload_module,
4921 .load_pri = AST_MODPRI_APP_DEPEND,
4922 .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:2786
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:1848
#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:2387
static const char type[]
Definition: chan_ooh323.c:109
static int request(void *obj)
Definition: chan_pjsip.c:2605
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:4734
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:3016
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:11060
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2414
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1848
#define ast_channel_lock(chan)
Definition: channel.h:2970
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:8190
int ast_recvchar(struct ast_channel *chan, int timeout)
Receives a text character from a channel.
Definition: channel.c:4723
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3190
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:10359
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:8236
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2995
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:4274
int ast_sendtext(struct ast_channel *chan, const char *text)
Sends text to a channel.
Definition: channel.c:4826
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:7355
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5779
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
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:2528
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2500
ast_timing_func_t ast_channel_timingfunc(const struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3006
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
@ AST_FLAG_DISABLE_WORKAROUNDS
Definition: channel.h:1042
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:7443
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1481
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2834
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4294
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2971
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:3267
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:2428
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
@ AST_SOFTHANGUP_EXPLICIT
Definition: channel.h:1168
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
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:1872
@ 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:1788
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1783
@ 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:1488
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:2009
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1758
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2206
#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:1093
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:845
int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int monfd)
Definition: file.c:1857
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition: file.c:244
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
Definition: file.c:1083
int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
Rewind stream ms.
Definition: file.c:1108
int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
Applies a open stream to a channel.
Definition: file.c:1065
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:856
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1301
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:1431
int ast_truncstream(struct ast_filestream *fs)
Trunc stream at current location.
Definition: file.c:1088
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1119
int ast_playstream(struct ast_filestream *s)
Play a open stream on a channel.
Definition: file.c:1071
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1848
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:1986
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2018
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:555
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1647
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7697
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:918
#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:194
#define ast_mutex_lock(a)
Definition: lock.h:193
size_t current
Definition: main/cli.c:113
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:10237
#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:7787
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7797
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:124
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_KEY_DIR
Definition: options.c:161
const char * ast_config_AST_MODULE_DIR
Definition: options.c:153
const char * ast_config_AST_RUN_DIR
Definition: options.c:162
const char * ast_config_AST_DATA_DIR
Definition: options.c:158
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:151
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:154
const char * ast_config_AST_AGI_DIR
Definition: options.c:160
const char * ast_config_AST_VAR_DIR
Definition: options.c:157
const char * ast_config_AST_CONFIG_FILE
Definition: options.c:152
const char * ast_config_AST_MONITOR_DIR
Definition: options.c:155
const char * ast_config_AST_LOG_DIR
Definition: options.c:159
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:4195
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:6960
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:3612
static char * eapp
Definition: res_agi.c:1556
static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3045
static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2951
static int parse_args(char *s, int *max, const char *argv[])
Definition: res_agi.c:4158
static struct ast_cli_entry cli_agi[]
Definition: res_agi.c:4825
static struct ast_manager_event_blob * agi_exec_start_to_ami(struct stasis_message *message)
Definition: res_agi.c:1600
static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2999
static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3286
static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2541
static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3475
static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
Definition: res_agi.c:2483
#define AMI_BUF_SIZE
#define MAX_CMD_LEN
Definition: res_agi.c:1549
#define MAX_ARGS
Definition: res_agi.c:1548
static agi_command * find_command(const char *const cmds[], int exact)
Definition: res_agi.c:4120
static void agi_destroy_commands_cb(void *data)
Definition: res_agi.c:1690
static struct ast_manager_event_blob * agi_async_end_to_ami(struct stasis_message *message)
Definition: res_agi.c:1620
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:4104
static enum agi_result launch_ha_netscript(char *agiurl, char *argv[], int *fds)
Definition: res_agi.c:2306
static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3547
static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2599
static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3703
static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3026
static char * handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: res_agi.c:4495
static enum agi_result async_agi_read_frame(struct ast_channel *chan)
Definition: res_agi.c:1919
static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3685
static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3525
static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3405
static struct ast_manager_event_blob * agi_exec_end_to_ami(struct stasis_message *message)
Definition: res_agi.c:1605
static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2985
int AST_OPTIONAL_API_NAME() ast_agi_unregister(agi_command *cmd)
Unregisters an AGI command.
Definition: res_agi.c:4034
static int eagi_exec(struct ast_channel *chan, const char *data)
Definition: res_agi.c:4777
#define ASYNC_AGI_BREAK
Definition: res_agi.c:1570
static struct ast_manager_event_blob * agi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: res_agi.c:1581
static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
Definition: res_agi.c:2213
static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, const char *const argv[])
Definition: res_agi.c:3593
static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2865
static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2616
static int write_htmldump(const char *filename)
Definition: res_agi.c:4623
static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3667
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:2360
static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2547
static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
Definition: res_agi.c:1740
static struct ast_manager_event_blob * agi_async_exec_to_ami(struct stasis_message *message)
Definition: res_agi.c:1615
static int agi_exec_full(struct ast_channel *chan, const char *data, int enhanced, int dead)
Definition: res_agi.c:4699
#define MAX_AGI_CONNECT
Definition: res_agi.c:1565
static struct ast_threadstorage agi_buf
Definition: res_agi.c:1643
static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3536
static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3636
static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
Definition: res_agi.c:3739
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:4323
static char * deadapp
Definition: res_agi.c:1558
static char * handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: res_agi.c:4675
static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2644
static int add_to_agi(struct ast_channel *chan)
Definition: res_agi.c:1773
static int agi_exec(struct ast_channel *chan, const char *data)
Definition: res_agi.c:4769
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:1718
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:2781
int AST_OPTIONAL_API_NAME() ast_agi_register(struct ast_module *mod, agi_command *cmd)
Registers an AGI command.
Definition: res_agi.c:3988
static int agidebug
Definition: res_agi.c:1560
static char * app
Definition: res_agi.c:1554
static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3264
static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3599
static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3036
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:1869
static struct ast_manager_event_blob * agi_async_start_to_ami(struct stasis_message *message)
Definition: res_agi.c:1610
#define AGI_BUF_SIZE
static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3492
static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3314
static struct agi_command commands[]
AGI commands list.
Definition: res_agi.c:3911
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:2850
#define AGI_BUF_INITSIZE
Definition: res_agi.c:1644
#define AGI_NANDFS_RETRY
Definition: res_agi.c:1550
static char * handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: res_agi.c:3564
static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3758
static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2660
static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3441
static int handle_connection(const char *agiurl, const struct ast_sockaddr addr, const int netsockfd)
Definition: res_agi.c:2172
static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3360
agi_result
Definition: res_agi.c:1572
@ AGI_RESULT_HANGUP
Definition: res_agi.c:1578
@ AGI_RESULT_SUCCESS
Definition: res_agi.c:1574
@ AGI_RESULT_FAILURE
Definition: res_agi.c:1573
@ AGI_RESULT_SUCCESS_ASYNC
Definition: res_agi.c:1576
@ AGI_RESULT_SUCCESS_FAST
Definition: res_agi.c:1575
@ AGI_RESULT_NOTFOUND
Definition: res_agi.c:1577
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:4221
static int load_module(void)
Definition: res_agi.c:4890
static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2722
static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char *argv[], int *efd)
Definition: res_agi.c:1947
static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3654
static struct agi_commands agi_commands
#define SRV_PREFIX
Definition: res_agi.c:1552
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:1817
#define AGI_BUF_LEN
Definition: res_agi.c:1551
#define AGI_PORT
Definition: res_agi.c:1567
static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3064
static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2529
static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3418
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:4872
static char * help_workhorse(int fd, const char *const match[])
Definition: res_agi.c:3962
static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2560
static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2579
static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
Definition: res_agi.c:4232
static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2936
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:1646
static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2921
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:4074
static const struct ast_datastore_info agi_commands_datastore_info
Definition: res_agi.c:1704
static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3721
static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:3381
static void free_agi_cmd(struct agi_cmd *cmd)
Definition: res_agi.c:1682
static int deadagi_exec(struct ast_channel *chan, const char *data)
Definition: res_agi.c:4819
static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2881
static void write_html_escaped(FILE *htmlfile, char *str)
Convert string to use HTML escaped characters.
Definition: res_agi.c:4595
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:2199
#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:2446
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:2167
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:2216
#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
char * cmd_buffer
Definition: res_agi.c:1677
char * cmd_id
Definition: res_agi.c:1678
struct agi_cmd::@425 entry
struct agi_command::@181 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::@216 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.
union ast_frame::@228 data
struct ast_frame_subclass subclass
enum ast_frame_type frametype
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:327
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:941
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:1771
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:1073
#define ast_clear_flag(p, flag)
Definition: utils.h:77
long int ast_random(void)
Definition: utils.c:2312
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:1039
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:666
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:2356
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:2169
char * ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module)
Generate synopsis documentation from XML.
Definition: xmldoc.c:2333
char * ast_xmldoc_build_since(const char *type, const char *name, const char *module)
Parse the <since> node content.
Definition: xmldoc.c:1787
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:1702
char * ast_xmldoc_printable(const char *bwinput, int withcolors)
Colorize and put delimiters (instead of tags) to the xmldoc output.
Definition: xmldoc.c:241