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