Asterisk - The Open Source Telephony Project GIT-master-f3e88d3
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)
2196{
2197 char tmp[256];
2198 int pid, toast[2], fromast[2], audio[2], res;
2199 struct stat st;
2200
2201 if (!strncasecmp(script, "agi://", 6)) {
2202 return (efd == NULL) ? launch_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
2203 }
2204 if (!strncasecmp(script, "hagi://", 7)) {
2205 return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
2206 }
2207 if (!strncasecmp(script, "agi:async", sizeof("agi:async") - 1)) {
2208 return launch_asyncagi(chan, argc, argv, efd);
2209 }
2210
2211 if (script[0] != '/') {
2212 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
2213 script = tmp;
2214 }
2215
2216 /* Before even trying let's see if the file actually exists */
2217 if (stat(script, &st)) {
2218 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
2219 return AGI_RESULT_NOTFOUND;
2220 }
2221
2222 if (pipe(toast)) {
2223 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
2224 return AGI_RESULT_FAILURE;
2225 }
2226 if (pipe(fromast)) {
2227 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
2228 close(toast[0]);
2229 close(toast[1]);
2230 return AGI_RESULT_FAILURE;
2231 }
2232 if (efd) {
2233 if (pipe(audio)) {
2234 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
2235 close(fromast[0]);
2236 close(fromast[1]);
2237 close(toast[0]);
2238 close(toast[1]);
2239 return AGI_RESULT_FAILURE;
2240 }
2241
2242 res = ast_fd_set_flags(audio[1], O_NONBLOCK);
2243 if (res < 0) {
2244 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
2245 close(fromast[0]);
2246 close(fromast[1]);
2247 close(toast[0]);
2248 close(toast[1]);
2249 close(audio[0]);
2250 close(audio[1]);
2251 return AGI_RESULT_FAILURE;
2252 }
2253 }
2254
2255 if ((pid = ast_safe_fork(1)) < 0) {
2256 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
2257 return AGI_RESULT_FAILURE;
2258 }
2259 if (!pid) {
2260 /* Pass paths to AGI via environmental variables */
2261 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
2262 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
2263 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
2264 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
2265 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
2266 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
2267 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
2268 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
2269 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
2270 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
2271 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
2272
2273 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
2275
2276 /* Redirect stdin and out, provide enhanced audio channel if desired */
2277 dup2(fromast[0], STDIN_FILENO);
2278 dup2(toast[1], STDOUT_FILENO);
2279 if (efd)
2280 dup2(audio[0], STDERR_FILENO + 1);
2281 else
2282 close(STDERR_FILENO + 1);
2283
2284 /* Close everything but stdin/out/error */
2285 ast_close_fds_above_n(STDERR_FILENO + 1);
2286
2287 /* Execute script */
2288 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
2289 execv(script, argv);
2290 /* Can't use ast_log since FD's are closed */
2291 ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
2292 /* Special case to set status of AGI to failure */
2293 fprintf(stdout, "failure\n");
2294 fflush(stdout);
2295 _exit(1);
2296 }
2297 ast_verb(3, "Launched AGI Script %s\n", script);
2298 fds[0] = toast[0];
2299 fds[1] = fromast[1];
2300 if (efd)
2301 *efd = audio[1];
2302 /* close what we're not using in the parent */
2303 close(toast[1]);
2304 close(fromast[0]);
2305
2306 if (efd)
2307 close(audio[0]);
2308
2309 *opid = pid;
2310 return AGI_RESULT_SUCCESS;
2311}
2312
2313static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
2314{
2315 int count;
2316
2317 /* Print initial environment, with agi_request always being the first
2318 thing */
2319 ast_agi_send(fd, chan, "agi_request: %s\n", request);
2320 ast_agi_send(fd, chan, "agi_channel: %s\n", ast_channel_name(chan));
2321 ast_agi_send(fd, chan, "agi_language: %s\n", ast_channel_language(chan));
2322 ast_agi_send(fd, chan, "agi_type: %s\n", ast_channel_tech(chan)->type);
2323 ast_agi_send(fd, chan, "agi_uniqueid: %s\n", ast_channel_uniqueid(chan));
2324 ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version());
2325
2326 /* ANI/DNIS */
2327 ast_agi_send(fd, chan, "agi_callerid: %s\n",
2328 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "unknown"));
2329 ast_agi_send(fd, chan, "agi_calleridname: %s\n",
2330 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "unknown"));
2331 ast_agi_send(fd, chan, "agi_callingpres: %d\n",
2333 ast_agi_send(fd, chan, "agi_callingani2: %d\n", ast_channel_caller(chan)->ani2);
2334 ast_agi_send(fd, chan, "agi_callington: %d\n", ast_channel_caller(chan)->id.number.plan);
2335 ast_agi_send(fd, chan, "agi_callingtns: %d\n", ast_channel_dialed(chan)->transit_network_select);
2336 ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(ast_channel_dialed(chan)->number.str, "unknown"));
2337 ast_agi_send(fd, chan, "agi_rdnis: %s\n",
2338 S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "unknown"));
2339
2340 /* Context information */
2341 ast_agi_send(fd, chan, "agi_context: %s\n", ast_channel_context(chan));
2342 ast_agi_send(fd, chan, "agi_extension: %s\n", ast_channel_exten(chan));
2343 ast_agi_send(fd, chan, "agi_priority: %d\n", ast_channel_priority(chan));
2344 ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
2345
2346 /* User information */
2347 ast_agi_send(fd, chan, "agi_accountcode: %s\n", ast_channel_accountcode(chan) ? ast_channel_accountcode(chan) : "");
2348 ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self());
2349
2350 /* Send any parameters to the fastagi server that have been passed via the agi application */
2351 /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
2352 for(count = 1; count < argc; count++)
2353 ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]);
2354
2355 /* End with empty return */
2356 ast_agi_send(fd, chan, "\n");
2357}
2358
2359static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2360{
2361 int res = 0;
2362
2363 /* Answer the channel */
2364 if (ast_channel_state(chan) != AST_STATE_UP)
2365 res = ast_answer(chan);
2366
2367 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2368 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2369}
2370
2371static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2372{
2373 ast_agi_send(agi->fd, chan, "200 result=0\n");
2374 return ASYNC_AGI_BREAK;
2375}
2376
2377static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2378{
2379 int res, to;
2380
2381 if (argc != 4)
2382 return RESULT_SHOWUSAGE;
2383 if (sscanf(argv[3], "%30d", &to) != 1)
2384 return RESULT_SHOWUSAGE;
2385 res = ast_waitfordigit_full(chan, to, NULL, agi->audio, agi->ctrl);
2386 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2387 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2388}
2389
2390static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2391{
2392 int res;
2393
2394 if (argc != 3)
2395 return RESULT_SHOWUSAGE;
2396
2397 /* At the moment, the parser (perhaps broken) returns with
2398 the last argument PLUS the newline at the end of the input
2399 buffer. This probably needs to be fixed, but I wont do that
2400 because other stuff may break as a result. The right way
2401 would probably be to strip off the trailing newline before
2402 parsing, then here, add a newline at the end of the string
2403 before sending it to ast_sendtext --DUDE */
2404 res = ast_sendtext(chan, argv[2]);
2405 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2406 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2407}
2408
2409static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2410{
2411 int res;
2412
2413 if (argc != 3)
2414 return RESULT_SHOWUSAGE;
2415
2416 res = ast_recvchar(chan,atoi(argv[2]));
2417 if (res == 0) {
2418 ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res);
2419 return RESULT_SUCCESS;
2420 }
2421 if (res > 0) {
2422 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2423 return RESULT_SUCCESS;
2424 }
2425 ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res);
2426 return RESULT_FAILURE;
2427}
2428
2429static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2430{
2431 char *buf;
2432
2433 if (argc != 3)
2434 return RESULT_SHOWUSAGE;
2435
2436 buf = ast_recvtext(chan, atoi(argv[2]));
2437 if (buf) {
2438 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf);
2439 ast_free(buf);
2440 } else {
2441 ast_agi_send(agi->fd, chan, "200 result=-1\n");
2442 }
2443 return RESULT_SUCCESS;
2444}
2445
2446static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2447{
2448 int res, x;
2449
2450 if (argc != 3)
2451 return RESULT_SHOWUSAGE;
2452
2453 if (!strncasecmp(argv[2],"on",2)) {
2454 x = 1;
2455 } else {
2456 x = 0;
2457 }
2458 if (!strncasecmp(argv[2],"mate",4)) {
2459 x = 2;
2460 }
2461 if (!strncasecmp(argv[2],"tdd",3)) {
2462 x = 1;
2463 }
2464 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
2465 if (res) {
2466 /* Set channel option failed */
2467 ast_agi_send(agi->fd, chan, "200 result=0\n");
2468 } else {
2469 ast_agi_send(agi->fd, chan, "200 result=1\n");
2470 }
2471 return RESULT_SUCCESS;
2472}
2473
2474static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2475{
2476 int res;
2477
2478 if (argc != 3) {
2479 return RESULT_SHOWUSAGE;
2480 }
2481
2482 res = ast_send_image(chan, argv[2]);
2483 if (!ast_check_hangup(chan)) {
2484 res = 0;
2485 }
2486 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2487 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2488}
2489
2490static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2491{
2492 int res = 0, skipms = 3000;
2493 const char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */
2494 char stopkeybuf[2];
2495 long offsetms = 0;
2496 char offsetbuf[20];
2497
2498 if (argc < 5 || argc > 10) {
2499 return RESULT_SHOWUSAGE;
2500 }
2501
2502 if (!ast_strlen_zero(argv[4])) {
2503 stop = argv[4];
2504 }
2505
2506 if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) {
2507 return RESULT_SHOWUSAGE;
2508 }
2509
2510 if (argc > 6 && !ast_strlen_zero(argv[6])) {
2511 fwd = argv[6];
2512 }
2513
2514 if (argc > 7 && !ast_strlen_zero(argv[7])) {
2515 rev = argv[7];
2516 }
2517
2518 if (argc > 8 && !ast_strlen_zero(argv[8])) {
2519 suspend = argv[8];
2520 }
2521
2522 if (argc > 9 && (sscanf(argv[9], "%30ld", &offsetms) != 1)) {
2523 return RESULT_SHOWUSAGE;
2524 }
2525
2526 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, &offsetms);
2527
2528 /* If we stopped on one of our stop keys, return 0 */
2529 if (res > 0 && stop && strchr(stop, res)) {
2530 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "USERSTOPPED");
2531 snprintf(stopkeybuf, sizeof(stopkeybuf), "%c", res);
2532 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTOPKEY", stopkeybuf);
2533 } else if (res > 0 && res == AST_CONTROL_STREAM_STOP) {
2534 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "REMOTESTOPPED");
2535 res = 0;
2536 } else {
2537 if (res < 0) {
2538 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "ERROR");
2539 } else {
2540 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "SUCCESS");
2541 }
2542 }
2543
2544 snprintf(offsetbuf, sizeof(offsetbuf), "%ld", offsetms);
2545 pbx_builtin_setvar_helper(chan, "CPLAYBACKOFFSET", offsetbuf);
2546
2547 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, offsetms);
2548
2549 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2550}
2551
2552static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2553{
2554 int res;
2555 struct ast_filestream *fs, *vfs;
2556 long sample_offset = 0, max_length;
2557 const char *edigits = "";
2558
2559 if (argc < 4 || argc > 5) {
2560 return RESULT_SHOWUSAGE;
2561 }
2562
2563 if (argv[3]) {
2564 edigits = argv[3];
2565 }
2566
2567 if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1)) {
2568 return RESULT_SHOWUSAGE;
2569 }
2570
2571 if (!(fs = ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
2572 ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
2573 return RESULT_FAILURE;
2574 }
2575
2576 if ((vfs = ast_openvstream(chan, argv[2], ast_channel_language(chan)))) {
2577 ast_debug(1, "Ooh, found a video stream, too\n");
2578 }
2579 ast_verb(3, "<%s> Playing '%s.%s' (escape_digits=%s) (sample_offset %ld) (language '%s')\n",
2581 edigits, sample_offset, S_OR(ast_channel_language(chan), "default"));
2582
2583 ast_seekstream(fs, 0, SEEK_END);
2584 max_length = ast_tellstream(fs);
2585 ast_seekstream(fs, sample_offset, SEEK_SET);
2586 res = ast_applystream(chan, fs);
2587 if (vfs) {
2588 ast_applystream(chan, vfs);
2589 }
2590 ast_playstream(fs);
2591 if (vfs) {
2593 }
2594
2595 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
2596 /* this is to check for if ast_waitstream closed the stream, we probably are at
2597 * the end of the stream, return that amount, else check for the amount */
2598 sample_offset = (ast_channel_stream(chan)) ? ast_tellstream(fs) : max_length;
2599 ast_stopstream(chan);
2600 if (res == 1) {
2601 /* Stop this command, don't print a result line, as there is a new command */
2602 return RESULT_SUCCESS;
2603 }
2604 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
2605 pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", res ? "FAILED" : "SUCCESS");
2606
2607 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2608}
2609
2610/*! \brief get option - really similar to the handle_streamfile, but with a timeout */
2611static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2612{
2613 int res;
2614 struct ast_filestream *fs, *vfs;
2615 long sample_offset = 0, max_length;
2616 int timeout = 0;
2617 const char *edigits = "";
2618
2619 if ( argc < 4 || argc > 5 )
2620 return RESULT_SHOWUSAGE;
2621
2622 if ( argv[3] )
2623 edigits = argv[3];
2624
2625 if ( argc == 5 )
2626 timeout = atoi(argv[4]);
2627 else if (ast_channel_pbx(chan)->dtimeoutms) {
2628 /* by default dtimeout is set to 5sec */
2629 timeout = ast_channel_pbx(chan)->dtimeoutms; /* in msec */
2630 }
2631
2632 if (!(fs = ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
2633 ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
2634 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
2635 return RESULT_FAILURE;
2636 }
2637
2638 if ((vfs = ast_openvstream(chan, argv[2], ast_channel_language(chan))))
2639 ast_debug(1, "Ooh, found a video stream, too\n");
2640
2641 ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
2642
2643 ast_seekstream(fs, 0, SEEK_END);
2644 max_length = ast_tellstream(fs);
2645 ast_seekstream(fs, sample_offset, SEEK_SET);
2646 res = ast_applystream(chan, fs);
2647 if (vfs)
2648 ast_applystream(chan, vfs);
2649 ast_playstream(fs);
2650 if (vfs)
2652
2653 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
2654 /* this is to check for if ast_waitstream closed the stream, we probably are at
2655 * the end of the stream, return that amount, else check for the amount */
2656 sample_offset = (ast_channel_stream(chan))?ast_tellstream(fs):max_length;
2657 ast_stopstream(chan);
2658 if (res == 1) {
2659 /* Stop this command, don't print a result line, as there is a new command */
2660 return RESULT_SUCCESS;
2661 }
2662
2663 /* If the user didnt press a key, wait for digitTimeout*/
2664 if (res == 0 ) {
2665 res = ast_waitfordigit_full(chan, timeout, NULL, agi->audio, agi->ctrl);
2666 /* Make sure the new result is in the escape digits of the GET OPTION */
2667 if ( !strchr(edigits,res) )
2668 res=0;
2669 }
2670
2671 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
2672 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2673}
2674
2675
2676
2677
2678/*! \brief Say number in various language syntaxes */
2679/* While waiting, we're sending a NULL. */
2680static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2681{
2682 int res, num;
2683
2684 if (argc < 4 || argc > 5)
2685 return RESULT_SHOWUSAGE;
2686 if (sscanf(argv[2], "%30d", &num) != 1)
2687 return RESULT_SHOWUSAGE;
2688 res = ast_say_number_full(chan, num, argv[3], ast_channel_language(chan), argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
2689 if (res == 1)
2690 return RESULT_SUCCESS;
2691 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2692 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2693}
2694
2695static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2696{
2697 int res, num;
2698
2699 if (argc != 4)
2700 return RESULT_SHOWUSAGE;
2701 if (sscanf(argv[2], "%30d", &num) != 1)
2702 return RESULT_SHOWUSAGE;
2703
2704 res = ast_say_digit_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->audio, agi->ctrl);
2705 if (res == 1) /* New command */
2706 return RESULT_SUCCESS;
2707 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2708 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2709}
2710
2711static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2712{
2713 int res;
2714 int sensitivity = AST_SAY_CASE_NONE;
2715
2716 if (argc < 4 || argc > 5) {
2717 return RESULT_SHOWUSAGE;
2718 }
2719
2720 if (argc > 4) {
2721 switch (argv[4][0]) {
2722 case 'a':
2723 case 'A':
2724 sensitivity = AST_SAY_CASE_ALL;
2725 break;
2726 case 'l':
2727 case 'L':
2728 sensitivity = AST_SAY_CASE_LOWER;
2729 break;
2730 case 'n':
2731 case 'N':
2732 sensitivity = AST_SAY_CASE_NONE;
2733 break;
2734 case 'u':
2735 case 'U':
2736 sensitivity = AST_SAY_CASE_UPPER;
2737 break;
2738 case '\0':
2739 break;
2740 default:
2741 return RESULT_SHOWUSAGE;
2742 }
2743 }
2744 res = ast_say_character_str_full(chan, argv[2], argv[3], ast_channel_language(chan), sensitivity, agi->audio, agi->ctrl);
2745 if (res == 1) /* New command */
2746 return RESULT_SUCCESS;
2747 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2748 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2749}
2750
2751static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2752{
2753 int res, num;
2754
2755 if (argc != 4)
2756 return RESULT_SHOWUSAGE;
2757 if (sscanf(argv[2], "%30d", &num) != 1)
2758 return RESULT_SHOWUSAGE;
2759 res = ast_say_date(chan, num, argv[3], ast_channel_language(chan));
2760 if (res == 1)
2761 return RESULT_SUCCESS;
2762 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2763 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2764}
2765
2766static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2767{
2768 int res, num;
2769
2770 if (argc != 4)
2771 return RESULT_SHOWUSAGE;
2772 if (sscanf(argv[2], "%30d", &num) != 1)
2773 return RESULT_SHOWUSAGE;
2774 res = ast_say_time(chan, num, argv[3], ast_channel_language(chan));
2775 if (res == 1)
2776 return RESULT_SUCCESS;
2777 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2778 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2779}
2780
2781static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2782{
2783 int res = 0;
2784 time_t unixtime;
2785 const char *format, *zone = NULL;
2786
2787 if (argc < 4)
2788 return RESULT_SHOWUSAGE;
2789
2790 if (argc > 4) {
2791 format = argv[4];
2792 } else {
2793 /* XXX this doesn't belong here, but in the 'say' module */
2794 if (!strcasecmp(ast_channel_language(chan), "de")) {
2795 format = "A dBY HMS";
2796 } else {
2797 format = "ABdY 'digits/at' IMp";
2798 }
2799 }
2800
2801 if (argc > 5 && !ast_strlen_zero(argv[5]))
2802 zone = argv[5];
2803
2804 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
2805 return RESULT_SHOWUSAGE;
2806
2807 res = ast_say_date_with_format(chan, unixtime, argv[3], ast_channel_language(chan), format, zone);
2808 if (res == 1)
2809 return RESULT_SUCCESS;
2810
2811 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2812 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2813}
2814
2815static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2816{
2817 int res;
2818
2819 if (argc != 4)
2820 return RESULT_SHOWUSAGE;
2821
2822 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->audio, agi->ctrl);
2823 if (res == 1) /* New command */
2824 return RESULT_SUCCESS;
2825 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2826 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2827}
2828
2829static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2830{
2831 int res, max, timeout;
2832 char data[1024];
2833
2834 if (argc < 3)
2835 return RESULT_SHOWUSAGE;
2836 if (argc >= 4)
2837 timeout = atoi(argv[3]);
2838 else
2839 timeout = 0;
2840 if (argc >= 5)
2841 max = atoi(argv[4]);
2842 else
2843 max = 1024;
2844 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
2845 if (res == 2) /* New command */
2846 return RESULT_SUCCESS;
2847 else if (res == 1)
2848 ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
2849 else if (res < 0 )
2850 ast_agi_send(agi->fd, chan, "200 result=-1\n");
2851 else
2852 ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
2853 return RESULT_SUCCESS;
2854}
2855
2856static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2857{
2858
2859 if (argc != 3)
2860 return RESULT_SHOWUSAGE;
2861 ast_channel_context_set(chan, argv[2]);
2862 ast_agi_send(agi->fd, chan, "200 result=0\n");
2863 return RESULT_SUCCESS;
2864}
2865
2866static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2867{
2868 if (argc != 3)
2869 return RESULT_SHOWUSAGE;
2870 ast_channel_exten_set(chan, argv[2]);
2871 ast_agi_send(agi->fd, chan, "200 result=0\n");
2872 return RESULT_SUCCESS;
2873}
2874
2875static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2876{
2877 int pri;
2878
2879 if (argc != 3)
2880 return RESULT_SHOWUSAGE;
2881
2882 if (sscanf(argv[2], "%30d", &pri) != 1) {
2883 pri = ast_findlabel_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), argv[2],
2884 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
2885 if (pri < 1)
2886 return RESULT_SHOWUSAGE;
2887 }
2888
2889 ast_explicit_goto(chan, NULL, NULL, pri);
2890 ast_agi_send(agi->fd, chan, "200 result=0\n");
2891 return RESULT_SUCCESS;
2892}
2893
2894static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2895{
2896 struct ast_filestream *fs;
2897 struct ast_frame *f;
2898 struct timeval start;
2899 long sample_offset = 0;
2900 int res = 0;
2901 int ms;
2902
2903 struct ast_dsp *sildet=NULL; /* silence detector dsp */
2904 int totalsilence = 0;
2905 int dspsilence = 0;
2906 int silence = 0; /* amount of silence to allow */
2907 int gotsilence = 0; /* did we timeout for silence? */
2908 char *silencestr = NULL;
2909 RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup);
2910 struct ast_silence_generator *silgen = NULL;
2911
2912 /* XXX EAGI FIXME XXX */
2913
2914 if (argc < 6)
2915 return RESULT_SHOWUSAGE;
2916 if (sscanf(argv[5], "%30d", &ms) != 1)
2917 return RESULT_SHOWUSAGE;
2918
2919 if (argc > 6)
2920 silencestr = strchr(argv[6],'s');
2921 if ((argc > 7) && (!silencestr))
2922 silencestr = strchr(argv[7],'s');
2923 if ((argc > 8) && (!silencestr))
2924 silencestr = strchr(argv[8],'s');
2925
2926 if (silencestr) {
2927 if (strlen(silencestr) > 2) {
2928 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
2929 silencestr++;
2930 silencestr++;
2931 if (silencestr)
2932 silence = atoi(silencestr);
2933 if (silence > 0)
2934 silence *= 1000;
2935 }
2936 }
2937 }
2938
2939 if (silence > 0) {
2940 rfmt = ao2_bump(ast_channel_readformat(chan));
2942 if (res < 0) {
2943 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
2944 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2945 return RESULT_FAILURE;
2946 }
2947 sildet = ast_dsp_new();
2948 if (!sildet) {
2949 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
2950 ast_agi_send(agi->fd, chan, "200 result=-1\n");
2951 return RESULT_FAILURE;
2952 }
2954 }
2955
2956 /* backward compatibility, if no offset given, arg[6] would have been
2957 * caught below and taken to be a beep, else if it is a digit then it is a
2958 * offset.
2959 *
2960 * In other words, if the argument does not look like the offset_samples
2961 * argument (a number) and it doesn't look like the silence argument (starts
2962 * with "s=") then it must be the beep argument. The beep argument has no
2963 * required value, the presence of anything in the argument slot we are
2964 * inspecting is an indication that the user wants a beep played.
2965 */
2966 if ((argc > 6 && sscanf(argv[6], "%30ld", &sample_offset) != 1 && !ast_begins_with(argv[6], "s="))
2967 || (argc > 7 && !ast_begins_with(argv[7], "s="))) {
2968 res = ast_streamfile(chan, "beep", ast_channel_language(chan));
2969 }
2970
2971 if (!res)
2972 res = ast_waitstream(chan, argv[4]);
2973 if (res) {
2974 ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
2975 } else {
2976 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
2977 if (!fs) {
2978 res = -1;
2979 ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
2980 if (sildet)
2981 ast_dsp_free(sildet);
2982 return RESULT_FAILURE;
2983 }
2984
2985 /* Request a video update */
2987
2988 ast_channel_stream_set(chan, fs);
2989 ast_applystream(chan,fs);
2990 /* really should have checks */
2991 ast_seekstream(fs, sample_offset, SEEK_SET);
2992 ast_truncstream(fs);
2993
2996 }
2997
2998 start = ast_tvnow();
2999 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
3000 res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start));
3001 if (res < 0) {
3002 ast_closestream(fs);
3003 ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
3004 if (sildet)
3005 ast_dsp_free(sildet);
3006 if (silgen)
3008 return RESULT_FAILURE;
3009 }
3010 f = ast_read(chan);
3011 if (!f) {
3012 ast_closestream(fs);
3013 ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
3014 if (sildet)
3015 ast_dsp_free(sildet);
3016 if (silgen)
3018 return RESULT_FAILURE;
3019 }
3020 switch(f->frametype) {
3021 case AST_FRAME_DTMF:
3022 if (strchr(argv[4], f->subclass.integer)) {
3023 /* This is an interrupting character, so rewind to chop off any small
3024 amount of DTMF that may have been recorded
3025 */
3026 ast_stream_rewind(fs, 200);
3027 ast_truncstream(fs);
3028 sample_offset = ast_tellstream(fs);
3029 ast_closestream(fs);
3030 ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset);
3031 ast_frfree(f);
3032 if (sildet)
3033 ast_dsp_free(sildet);
3034 if (silgen)
3036 return RESULT_SUCCESS;
3037 }
3038 break;
3039 case AST_FRAME_VOICE:
3040 ast_writestream(fs, f);
3041 /* this is a safe place to check progress since we know that fs
3042 * is valid after a write, and it will then have our current
3043 * location */
3044 sample_offset = ast_tellstream(fs);
3045 if (silence > 0) {
3046 dspsilence = 0;
3047 ast_dsp_silence(sildet, f, &dspsilence);
3048 if (dspsilence) {
3049 totalsilence = dspsilence;
3050 } else {
3051 totalsilence = 0;
3052 }
3053 if (totalsilence > silence) {
3054 /* Ended happily with silence */
3055 gotsilence = 1;
3056 break;
3057 }
3058 }
3059 break;
3060 case AST_FRAME_VIDEO:
3061 ast_writestream(fs, f);
3062 default:
3063 /* Ignore all other frames */
3064 break;
3065 }
3066 ast_frfree(f);
3067 if (gotsilence)
3068 break;
3069 }
3070
3071 if (gotsilence) {
3072 ast_stream_rewind(fs, silence-1000);
3073 ast_truncstream(fs);
3074 sample_offset = ast_tellstream(fs);
3075 }
3076 ast_closestream(fs);
3077 ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
3078 }
3079
3080 if (silence > 0) {
3081 res = ast_set_read_format(chan, rfmt);
3082 if (res)
3083 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(chan));
3084 ast_dsp_free(sildet);
3085 }
3086
3087 if (silgen) {
3089 }
3090
3091 return RESULT_SUCCESS;
3092}
3093
3094static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3095{
3096 double timeout;
3097 struct timeval whentohangup = { 0, 0 };
3098
3099 if (argc != 3)
3100 return RESULT_SHOWUSAGE;
3101 if (sscanf(argv[2], "%30lf", &timeout) != 1)
3102 return RESULT_SHOWUSAGE;
3103 if (timeout < 0)
3104 timeout = 0;
3105 if (timeout) {
3106 whentohangup.tv_sec = timeout;
3107 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
3108 }
3109 ast_channel_lock(chan);
3110 ast_channel_setwhentohangup_tv(chan, whentohangup);
3111 ast_channel_unlock(chan);
3112 ast_agi_send(agi->fd, chan, "200 result=0\n");
3113 return RESULT_SUCCESS;
3114}
3115
3116static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3117{
3118 struct ast_channel *c;
3119
3120 if (argc == 1) {
3121 /* no argument: hangup the current channel */
3122 ast_set_hangupsource(chan, "dialplan/agi", 0);
3124 ast_agi_send(agi->fd, chan, "200 result=1\n");
3125 return RESULT_SUCCESS;
3126 } else if (argc == 2) {
3127 /* one argument: look for info on the specified channel */
3128 if ((c = ast_channel_get_by_name(argv[1]))) {
3129 /* we have a matching channel */
3130 ast_set_hangupsource(c, "dialplan/agi", 0);
3133 ast_agi_send(agi->fd, chan, "200 result=1\n");
3134 return RESULT_SUCCESS;
3135 }
3136 /* if we get this far no channel name matched the argument given */
3137 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3138 return RESULT_SUCCESS;
3139 } else {
3140 return RESULT_SHOWUSAGE;
3141 }
3142}
3143
3144static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3145{
3146 int res, workaround;
3147 struct ast_app *app_to_exec;
3148 const char *agi_exec_full_str;
3149 int agi_exec_full;
3150 struct ast_str *data_with_var = NULL;
3151
3152 if (argc < 2)
3153 return RESULT_SHOWUSAGE;
3154
3155 ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
3156
3157 if ((app_to_exec = pbx_findapp(argv[1]))) {
3158 ast_channel_lock(chan);
3159 if (!(workaround = ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS))) {
3161 }
3162 agi_exec_full_str = pbx_builtin_getvar_helper(chan, "AGIEXECFULL");
3163 agi_exec_full = ast_true(agi_exec_full_str);
3164 ast_channel_unlock(chan);
3165
3166 if (agi_exec_full) {
3167 if ((data_with_var = ast_str_create(16))) {
3168 ast_str_substitute_variables(&data_with_var, 0, chan, argv[2]);
3169 res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : ast_str_buffer(data_with_var));
3170 ast_free(data_with_var);
3171 } else {
3172 res = -2;
3173 }
3174 } else {
3175 res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
3176 }
3177 if (!workaround) {
3179 }
3180 } else {
3181 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
3182 res = -2;
3183 }
3184 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
3185
3186 /* Even though this is wrong, users are depending upon this result. */
3187 return res;
3188}
3189
3190static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3191{
3192 char tmp[256]="";
3193 char *l = NULL, *n = NULL;
3194
3195 if (argv[2]) {
3196 ast_copy_string(tmp, argv[2], sizeof(tmp));
3197 ast_callerid_parse(tmp, &n, &l);
3198 if (l)
3200 else
3201 l = "";
3202 if (!n)
3203 n = "";
3204 ast_set_callerid(chan, l, n, NULL);
3205 }
3206
3207 ast_agi_send(agi->fd, chan, "200 result=1\n");
3208 return RESULT_SUCCESS;
3209}
3210
3211static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3212{
3213 if (argc == 2) {
3214 /* no argument: supply info on the current channel */
3215 ast_agi_send(agi->fd, chan, "200 result=%u\n", ast_channel_state(chan));
3216 return RESULT_SUCCESS;
3217 } else if (argc == 3) {
3218 struct ast_channel_snapshot *snapshot;
3219
3220 /* one argument: look for info on the specified channel */
3221 snapshot = ast_channel_snapshot_get_latest_by_name(argv[2]);
3222 if (snapshot) {
3223 ast_agi_send(agi->fd, chan, "200 result=%u\n", snapshot->state);
3224 ao2_ref(snapshot, -1);
3225 return RESULT_SUCCESS;
3226 }
3227 /* if we get this far no channel name matched the argument given */
3228 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3229 return RESULT_SUCCESS;
3230 } else {
3231 return RESULT_SHOWUSAGE;
3232 }
3233}
3234
3235static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3236{
3237 if (argc != 4) {
3238 return RESULT_SHOWUSAGE;
3239 }
3240
3241 if (argv[3])
3242 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
3243
3244 ast_agi_send(agi->fd, chan, "200 result=1\n");
3245 return RESULT_SUCCESS;
3246}
3247
3248static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3249{
3250 char *ret;
3251 char tempstr[1024] = "";
3252
3253 if (argc != 3)
3254 return RESULT_SHOWUSAGE;
3255
3256 /* check if we want to execute an ast_custom_function */
3257 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
3258 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
3259 } else {
3260 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
3261 }
3262
3263 if (ret)
3264 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
3265 else
3266 ast_agi_send(agi->fd, chan, "200 result=0\n");
3267
3268 return RESULT_SUCCESS;
3269}
3270
3271static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3272{
3273 struct ast_channel *chan2 = NULL;
3274
3275 if (argc != 4 && argc != 5) {
3276 return RESULT_SHOWUSAGE;
3277 }
3278
3279 if (argc == 5) {
3280 chan2 = ast_channel_get_by_name(argv[4]);
3281 } else {
3282 chan2 = ast_channel_ref(chan);
3283 }
3284
3285 if (chan2) {
3286 struct ast_str *str = ast_str_create(16);
3287 if (!str) {
3288 ast_agi_send(agi->fd, chan, "200 result=0\n");
3289 return RESULT_SUCCESS;
3290 }
3291 ast_str_substitute_variables(&str, 0, chan2, argv[3]);
3292 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(str));
3293 ast_free(str);
3294 } else {
3295 ast_agi_send(agi->fd, chan, "200 result=0\n");
3296 }
3297
3298 if (chan2) {
3299 chan2 = ast_channel_unref(chan2);
3300 }
3301
3302 return RESULT_SUCCESS;
3303}
3304
3305static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3306{
3307 int level = 0;
3308
3309 if (argc < 2)
3310 return RESULT_SHOWUSAGE;
3311
3312 if (argv[2])
3313 sscanf(argv[2], "%30d", &level);
3314
3315 ast_verb(level, "%s: %s\n", ast_channel_data(chan), argv[1]);
3316
3317 ast_agi_send(agi->fd, chan, "200 result=1\n");
3318
3319 return RESULT_SUCCESS;
3320}
3321
3322static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3323{
3324 int res;
3325 struct ast_str *buf;
3326
3327 if (argc != 4)
3328 return RESULT_SHOWUSAGE;
3329
3330 if (!(buf = ast_str_create(16))) {
3331 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3332 return RESULT_SUCCESS;
3333 }
3334
3335 do {
3336 res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
3338 if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
3339 break;
3340 }
3341 if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
3342 break;
3343 }
3344 } while (1);
3345
3346 if (res)
3347 ast_agi_send(agi->fd, chan, "200 result=0\n");
3348 else
3349 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
3350
3351 ast_free(buf);
3352 return RESULT_SUCCESS;
3353}
3354
3355static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3356{
3357 int res;
3358
3359 if (argc != 5)
3360 return RESULT_SHOWUSAGE;
3361 res = ast_db_put(argv[2], argv[3], argv[4]);
3362 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
3363 return RESULT_SUCCESS;
3364}
3365
3366static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3367{
3368 int res;
3369
3370 if (argc != 4)
3371 return RESULT_SHOWUSAGE;
3372 res = ast_db_del(argv[2], argv[3]);
3373 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
3374 return RESULT_SUCCESS;
3375}
3376
3377static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3378{
3379 int num_deleted;
3380
3381 if ((argc < 3) || (argc > 4)) {
3382 return RESULT_SHOWUSAGE;
3383 }
3384 if (argc == 4) {
3385 num_deleted = ast_db_deltree(argv[2], argv[3]);
3386 } else {
3387 num_deleted = ast_db_deltree(argv[2], NULL);
3388 }
3389
3390 ast_agi_send(agi->fd, chan, "200 result=%c\n", num_deleted > 0 ? '0' : '1');
3391 return RESULT_SUCCESS;
3392}
3393
3394static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3395{
3396 switch (cmd) {
3397 case CLI_INIT:
3398 e->command = "agi set debug [on|off]";
3399 e->usage =
3400 "Usage: agi set debug [on|off]\n"
3401 " Enables/disables dumping of AGI transactions for\n"
3402 " debugging purposes.\n";
3403 return NULL;
3404
3405 case CLI_GENERATE:
3406 return NULL;
3407 }
3408
3409 if (a->argc != e->args)
3410 return CLI_SHOWUSAGE;
3411
3412 if (strncasecmp(a->argv[3], "off", 3) == 0) {
3413 agidebug = 0;
3414 } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
3415 agidebug = 1;
3416 } else {
3417 return CLI_SHOWUSAGE;
3418 }
3419 ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
3420 return CLI_SUCCESS;
3421}
3422
3423static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, const char * const argv[])
3424{
3425 ast_agi_send(agi->fd, chan, "200 result=0\n");
3426 return RESULT_SUCCESS;
3427}
3428
3429static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3430{
3431 if (argc < 3) {
3432 return RESULT_SHOWUSAGE;
3433 }
3434 if (!strncasecmp(argv[2], "on", 2))
3435 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
3436 else if (!strncasecmp(argv[2], "off", 3))
3437 ast_moh_stop(chan);
3438 ast_agi_send(agi->fd, chan, "200 result=0\n");
3439 return RESULT_SUCCESS;
3440}
3441
3442static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3443{
3444 struct ast_format_cap *cap;
3445
3446 /* If a structure already exists, return an error */
3447 if (agi->speech) {
3448 ast_agi_send(agi->fd, chan, "200 result=0\n");
3449 return RESULT_SUCCESS;
3450 }
3451
3453 return RESULT_FAILURE;
3454 }
3456 if ((agi->speech = ast_speech_new(argv[2], cap))) {
3457 ast_agi_send(agi->fd, chan, "200 result=1\n");
3458 } else {
3459 ast_agi_send(agi->fd, chan, "200 result=0\n");
3460 }
3461 ao2_ref(cap, -1);
3462
3463 return RESULT_SUCCESS;
3464}
3465
3466static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3467{
3468 /* Check for minimum arguments */
3469 if (argc != 4)
3470 return RESULT_SHOWUSAGE;
3471
3472 /* Check to make sure speech structure exists */
3473 if (!agi->speech) {
3474 ast_agi_send(agi->fd, chan, "200 result=0\n");
3475 return RESULT_SUCCESS;
3476 }
3477
3478 ast_speech_change(agi->speech, argv[2], argv[3]);
3479 ast_agi_send(agi->fd, chan, "200 result=1\n");
3480
3481 return RESULT_SUCCESS;
3482}
3483
3484static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3485{
3486 if (agi->speech) {
3488 agi->speech = NULL;
3489 ast_agi_send(agi->fd, chan, "200 result=1\n");
3490 } else {
3491 ast_agi_send(agi->fd, chan, "200 result=0\n");
3492 }
3493
3494 return RESULT_SUCCESS;
3495}
3496
3497static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3498{
3499 if (argc != 5)
3500 return RESULT_SHOWUSAGE;
3501
3502 if (!agi->speech) {
3503 ast_agi_send(agi->fd, chan, "200 result=0\n");
3504 return RESULT_SUCCESS;
3505 }
3506
3507 if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
3508 ast_agi_send(agi->fd, chan, "200 result=0\n");
3509 else
3510 ast_agi_send(agi->fd, chan, "200 result=1\n");
3511
3512 return RESULT_SUCCESS;
3513}
3514
3515static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3516{
3517 if (argc != 4)
3518 return RESULT_SHOWUSAGE;
3519
3520 if (!agi->speech) {
3521 ast_agi_send(agi->fd, chan, "200 result=0\n");
3522 return RESULT_SUCCESS;
3523 }
3524
3525 if (ast_speech_grammar_unload(agi->speech, argv[3]))
3526 ast_agi_send(agi->fd, chan, "200 result=0\n");
3527 else
3528 ast_agi_send(agi->fd, chan, "200 result=1\n");
3529
3530 return RESULT_SUCCESS;
3531}
3532
3533static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3534{
3535 if (argc != 4)
3536 return RESULT_SHOWUSAGE;
3537
3538 if (!agi->speech) {
3539 ast_agi_send(agi->fd, chan, "200 result=0\n");
3540 return RESULT_SUCCESS;
3541 }
3542
3543 if (ast_speech_grammar_activate(agi->speech, argv[3]))
3544 ast_agi_send(agi->fd, chan, "200 result=0\n");
3545 else
3546 ast_agi_send(agi->fd, chan, "200 result=1\n");
3547
3548 return RESULT_SUCCESS;
3549}
3550
3551static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3552{
3553 if (argc != 4)
3554 return RESULT_SHOWUSAGE;
3555
3556 if (!agi->speech) {
3557 ast_agi_send(agi->fd, chan, "200 result=0\n");
3558 return RESULT_SUCCESS;
3559 }
3560
3561 if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
3562 ast_agi_send(agi->fd, chan, "200 result=0\n");
3563 else
3564 ast_agi_send(agi->fd, chan, "200 result=1\n");
3565
3566 return RESULT_SUCCESS;
3567}
3568
3569static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
3570{
3571 struct ast_filestream *fs = NULL;
3572
3573 if (!(fs = ast_openstream(chan, filename, preflang)))
3574 return -1;
3575
3576 if (offset)
3577 ast_seekstream(fs, offset, SEEK_SET);
3578
3579 if (ast_applystream(chan, fs))
3580 return -1;
3581
3582 if (ast_playstream(fs))
3583 return -1;
3584
3585 return 0;
3586}
3587
3588static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
3589{
3590 struct ast_speech *speech = agi->speech;
3591 const char *prompt;
3592 char dtmf = 0, tmp[4096] = "", *buf = tmp;
3593 int timeout = 0, offset = 0, res = 0, i = 0;
3594 long current_offset = 0;
3595 const char *reason = NULL;
3596 struct ast_frame *fr = NULL;
3597 struct ast_speech_result *result = NULL;
3598 size_t left = sizeof(tmp);
3599 time_t start = 0, current;
3600
3601 if (argc < 4)
3602 return RESULT_SHOWUSAGE;
3603
3604 if (!speech) {
3605 ast_agi_send(agi->fd, chan, "200 result=0\n");
3606 return RESULT_SUCCESS;
3607 }
3608
3609 prompt = argv[2];
3610 timeout = atoi(argv[3]);
3611
3612 /* If offset is specified then convert from text to integer */
3613 if (argc == 5)
3614 offset = atoi(argv[4]);
3615
3616 /* We want frames coming in signed linear */
3618 ast_agi_send(agi->fd, chan, "200 result=0\n");
3619 return RESULT_SUCCESS;
3620 }
3621
3622 /* Setup speech structure */
3623 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
3625 ast_speech_start(speech);
3626 }
3627
3628 /* Start playing prompt */
3629 speech_streamfile(chan, prompt, ast_channel_language(chan), offset);
3630
3631 /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
3632 while (ast_strlen_zero(reason)) {
3633 /* Run scheduled items */
3635
3636 /* See maximum time of waiting */
3637 if ((res = ast_sched_wait(ast_channel_sched(chan))) < 0)
3638 res = 1000;
3639
3640 /* Wait for frame */
3641 if (ast_waitfor(chan, res) > 0) {
3642 if (!(fr = ast_read(chan))) {
3643 reason = "hangup";
3644 break;
3645 }
3646 }
3647
3648 /* Perform timeout check */
3649 if ((timeout > 0) && (start > 0)) {
3650 time(&current);
3651 if ((current - start) >= timeout) {
3652 reason = "timeout";
3653 if (fr)
3654 ast_frfree(fr);
3655 break;
3656 }
3657 }
3658
3659 /* Check the speech structure for any changes */
3660 ast_mutex_lock(&speech->lock);
3661
3662 /* See if we need to quiet the audio stream playback */
3663 if (ast_test_flag(speech, AST_SPEECH_QUIET) && ast_channel_stream(chan)) {
3664 current_offset = ast_tellstream(ast_channel_stream(chan));
3665 ast_stopstream(chan);
3667 }
3668
3669 /* Check each state */
3670 switch (speech->state) {
3672 /* If the stream is done, start timeout calculation */
3673 if ((timeout > 0) && start == 0 && ((!ast_channel_stream(chan)) || (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL))) {
3674 ast_stopstream(chan);
3675 time(&start);
3676 }
3677 /* Write audio frame data into speech engine if possible */
3678 if (fr && fr->frametype == AST_FRAME_VOICE)
3679 ast_speech_write(speech, fr->data.ptr, fr->datalen);
3680 break;
3682 /* Cue waiting sound if not already playing */
3683 if ((!ast_channel_stream(chan)) || (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL)) {
3684 ast_stopstream(chan);
3685 /* If a processing sound exists, or is not none - play it */
3686 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
3688 }
3689 break;
3691 /* Get the results */
3692 speech->results = ast_speech_results_get(speech);
3693 /* Change state to not ready */
3695 reason = "speech";
3696 break;
3697 default:
3698 break;
3699 }
3700 ast_mutex_unlock(&speech->lock);
3701
3702 /* Check frame for DTMF or hangup */
3703 if (fr) {
3704 if (fr->frametype == AST_FRAME_DTMF) {
3705 reason = "dtmf";
3706 dtmf = fr->subclass.integer;
3707 } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_HANGUP) {
3708 reason = "hangup";
3709 }
3710 ast_frfree(fr);
3711 }
3712 }
3713
3714 if (!strcasecmp(reason, "speech")) {
3715 /* Build string containing speech results */
3716 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
3717 /* Build result string */
3718 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);
3719 /* Increment result count */
3720 i++;
3721 }
3722 /* Print out */
3723 ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
3724 } else if (!strcasecmp(reason, "dtmf")) {
3725 ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
3726 } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
3727 ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
3728 } else {
3729 ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
3730 }
3731
3732 return RESULT_SUCCESS;
3733}
3734
3735/*!
3736 * \brief AGI commands list
3737 */
3738static struct agi_command commands[] = {
3739 { { "answer", NULL }, handle_answer, NULL, NULL, 0 },
3740 { { "asyncagi", "break", NULL }, handle_asyncagi_break, NULL, NULL, 1 },
3741 { { "channel", "status", NULL }, handle_channelstatus, NULL, NULL, 0 },
3742 { { "database", "del", NULL }, handle_dbdel, NULL, NULL, 1 },
3743 { { "database", "deltree", NULL }, handle_dbdeltree, NULL, NULL, 1 },
3744 { { "database", "get", NULL }, handle_dbget, NULL, NULL, 1 },
3745 { { "database", "put", NULL }, handle_dbput, NULL, NULL, 1 },
3746 { { "exec", NULL }, handle_exec, NULL, NULL, 1 },
3747 { { "get", "data", NULL }, handle_getdata, NULL, NULL, 0 },
3748 { { "get", "full", "variable", NULL }, handle_getvariablefull, NULL, NULL, 1 },
3749 { { "get", "option", NULL }, handle_getoption, NULL, NULL, 0 },
3750 { { "get", "variable", NULL }, handle_getvariable, NULL, NULL, 1 },
3751 { { "hangup", NULL }, handle_hangup, NULL, NULL, 0 },
3752 { { "noop", NULL }, handle_noop, NULL, NULL, 1 },
3753 { { "receive", "char", NULL }, handle_recvchar, NULL, NULL, 0 },
3754 { { "receive", "text", NULL }, handle_recvtext, NULL, NULL, 0 },
3755 { { "record", "file", NULL }, handle_recordfile, NULL, NULL, 0 },
3756 { { "say", "alpha", NULL }, handle_sayalpha, NULL, NULL, 0},
3757 { { "say", "digits", NULL }, handle_saydigits, NULL, NULL, 0 },
3758 { { "say", "number", NULL }, handle_saynumber, NULL, NULL, 0 },
3759 { { "say", "phonetic", NULL }, handle_sayphonetic, NULL, NULL, 0},
3760 { { "say", "date", NULL }, handle_saydate, NULL, NULL, 0},
3761 { { "say", "time", NULL }, handle_saytime, NULL, NULL, 0},
3762 { { "say", "datetime", NULL }, handle_saydatetime, NULL, NULL, 0},
3763 { { "send", "image", NULL }, handle_sendimage, NULL, NULL, 0},
3764 { { "send", "text", NULL }, handle_sendtext, NULL, NULL, 0},
3765 { { "set", "autohangup", NULL }, handle_autohangup, NULL, NULL, 0},
3766 { { "set", "callerid", NULL }, handle_setcallerid, NULL, NULL, 0},
3767 { { "set", "context", NULL }, handle_setcontext, NULL, NULL, 0},
3768 { { "set", "extension", NULL }, handle_setextension, NULL, NULL, 0},
3769 { { "set", "music", NULL }, handle_setmusic, NULL, NULL, 0 },
3770 { { "set", "priority", NULL }, handle_setpriority, NULL, NULL, 0 },
3771 { { "set", "variable", NULL }, handle_setvariable, NULL, NULL, 1 },
3772 { { "stream", "file", NULL }, handle_streamfile, NULL, NULL, 0 },
3773 { { "control", "stream", "file", NULL }, handle_controlstreamfile, NULL, NULL, 0 },
3774 { { "tdd", "mode", NULL }, handle_tddmode, NULL, NULL, 0 },
3775 { { "verbose", NULL }, handle_verbose, NULL, NULL, 1 },
3776 { { "wait", "for", "digit", NULL }, handle_waitfordigit, NULL, NULL, 0 },
3777 { { "speech", "create", NULL }, handle_speechcreate, NULL, NULL, 0 },
3778 { { "speech", "set", NULL }, handle_speechset, NULL, NULL, 0 },
3779 { { "speech", "destroy", NULL }, handle_speechdestroy, NULL, NULL, 1 },
3780 { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, NULL, NULL, 0 },
3781 { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, NULL, NULL, 1 },
3782 { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, NULL, NULL, 0 },
3783 { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, NULL, NULL, 0 },
3784 { { "speech", "recognize", NULL }, handle_speechrecognize, NULL, NULL, 0 },
3785};
3786
3788
3789static char *help_workhorse(int fd, const char * const match[])
3790{
3791 char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
3792 struct agi_command *e;
3793
3794 if (match)
3795 ast_join(matchstr, sizeof(matchstr), match);
3796
3797 ast_cli(fd, "%5.5s %30.30s %s\n","Dead","Command","Description");
3800 if (!e->cmda[0])
3801 break;
3802 /* Hide commands that start with '_' */
3803 if ((e->cmda[0])[0] == '_')
3804 continue;
3805 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
3806 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
3807 continue;
3808 ast_cli(fd, "%5.5s %30.30s %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
3809 }
3811
3812 return CLI_SUCCESS;
3813}
3814
3816{
3817 char fullcmd[MAX_CMD_LEN];
3818
3819 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
3820
3821 if (!find_command(cmd->cmda, 1)) {
3822 *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
3823 if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
3824#ifdef AST_XML_DOCS
3825 *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd, NULL);
3826 *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd, NULL);
3827 *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd, NULL);
3828 *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd, NULL);
3829 *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
3830#endif
3831#ifndef HAVE_NULLSAFE_PRINTF
3832 if (!cmd->summary) {
3833 *((char **) &cmd->summary) = ast_strdup("");
3834 }
3835 if (!cmd->usage) {
3836 *((char **) &cmd->usage) = ast_strdup("");
3837 }
3838 if (!cmd->syntax) {
3839 *((char **) &cmd->syntax) = ast_strdup("");
3840 }
3841 if (!cmd->seealso) {
3842 *((char **) &cmd->seealso) = ast_strdup("");
3843 }
3844#endif
3845 }
3846
3847 cmd->mod = mod;
3851 ast_verb(5, "AGI Command '%s' registered\n",fullcmd);
3852 return 1;
3853 } else {
3854 ast_log(LOG_WARNING, "Command already registered!\n");
3855 return 0;
3856 }
3857}
3858
3860{
3861 struct agi_command *e;
3862 int unregistered = 0;
3863 char fullcmd[MAX_CMD_LEN];
3864
3865 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
3866
3869 if (cmd == e) {
3871#ifdef AST_XML_DOCS
3872 if (e->docsrc == AST_XML_DOC) {
3873 ast_free((char *) e->summary);
3874 ast_free((char *) e->usage);
3875 ast_free((char *) e->syntax);
3876 ast_free((char *) e->seealso);
3877 *((char **) &e->summary) = NULL;
3878 *((char **) &e->usage) = NULL;
3879 *((char **) &e->syntax) = NULL;
3880 *((char **) &e->seealso) = NULL;
3881 }
3882#endif
3883 unregistered=1;
3884 break;
3885 }
3886 }
3889 if (unregistered) {
3890 ast_verb(5, "AGI Command '%s' unregistered\n",fullcmd);
3891 }
3892 return unregistered;
3893}
3894
3896{
3897 unsigned int i, x = 0;
3898
3899 for (i = 0; i < len; i++) {
3900 if (ast_agi_register(mod, cmd + i) == 1) {
3901 x++;
3902 continue;
3903 }
3904
3905 /* registration failed, unregister everything
3906 that had been registered up to that point
3907 */
3908 for (; x > 0; x--) {
3909 /* we are intentionally ignoring the
3910 result of ast_agi_unregister() here,
3911 but it should be safe to do so since
3912 we just registered these commands and
3913 the only possible way for unregistration
3914 to fail is if the command is not
3915 registered
3916 */
3917 (void) ast_agi_unregister(cmd + x - 1);
3918 }
3919 return -1;
3920 }
3921
3922 return 0;
3923}
3924
3926{
3927 unsigned int i;
3928 int res = 0;
3929
3930 for (i = 0; i < len; i++) {
3931 /* remember whether any of the unregistration
3932 attempts failed... there is no recourse if
3933 any of them do
3934 */
3935 res |= ast_agi_unregister(cmd + i);
3936 }
3937
3938 return res;
3939}
3940
3941static agi_command *find_command(const char * const cmds[], int exact)
3942{
3943 int y, match;
3944 struct agi_command *e;
3945
3948 if (!e->cmda[0])
3949 break;
3950 /* start optimistic */
3951 match = 1;
3952 for (y = 0; match && cmds[y]; y++) {
3953 /* If there are no more words in the command (and we're looking for
3954 an exact match) or there is a difference between the two words,
3955 then this is not a match */
3956 if (!e->cmda[y] && !exact)
3957 break;
3958 /* don't segfault if the next part of a command doesn't exist */
3959 if (!e->cmda[y]) {
3961 return NULL;
3962 }
3963 if (strcasecmp(e->cmda[y], cmds[y]))
3964 match = 0;
3965 }
3966 /* If more words are needed to complete the command then this is not
3967 a candidate (unless we're looking for a really inexact answer */
3968 if ((exact > -1) && e->cmda[y])
3969 match = 0;
3970 if (match) {
3972 return e;
3973 }
3974 }
3976 return NULL;
3977}
3978
3979static int parse_args(char *s, int *max, const char *argv[])
3980{
3981 int x = 0, quoted = 0, escaped = 0, whitespace = 1;
3982 char *cur;
3983
3984 cur = s;
3985 while(*s) {
3986 switch(*s) {
3987 case '"':
3988 /* If it's escaped, put a literal quote */
3989 if (escaped)
3990 goto normal;
3991 else
3992 quoted = !quoted;
3993 if (quoted && whitespace) {
3994 /* If we're starting a quote, coming off white space start a new word, too */
3995 argv[x++] = cur;
3996 whitespace=0;
3997 }
3998 escaped = 0;
3999 break;
4000 case ' ':
4001 case '\t':
4002 if (!quoted && !escaped) {
4003 /* If we're not quoted, mark this as whitespace, and
4004 end the previous argument */
4005 whitespace = 1;
4006 *(cur++) = '\0';
4007 } else
4008 /* Otherwise, just treat it as anything else */
4009 goto normal;
4010 break;
4011 case '\\':
4012 /* If we're escaped, print a literal, otherwise enable escaping */
4013 if (escaped) {
4014 goto normal;
4015 } else {
4016 escaped=1;
4017 }
4018 break;
4019 default:
4020normal:
4021 if (whitespace) {
4022 if (x >= MAX_ARGS -1) {
4023 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
4024 break;
4025 }
4026 /* Coming off of whitespace, start the next argument */
4027 argv[x++] = cur;
4028 whitespace=0;
4029 }
4030 *(cur++) = *s;
4031 escaped=0;
4032 }
4033 s++;
4034 }
4035 /* Null terminate */
4036 *(cur++) = '\0';
4037 argv[x] = NULL;
4038 *max = x;
4039 return 0;
4040}
4041
4042static void publish_async_exec_end(struct ast_channel *chan, int command_id, const char *command, int result_code, const char *result)
4043{
4044 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4045 blob = ast_json_pack("{s: i, s: s, s: i, s: s}",
4046 "CommandId", command_id,
4047 "Command", command,
4048 "ResultCode", result_code,
4049 "Result", result);
4050 ast_channel_publish_cached_blob(chan, agi_exec_end_type(), blob);
4051}
4052
4053static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
4054{
4055 const char *argv[MAX_ARGS] = {0};
4056 int argc = MAX_ARGS;
4057 int res;
4058 agi_command *c;
4059 char *ami_cmd = ast_strdupa(buf);
4060 const char *ami_res;
4061 int command_id = ast_random();
4062 int resultcode = 0;
4063 RAII_VAR(struct ast_json *, startblob, NULL, ast_json_unref);
4064
4065 startblob = ast_json_pack("{s: i, s: s}",
4066 "CommandId", command_id,
4067 "Command", ami_cmd);
4068 ast_channel_publish_cached_blob(chan, agi_exec_start_type(), startblob);
4069
4070 parse_args(buf, &argc, argv);
4071 c = find_command(argv, 0);
4072 if (!c || !ast_module_running_ref(c->mod)) {
4073 ami_res = "Invalid or unknown command";
4074 resultcode = 510;
4075
4076 ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
4077
4078 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4079
4080 return AGI_RESULT_SUCCESS;
4081 }
4082
4083 if (!dead || (dead && c->dead)) {
4084 res = c->handler(chan, agi, argc, argv);
4085 switch (res) {
4086 case RESULT_SHOWUSAGE:
4087 ami_res = "Usage";
4088 resultcode = 520;
4089
4090 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4091
4092 if (ast_strlen_zero(c->usage)) {
4093 ast_agi_send(agi->fd, chan, "520 Invalid command syntax. Proper usage not available.\n");
4094 } else {
4095 ast_agi_send(agi->fd, chan, "520-Invalid command syntax. Proper usage follows:\n");
4096 ast_agi_send(agi->fd, chan, "%s\n", c->usage);
4097 ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
4098 }
4099
4100 break;
4101 case RESULT_FAILURE:
4102 ami_res = "Failure";
4103 resultcode = -1;
4104
4105 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4106
4107 /* The RESULT_FAILURE code is usually because the channel hungup. */
4108 return AGI_RESULT_FAILURE;
4109 case ASYNC_AGI_BREAK:
4110 ami_res = "Success";
4111 resultcode = 200;
4112
4113 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4114
4116 case RESULT_SUCCESS:
4117 ami_res = "Success";
4118 resultcode = 200;
4119
4120 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4121
4122 break;
4123 default:
4124 ami_res = "Unknown Result";
4125 resultcode = 200;
4126
4127 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4128
4129 break;
4130 }
4131 } else {
4132 ami_res = "Command Not Permitted on a dead channel or intercept routine";
4133 resultcode = 511;
4134
4135 ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
4136
4137 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4138 }
4139 ast_module_unref(c->mod);
4140
4141 return AGI_RESULT_SUCCESS;
4142}
4143
4144static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
4145{
4146 struct ast_channel *c;
4147 int outfd;
4148 int ms;
4149 int needhup = 0;
4150 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
4151 struct ast_frame *f;
4152 char buf[AGI_BUF_LEN];
4153 char *res = NULL;
4154 FILE *readf;
4155 /* how many times we'll retry if ast_waitfor_nandfs will return without either
4156 channel or file descriptor in case select is interrupted by a system call (EINTR) */
4157 int retry = AGI_NANDFS_RETRY;
4158 int send_sighup;
4159 const char *sighup_str;
4160 const char *exit_on_hangup_str;
4161 int exit_on_hangup;
4162 /*! Running in an interception routine is like DeadAGI mode. No touchy the channel frames. */
4163 int in_intercept = ast_channel_get_intercept_mode();
4164
4165 ast_channel_lock(chan);
4166 sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
4167 send_sighup = !ast_false(sighup_str);
4168 exit_on_hangup_str = pbx_builtin_getvar_helper(chan, "AGIEXITONHANGUP");
4169 exit_on_hangup = ast_true(exit_on_hangup_str);
4170 ast_channel_unlock(chan);
4171
4172 if (!(readf = fdopen(agi->ctrl, "r"))) {
4173 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
4174 if (send_sighup && pid > -1)
4175 kill(pid, SIGHUP);
4176 close(agi->ctrl);
4177 return AGI_RESULT_FAILURE;
4178 }
4179
4180 setlinebuf(readf);
4181 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
4182 for (;;) {
4183 if (needhup) {
4184 needhup = 0;
4185 dead = 1;
4186 if (send_sighup) {
4187 if (pid > -1) {
4188 kill(pid, SIGHUP);
4189 } else if (agi->fast) {
4190 ast_agi_send(agi->fd, chan, "HANGUP\n");
4191 }
4192 }
4193 if (exit_on_hangup) {
4194 break;
4195 }
4196 }
4197 ms = -1;
4198 if (dead || in_intercept) {
4199 c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
4200 } else if (!ast_check_hangup(chan)) {
4201 c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
4202 } else {
4203 /*
4204 * Read the channel control queue until it is dry so we can
4205 * switch to dead mode.
4206 */
4207 c = chan;
4208 }
4209 if (c) {
4210 retry = AGI_NANDFS_RETRY;
4211 /* Idle the channel until we get a command */
4212 f = ast_read(c);
4213 if (!f) {
4214 ast_debug(1, "%s hungup\n", ast_channel_name(chan));
4215 needhup = 1;
4216 if (!returnstatus) {
4217 returnstatus = AGI_RESULT_HANGUP;
4218 }
4219 } else {
4220 /* If it's voice, write it to the audio pipe */
4221 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
4222 /* Write, ignoring errors */
4223 if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
4224 }
4225 }
4226 ast_frfree(f);
4227 }
4228 } else if (outfd > -1) {
4229 size_t len = sizeof(buf);
4230 size_t buflen = 0;
4231 enum agi_result cmd_status;
4232
4233 retry = AGI_NANDFS_RETRY;
4234 buf[0] = '\0';
4235
4236 while (len > 1) {
4237 res = fgets(buf + buflen, len, readf);
4238 if (feof(readf))
4239 break;
4240 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
4241 break;
4242 if (res != NULL && !agi->fast)
4243 break;
4244 buflen = strlen(buf);
4245 if (buflen && buf[buflen - 1] == '\n')
4246 break;
4247 len = sizeof(buf) - buflen;
4248 if (agidebug)
4249 ast_verbose("AGI Rx << temp buffer %s - errno %s\nNo \\n received, checking again.\n", buf, strerror(errno));
4250 }
4251
4252 if (!buf[0]) {
4253 /* Program terminated */
4254 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", ast_channel_name(chan), request, returnstatus);
4255 if (pid > 0)
4256 waitpid(pid, status, 0);
4257 /* No need to kill the pid anymore, since they closed us */
4258 pid = -1;
4259 break;
4260 }
4261
4262 /* Special case for inability to execute child process */
4263 if (*buf && strncasecmp(buf, "failure", 7) == 0) {
4264 returnstatus = AGI_RESULT_FAILURE;
4265 break;
4266 }
4267
4268 /* get rid of trailing newline, if any */
4269 buflen = strlen(buf);
4270 if (buflen && buf[buflen - 1] == '\n') {
4271 buf[buflen - 1] = '\0';
4272 }
4273
4274 if (agidebug)
4275 ast_verbose("<%s>AGI Rx << %s\n", ast_channel_name(chan), buf);
4276 cmd_status = agi_handle_command(chan, agi, buf, dead || in_intercept);
4277 switch (cmd_status) {
4278 case AGI_RESULT_FAILURE:
4279 if (dead || in_intercept || !ast_check_hangup(chan)) {
4280 /* The failure was not because of a hangup. */
4281 returnstatus = AGI_RESULT_FAILURE;
4282 }
4283 break;
4284 default:
4285 break;
4286 }
4287 } else {
4288 if (--retry <= 0) {
4289 ast_log(LOG_WARNING, "No channel, no fd?\n");
4290 returnstatus = AGI_RESULT_FAILURE;
4291 break;
4292 }
4293 }
4294 }
4295
4296 if (agi->speech) {
4298 }
4299 /* Notify process */
4300 if (send_sighup) {
4301 if (pid > -1) {
4302 if (kill(pid, SIGHUP)) {
4303 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
4304 } else { /* Give the process a chance to die */
4305 usleep(1);
4306 }
4307 waitpid(pid, status, WNOHANG);
4308 } else if (agi->fast) {
4309 ast_agi_send(agi->fd, chan, "HANGUP\n");
4310 }
4311 }
4312 fclose(readf);
4313 return returnstatus;
4314}
4315
4316static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4317{
4318 struct agi_command *command;
4319 char fullcmd[MAX_CMD_LEN];
4320 int error = 0;
4321
4322 switch (cmd) {
4323 case CLI_INIT:
4324 e->command = "agi show commands [topic]";
4325 e->usage =
4326 "Usage: agi show commands [topic] <topic>\n"
4327 " When called with a topic as an argument, displays usage\n"
4328 " information on the given command. If called without a\n"
4329 " topic, it provides a list of AGI commands.\n";
4330 case CLI_GENERATE:
4331 return NULL;
4332 }
4333 if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
4334 return CLI_SHOWUSAGE;
4335 if (a->argc > e->args - 1) {
4336 command = find_command(a->argv + e->args, 1);
4337 if (command) {
4338 char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL;
4339 char info[30 + MAX_CMD_LEN]; /* '-= Info about...' */
4340 char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS]; /* '-= Info about...' with colors */
4341 char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Syntax]\n with colors */
4342 char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Description]\n with colors */
4343 char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Runs Dead]\n with colors */
4344 char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS]; /* 'Yes' or 'No' with colors */
4345 char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS]; /* [See Also]\n with colors */
4346 char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Syntax]\n with colors */
4347 size_t synlen, desclen, seealsolen, stxlen;
4348
4349 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle));
4350 term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle));
4351 term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle));
4352 term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle));
4353 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle));
4354 term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent));
4355
4356 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
4357 snprintf(info, sizeof(info), "\n -= Info about agi '%s' =- ", fullcmd);
4358 term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle));
4359#ifdef AST_XML_DOCS
4360 if (command->docsrc == AST_XML_DOC) {
4361 synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
4362 description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
4363 seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
4364 if (!seealso || !description || !synopsis) {
4365 error = 1;
4366 goto return_cleanup;
4367 }
4368 } else
4369#endif
4370 {
4371 synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
4372 synopsis = ast_malloc(synlen);
4373
4374 desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
4375 description = ast_malloc(desclen);
4376
4377 seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
4378 seealso = ast_malloc(seealsolen);
4379
4380 if (!synopsis || !description || !seealso) {
4381 error = 1;
4382 goto return_cleanup;
4383 }
4384 term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen);
4385 term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen);
4386 term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen);
4387 }
4388
4389 stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
4390 syntax = ast_malloc(stxlen);
4391 if (!syntax) {
4392 error = 1;
4393 goto return_cleanup;
4394 }
4395 term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen);
4396
4397 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,
4398 desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
4399 seealsotitle, seealso);
4400return_cleanup:
4402 ast_free(description);
4405 } else {
4406 if (find_command(a->argv + e->args, -1)) {
4407 return help_workhorse(a->fd, a->argv + e->args);
4408 } else {
4409 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
4410 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
4411 }
4412 }
4413 } else {
4414 return help_workhorse(a->fd, NULL);
4415 }
4416 return (error ? CLI_FAILURE : CLI_SUCCESS);
4417}
4418
4419/*! \brief Convert string to use HTML escaped characters
4420 \note Maybe this should be a generic function?
4421*/
4422static void write_html_escaped(FILE *htmlfile, char *str)
4423{
4424 char *cur = str;
4425
4426 while(*cur) {
4427 switch (*cur) {
4428 case '<':
4429 fprintf(htmlfile, "%s", "&lt;");
4430 break;
4431 case '>':
4432 fprintf(htmlfile, "%s", "&gt;");
4433 break;
4434 case '&':
4435 fprintf(htmlfile, "%s", "&amp;");
4436 break;
4437 case '"':
4438 fprintf(htmlfile, "%s", "&quot;");
4439 break;
4440 default:
4441 fprintf(htmlfile, "%c", *cur);
4442 break;
4443 }
4444 cur++;
4445 }
4446
4447 return;
4448}
4449
4450static int write_htmldump(const char *filename)
4451{
4452 struct agi_command *command;
4453 char fullcmd[MAX_CMD_LEN];
4454 FILE *htmlfile;
4455
4456 if (!(htmlfile = fopen(filename, "wt")))
4457 return -1;
4458
4459 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
4460 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
4461 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
4462
4465 char *tempstr, *stringp;
4466
4467 if (!command->cmda[0]) /* end ? */
4468 break;
4469 /* Hide commands that start with '_' */
4470 if ((command->cmda[0])[0] == '_')
4471 continue;
4472 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
4473
4474 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
4475 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
4476#ifdef AST_XML_DOCS
4477 stringp = ast_xmldoc_printable(command->usage, 0);
4478#else
4479 stringp = ast_strdup(command->usage);
4480#endif
4481 tempstr = strsep(&stringp, "\n");
4482
4483 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
4484 write_html_escaped(htmlfile, tempstr);
4485 fprintf(htmlfile, "</TD></TR>\n");
4486 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
4487
4488 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
4489 write_html_escaped(htmlfile, tempstr);
4490 fprintf(htmlfile, "<BR>\n");
4491 }
4492 fprintf(htmlfile, "</TD></TR>\n");
4493 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
4494 ast_free(stringp);
4495 }
4497 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
4498 fclose(htmlfile);
4499 return 0;
4500}
4501
4502static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4503{
4504 switch (cmd) {
4505 case CLI_INIT:
4506 e->command = "agi dump html";
4507 e->usage =
4508 "Usage: agi dump html <filename>\n"
4509 " Dumps the AGI command list in HTML format to the given\n"
4510 " file.\n";
4511 return NULL;
4512 case CLI_GENERATE:
4513 return NULL;
4514 }
4515 if (a->argc != e->args + 1)
4516 return CLI_SHOWUSAGE;
4517
4518 if (write_htmldump(a->argv[e->args]) < 0) {
4519 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
4520 return CLI_SHOWUSAGE;
4521 }
4522 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
4523 return CLI_SUCCESS;
4524}
4525
4526static int agi_exec_full(struct ast_channel *chan, const char *data, int enhanced, int dead)
4527{
4528 enum agi_result res;
4529 char *buf;
4530 int fds[2], efd = -1, pid = -1;
4532 AST_APP_ARG(arg)[MAX_ARGS];
4533 );
4534 AGI agi;
4535
4536 if (ast_strlen_zero(data)) {
4537 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
4538 return -1;
4539 }
4540 if (dead)
4541 ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
4542 memset(&agi, 0, sizeof(agi));
4543 buf = ast_strdupa(data);
4545 args.arg[args.argc] = NULL;
4546#if 0
4547 /* Answer if need be */
4548 if (chan->_state != AST_STATE_UP) {
4549 if (ast_answer(chan))
4550 return -1;
4551 }
4552#endif
4553 res = launch_script(chan, args.arg[0], args.argc, args.arg, fds, enhanced ? &efd : NULL, &pid);
4554 /* Async AGI do not require run_agi(), so just proceed if normal AGI
4555 or Fast AGI are setup with success. */
4556 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
4557 int status = 0;
4558 agi.fd = fds[1];
4559 agi.ctrl = fds[0];
4560 agi.audio = efd;
4561 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
4562 res = run_agi(chan, args.arg[0], &agi, pid, &status, dead, args.argc, args.arg);
4563 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
4564 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
4565 res = AGI_RESULT_FAILURE;
4566 if (fds[1] != fds[0])
4567 close(fds[1]);
4568 if (efd > -1)
4569 close(efd);
4570 }
4572
4573 switch (res) {
4574 case AGI_RESULT_SUCCESS:
4577 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
4578 break;
4579 case AGI_RESULT_FAILURE:
4580 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
4581 break;
4583 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
4584 break;
4585 case AGI_RESULT_HANGUP:
4586 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
4587 return -1;
4588 }
4589
4590 return 0;
4591}
4592
4593static int agi_exec(struct ast_channel *chan, const char *data)
4594{
4595 if (!ast_check_hangup(chan))
4596 return agi_exec_full(chan, data, 0, 0);
4597 else
4598 return agi_exec_full(chan, data, 0, 1);
4599}
4600
4601static int eagi_exec(struct ast_channel *chan, const char *data)
4602{
4603 int res;
4604 struct ast_format *readformat;
4605 struct ast_format *requested_format = NULL;
4606 const char *requested_format_name;
4607
4608 if (ast_check_hangup(chan)) {
4609 ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
4610 return 0;
4611 }
4612
4613 requested_format_name = pbx_builtin_getvar_helper(chan, "EAGI_AUDIO_FORMAT");
4614 if (requested_format_name) {
4615 requested_format = ast_format_cache_get(requested_format_name);
4616 if (requested_format) {
4617 ast_verb(3, "<%s> Setting EAGI audio pipe format to %s\n",
4618 ast_channel_name(chan), ast_format_get_name(requested_format));
4619 } else {
4620 ast_log(LOG_ERROR, "Could not find requested format: %s\n", requested_format_name);
4621 }
4622 }
4623
4624 readformat = ao2_bump(ast_channel_readformat(chan));
4625 if (ast_set_read_format(chan, requested_format ?: ast_format_slin)) {
4626 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", ast_channel_name(chan));
4627 ao2_cleanup(requested_format);
4628 ao2_cleanup(readformat);
4629 return -1;
4630 }
4631 res = agi_exec_full(chan, data, 1, 0);
4632 if (!res) {
4633 if (ast_set_read_format(chan, readformat)) {
4634 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", ast_channel_name(chan),
4635 ast_format_get_name(readformat));
4636 }
4637 }
4638 ao2_cleanup(requested_format);
4639 ao2_cleanup(readformat);
4640 return res;
4641}
4642
4643static int deadagi_exec(struct ast_channel *chan, const char *data)
4644{
4645 ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
4646 return agi_exec(chan, data);
4647}
4648
4649static struct ast_cli_entry cli_agi[] = {
4650 AST_CLI_DEFINE(handle_cli_agi_add_cmd, "Add AGI command to a channel in Async AGI"),
4651 AST_CLI_DEFINE(handle_cli_agi_debug, "Enable/Disable AGI debugging"),
4652 AST_CLI_DEFINE(handle_cli_agi_show, "List AGI commands or specific help"),
4653 AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format")
4654};
4655
4656#ifdef TEST_FRAMEWORK
4657AST_TEST_DEFINE(test_agi_null_docs)
4658{
4659 int res = AST_TEST_PASS;
4660 struct agi_command noop_command =
4661 { { "testnoop", NULL }, handle_noop, NULL, NULL, 0 };
4662
4663 switch (cmd) {
4664 case TEST_INIT:
4665 info->name = "null_agi_docs";
4666 info->category = "/res/agi/";
4667 info->summary = "AGI command with no documentation";
4668 info->description = "Test whether an AGI command with no documentation will crash Asterisk";
4669 return AST_TEST_NOT_RUN;
4670 case TEST_EXECUTE:
4671 break;
4672 }
4673
4674 if (ast_agi_register(ast_module_info->self, &noop_command) == 0) {
4675 ast_test_status_update(test, "Unable to register testnoop command, because res_agi is not loaded.\n");
4676 return AST_TEST_NOT_RUN;
4677 }
4678
4679#ifndef HAVE_NULLSAFE_PRINTF
4680 /* Test for condition without actually crashing Asterisk */
4681 if (noop_command.usage == NULL) {
4682 ast_test_status_update(test, "AGI testnoop usage was not updated properly.\n");
4683 res = AST_TEST_FAIL;
4684 }
4685 if (noop_command.syntax == NULL) {
4686 ast_test_status_update(test, "AGI testnoop syntax was not updated properly.\n");
4687 res = AST_TEST_FAIL;
4688 }
4689#endif
4690
4691 ast_agi_unregister(&noop_command);
4692 return res;
4693}
4694#endif
4695
4696static int unload_module(void)
4697{
4698 STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_start_type);
4699 STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_end_type);
4700 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_start_type);
4701 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_exec_type);
4702 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_end_type);
4703
4710 AST_TEST_UNREGISTER(test_agi_null_docs);
4711 return 0;
4712}
4713
4714static int load_module(void)
4715{
4716 int err = 0;
4717
4718 err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_start_type);
4719 err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_end_type);
4720 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_start_type);
4721 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_exec_type);
4722 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_end_type);
4723
4730
4731 AST_TEST_REGISTER(test_agi_null_docs);
4732
4733 if (err) {
4734 unload_module();
4736 }
4737
4739}
4740
4742 .support_level = AST_MODULE_SUPPORT_CORE,
4743 .load = load_module,
4744 .unload = unload_module,
4745 .load_pri = AST_MODPRI_APP_DEPEND,
4746 .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:342
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:476
int ast_db_deltree(const char *family, const char *keytree)
Delete one or more entries in astdb.
Definition: main/db.c:536
static struct ast_str * prompt
Definition: asterisk.c:2775
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:1837
#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:2601
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:4717
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:2988
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:11034
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1821
#define ast_channel_lock(chan)
Definition: channel.h:2922
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:8164
int ast_recvchar(struct ast_channel *chan, int timeout)
Receives a text character from a channel.
Definition: channel.c:4706
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3162
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:10333