Wed Jan 8 2020 09:49:49

Asterisk developer's documentation


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  * \todo Convert the rest of the AGI commands over to XML documentation
26  */
27 
28 /*** MODULEINFO
29  <support_level>core</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426363 $")
35 
36 #include <math.h>
37 #include <signal.h>
38 #include <sys/time.h>
39 #include <sys/wait.h>
40 #include <sys/stat.h>
41 #include <pthread.h>
42 
43 #include "asterisk/paths.h" /* use many ast_config_AST_*_DIR */
44 #include "asterisk/network.h"
45 #include "asterisk/file.h"
46 #include "asterisk/channel.h"
47 #include "asterisk/pbx.h"
48 #include "asterisk/module.h"
49 #include "asterisk/astdb.h"
50 #include "asterisk/callerid.h"
51 #include "asterisk/cli.h"
52 #include "asterisk/image.h"
53 #include "asterisk/say.h"
54 #include "asterisk/app.h"
55 #include "asterisk/dsp.h"
56 #include "asterisk/musiconhold.h"
57 #include "asterisk/utils.h"
58 #include "asterisk/lock.h"
59 #include "asterisk/strings.h"
60 #include "asterisk/manager.h"
61 #include "asterisk/ast_version.h"
62 #include "asterisk/speech.h"
63 #include "asterisk/manager.h"
64 #include "asterisk/term.h"
65 #include "asterisk/xmldoc.h"
66 #include "asterisk/srv.h"
67 #include "asterisk/test.h"
68 
69 #define AST_API_MODULE
70 #include "asterisk/agi.h"
71 
72 /*** DOCUMENTATION
73  <agi name="answer" language="en_US">
74  <synopsis>
75  Answer channel
76  </synopsis>
77  <syntax />
78  <description>
79  <para>Answers channel if not already in answer state. Returns <literal>-1</literal> on
80  channel failure, or <literal>0</literal> if successful.</para>
81  </description>
82  <see-also>
83  <ref type="agi">hangup</ref>
84  </see-also>
85  </agi>
86  <agi name="asyncagi break" language="en_US">
87  <synopsis>
88  Interrupts Async AGI
89  </synopsis>
90  <syntax />
91  <description>
92  <para>Interrupts expected flow of Async AGI commands and returns control to previous source
93  (typically, the PBX dialplan).</para>
94  </description>
95  <see-also>
96  <ref type="agi">hangup</ref>
97  </see-also>
98  </agi>
99  <agi name="channel status" language="en_US">
100  <synopsis>
101  Returns status of the connected channel.
102  </synopsis>
103  <syntax>
104  <parameter name="channelname" />
105  </syntax>
106  <description>
107  <para>Returns the status of the specified <replaceable>channelname</replaceable>.
108  If no channel name is given then returns the status of the current channel.</para>
109  <para>Return values:</para>
110  <enumlist>
111  <enum name="0">
112  <para>Channel is down and available.</para>
113  </enum>
114  <enum name="1">
115  <para>Channel is down, but reserved.</para>
116  </enum>
117  <enum name="2">
118  <para>Channel is off hook.</para>
119  </enum>
120  <enum name="3">
121  <para>Digits (or equivalent) have been dialed.</para>
122  </enum>
123  <enum name="4">
124  <para>Line is ringing.</para>
125  </enum>
126  <enum name="5">
127  <para>Remote end is ringing.</para>
128  </enum>
129  <enum name="6">
130  <para>Line is up.</para>
131  </enum>
132  <enum name="7">
133  <para>Line is busy.</para>
134  </enum>
135  </enumlist>
136  </description>
137  </agi>
138  <agi name="control stream file" language="en_US">
139  <synopsis>
140  Sends audio file on channel and allows the listener to control the stream.
141  </synopsis>
142  <syntax>
143  <parameter name="filename" required="true">
144  <para>The file extension must not be included in the filename.</para>
145  </parameter>
146  <parameter name="escape_digits" required="true" />
147  <parameter name="skipms" />
148  <parameter name="ffchar">
149  <para>Defaults to <literal>#</literal></para>
150  </parameter>
151  <parameter name="rewchr">
152  <para>Defaults to <literal>*</literal></para>
153  </parameter>
154  <parameter name="pausechr" />
155  </syntax>
156  <description>
157  <para>Send the given file, allowing playback to be controlled by the given
158  digits, if any. Use double quotes for the digits if you wish none to be
159  permitted. Returns <literal>0</literal> if playback completes without a digit
160  being pressed, or the ASCII numerical value of the digit if one was pressed,
161  or <literal>-1</literal> on error or if the channel was disconnected.</para>
162  </description>
163  </agi>
164  <agi name="database del" language="en_US">
165  <synopsis>
166  Removes database key/value
167  </synopsis>
168  <syntax>
169  <parameter name="family" required="true" />
170  <parameter name="key" required="true" />
171  </syntax>
172  <description>
173  <para>Deletes an entry in the Asterisk database for a given
174  <replaceable>family</replaceable> and <replaceable>key</replaceable>.</para>
175  <para>Returns <literal>1</literal> if successful, <literal>0</literal>
176  otherwise.</para>
177  </description>
178  </agi>
179  <agi name="database deltree" language="en_US">
180  <synopsis>
181  Removes database keytree/value
182  </synopsis>
183  <syntax>
184  <parameter name="family" required="true" />
185  <parameter name="keytree" />
186  </syntax>
187  <description>
188  <para>Deletes a <replaceable>family</replaceable> or specific <replaceable>keytree</replaceable>
189  within a <replaceable>family</replaceable> in the Asterisk database.</para>
190  <para>Returns <literal>1</literal> if successful, <literal>0</literal> otherwise.</para>
191  </description>
192  </agi>
193  <agi name="database get" language="en_US">
194  <synopsis>
195  Gets database value
196  </synopsis>
197  <syntax>
198  <parameter name="family" required="true" />
199  <parameter name="key" required="true" />
200  </syntax>
201  <description>
202  <para>Retrieves an entry in the Asterisk database for a given <replaceable>family</replaceable>
203  and <replaceable>key</replaceable>.</para>
204  <para>Returns <literal>0</literal> if <replaceable>key</replaceable> is not set.
205  Returns <literal>1</literal> if <replaceable>key</replaceable> is set and returns the variable
206  in parenthesis.</para>
207  <para>Example return code: 200 result=1 (testvariable)</para>
208  </description>
209  </agi>
210  <agi name="database put" language="en_US">
211  <synopsis>
212  Adds/updates database value
213  </synopsis>
214  <syntax>
215  <parameter name="family" required="true" />
216  <parameter name="key" required="true" />
217  <parameter name="value" required="true" />
218  </syntax>
219  <description>
220  <para>Adds or updates an entry in the Asterisk database for a given
221  <replaceable>family</replaceable>, <replaceable>key</replaceable>, and
222  <replaceable>value</replaceable>.</para>
223  <para>Returns <literal>1</literal> if successful, <literal>0</literal> otherwise.</para>
224  </description>
225  </agi>
226  <agi name="exec" language="en_US">
227  <synopsis>
228  Executes a given Application
229  </synopsis>
230  <syntax>
231  <parameter name="application" required="true" />
232  <parameter name="options" required="true" />
233  </syntax>
234  <description>
235  <para>Executes <replaceable>application</replaceable> with given
236  <replaceable>options</replaceable>.</para>
237  <para>Returns whatever the <replaceable>application</replaceable> returns, or
238  <literal>-2</literal> on failure to find <replaceable>application</replaceable>.</para>
239  </description>
240  </agi>
241  <agi name="get data" language="en_US">
242  <synopsis>
243  Prompts for DTMF on a channel
244  </synopsis>
245  <syntax>
246  <parameter name="file" required="true" />
247  <parameter name="timeout" />
248  <parameter name="maxdigits" />
249  </syntax>
250  <description>
251  <para>Stream the given <replaceable>file</replaceable>, and receive DTMF data.</para>
252  <para>Returns the digits received from the channel at the other end.</para>
253  </description>
254  </agi>
255  <agi name="get full variable" language="en_US">
256  <synopsis>
257  Evaluates a channel expression
258  </synopsis>
259  <syntax>
260  <parameter name="variablename" required="true" />
261  <parameter name="channel name" />
262  </syntax>
263  <description>
264  <para>Returns <literal>0</literal> if <replaceable>variablename</replaceable> is not set
265  or channel does not exist. Returns <literal>1</literal> if <replaceable>variablename</replaceable>
266  is set and returns the variable in parenthesis. Understands complex variable names and builtin
267  variables, unlike GET VARIABLE.</para>
268  <para>Example return code: 200 result=1 (testvariable)</para>
269  </description>
270  </agi>
271  <agi name="get option" language="en_US">
272  <synopsis>
273  Stream file, prompt for DTMF, with timeout.
274  </synopsis>
275  <syntax>
276  <parameter name="filename" required="true" />
277  <parameter name="escape_digits" required="true" />
278  <parameter name="timeout" />
279  </syntax>
280  <description>
281  <para>Behaves similar to STREAM FILE but used with a timeout option.</para>
282  </description>
283  <see-also>
284  <ref type="agi">stream file</ref>
285  </see-also>
286  </agi>
287  <agi name="get variable" language="en_US">
288  <synopsis>
289  Gets a channel variable.
290  </synopsis>
291  <syntax>
292  <parameter name="variablename" required="true" />
293  </syntax>
294  <description>
295  <para>Returns <literal>0</literal> if <replaceable>variablename</replaceable> is not set.
296  Returns <literal>1</literal> if <replaceable>variablename</replaceable> is set and returns
297  the variable in parentheses.</para>
298  <para>Example return code: 200 result=1 (testvariable)</para>
299  </description>
300  </agi>
301  <agi name="hangup" language="en_US">
302  <synopsis>
303  Hangup a channel.
304  </synopsis>
305  <syntax>
306  <parameter name="channelname" />
307  </syntax>
308  <description>
309  <para>Hangs up the specified channel. If no channel name is given, hangs
310  up the current channel</para>
311  </description>
312  </agi>
313  <agi name="noop" language="en_US">
314  <synopsis>
315  Does nothing.
316  </synopsis>
317  <syntax />
318  <description>
319  <para>Does nothing.</para>
320  </description>
321  </agi>
322  <agi name="receive char" language="en_US">
323  <synopsis>
324  Receives one character from channels supporting it.
325  </synopsis>
326  <syntax>
327  <parameter name="timeout" required="true">
328  <para>The maximum time to wait for input in milliseconds, or <literal>0</literal>
329  for infinite. Most channels</para>
330  </parameter>
331  </syntax>
332  <description>
333  <para>Receives a character of text on a channel. Most channels do not support
334  the reception of text. Returns the decimal value of the character
335  if one is received, or <literal>0</literal> if the channel does not support
336  text reception. Returns <literal>-1</literal> only on error/hangup.</para>
337  </description>
338  </agi>
339  <agi name="receive text" language="en_US">
340  <synopsis>
341  Receives text from channels supporting it.
342  </synopsis>
343  <syntax>
344  <parameter name="timeout" required="true">
345  <para>The timeout to be the maximum time to wait for input in
346  milliseconds, or <literal>0</literal> for infinite.</para>
347  </parameter>
348  </syntax>
349  <description>
350  <para>Receives a string of text on a channel. Most channels
351  do not support the reception of text. Returns <literal>-1</literal> for failure
352  or <literal>1</literal> for success, and the string in parenthesis.</para>
353  </description>
354  </agi>
355  <agi name="record file" language="en_US">
356  <synopsis>
357  Records to a given file.
358  </synopsis>
359  <syntax>
360  <parameter name="filename" required="true" />
361  <parameter name="format" required="true" />
362  <parameter name="escape_digits" required="true" />
363  <parameter name="timeout" required="true" />
364  <parameter name="offset samples" />
365  <parameter name="BEEP" />
366  <parameter name="s=silence" />
367  </syntax>
368  <description>
369  <para>Record to a file until a given dtmf digit in the sequence is received.
370  Returns <literal>-1</literal> on hangup or error. The format will specify what kind of file
371  will be recorded. The <replaceable>timeout</replaceable> is the maximum record time in
372  milliseconds, or <literal>-1</literal> for no <replaceable>timeout</replaceable>.
373  <replaceable>offset samples</replaceable> is optional, and, if provided, will seek
374  to the offset without exceeding the end of the file. <replaceable>silence</replaceable> is
375  the number of seconds of silence allowed before the function returns despite the
376  lack of dtmf digits or reaching <replaceable>timeout</replaceable>. <replaceable>silence</replaceable>
377  value must be preceded by <literal>s=</literal> and is also optional.</para>
378  </description>
379  </agi>
380  <agi name="say alpha" language="en_US">
381  <synopsis>
382  Says a given character string.
383  </synopsis>
384  <syntax>
385  <parameter name="number" required="true" />
386  <parameter name="escape_digits" required="true" />
387  </syntax>
388  <description>
389  <para>Say a given character string, returning early if any of the given DTMF digits
390  are received on the channel. Returns <literal>0</literal> if playback completes
391  without a digit being pressed, or the ASCII numerical value of the digit if one
392  was pressed or <literal>-1</literal> on error/hangup.</para>
393  </description>
394  </agi>
395  <agi name="say digits" language="en_US">
396  <synopsis>
397  Says a given digit string.
398  </synopsis>
399  <syntax>
400  <parameter name="number" required="true" />
401  <parameter name="escape_digits" required="true" />
402  </syntax>
403  <description>
404  <para>Say a given digit string, returning early if any of the given DTMF digits
405  are received on the channel. Returns <literal>0</literal> if playback completes
406  without a digit being pressed, or the ASCII numerical value of the digit if one
407  was pressed or <literal>-1</literal> on error/hangup.</para>
408  </description>
409  </agi>
410  <agi name="say number" language="en_US">
411  <synopsis>
412  Says a given number.
413  </synopsis>
414  <syntax>
415  <parameter name="number" required="true" />
416  <parameter name="escape_digits" required="true" />
417  <parameter name="gender" />
418  </syntax>
419  <description>
420  <para>Say a given number, returning early if any of the given DTMF digits
421  are received on the channel. Returns <literal>0</literal> if playback
422  completes without a digit being pressed, or the ASCII numerical value of
423  the digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
424  </description>
425  </agi>
426  <agi name="say phonetic" language="en_US">
427  <synopsis>
428  Says a given character string with phonetics.
429  </synopsis>
430  <syntax>
431  <parameter name="string" required="true" />
432  <parameter name="escape_digits" required="true" />
433  </syntax>
434  <description>
435  <para>Say a given character string with phonetics, returning early if any of the
436  given DTMF digits are received on the channel. Returns <literal>0</literal> if
437  playback completes without a digit pressed, the ASCII numerical value of the digit
438  if one was pressed, or <literal>-1</literal> on error/hangup.</para>
439  </description>
440  </agi>
441  <agi name="say date" language="en_US">
442  <synopsis>
443  Says a given date.
444  </synopsis>
445  <syntax>
446  <parameter name="date" required="true">
447  <para>Is number of seconds elapsed since 00:00:00 on January 1, 1970.
448  Coordinated Universal Time (UTC).</para>
449  </parameter>
450  <parameter name="escape_digits" required="true" />
451  </syntax>
452  <description>
453  <para>Say a given date, returning early if any of the given DTMF digits are
454  received on the channel. Returns <literal>0</literal> if playback
455  completes without a digit being pressed, or the ASCII numerical value of the
456  digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
457  </description>
458  </agi>
459  <agi name="say time" language="en_US">
460  <synopsis>
461  Says a given time.
462  </synopsis>
463  <syntax>
464  <parameter name="time" required="true">
465  <para>Is number of seconds elapsed since 00:00:00 on January 1, 1970.
466  Coordinated Universal Time (UTC).</para>
467  </parameter>
468  <parameter name="escape_digits" required="true" />
469  </syntax>
470  <description>
471  <para>Say a given time, returning early if any of the given DTMF digits are
472  received on the channel. Returns <literal>0</literal> if playback completes
473  without a digit being pressed, or the ASCII numerical value of the digit if
474  one was pressed or <literal>-1</literal> on error/hangup.</para>
475  </description>
476  </agi>
477  <agi name="say datetime" language="en_US">
478  <synopsis>
479  Says a given time as specified by the format given.
480  </synopsis>
481  <syntax>
482  <parameter name="time" required="true">
483  <para>Is number of seconds elapsed since 00:00:00
484  on January 1, 1970, Coordinated Universal Time (UTC)</para>
485  </parameter>
486  <parameter name="escape_digits" required="true" />
487  <parameter name="format">
488  <para>Is the format the time should be said in. See
489  <filename>voicemail.conf</filename> (defaults to <literal>ABdY
490  'digits/at' IMp</literal>).</para>
491  </parameter>
492  <parameter name="timezone">
493  <para>Acceptable values can be found in <filename>/usr/share/zoneinfo</filename>
494  Defaults to machine default.</para>
495  </parameter>
496  </syntax>
497  <description>
498  <para>Say a given time, returning early if any of the given DTMF digits are
499  received on the channel. Returns <literal>0</literal> if playback
500  completes without a digit being pressed, or the ASCII numerical value of the
501  digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
502  </description>
503  </agi>
504  <agi name="send image" language="en_US">
505  <synopsis>
506  Sends images to channels supporting it.
507  </synopsis>
508  <syntax>
509  <parameter name="image" required="true" />
510  </syntax>
511  <description>
512  <para>Sends the given image on a channel. Most channels do not support the
513  transmission of images. Returns <literal>0</literal> if image is sent, or if
514  the channel does not support image transmission. Returns <literal>-1</literal>
515  only on error/hangup. Image names should not include extensions.</para>
516  </description>
517  </agi>
518  <agi name="send text" language="en_US">
519  <synopsis>
520  Sends text to channels supporting it.
521  </synopsis>
522  <syntax>
523  <parameter name="text to send" required="true">
524  <para>Text consisting of greater than one word should be placed
525  in quotes since the command only accepts a single argument.</para>
526  </parameter>
527  </syntax>
528  <description>
529  <para>Sends the given text on a channel. Most channels do not support the
530  transmission of text. Returns <literal>0</literal> if text is sent, or if the
531  channel does not support text transmission. Returns <literal>-1</literal> only
532  on error/hangup.</para>
533  </description>
534  </agi>
535  <agi name="set autohangup" language="en_US">
536  <synopsis>
537  Autohangup channel in some time.
538  </synopsis>
539  <syntax>
540  <parameter name="time" required="true" />
541  </syntax>
542  <description>
543  <para>Cause the channel to automatically hangup at <replaceable>time</replaceable>
544  seconds in the future. Of course it can be hungup before then as well. Setting to
545  <literal>0</literal> will cause the autohangup feature to be disabled on this channel.</para>
546  </description>
547  </agi>
548  <agi name="set callerid" language="en_US">
549  <synopsis>
550  Sets callerid for the current channel.
551  </synopsis>
552  <syntax>
553  <parameter name="number" required="true" />
554  </syntax>
555  <description>
556  <para>Changes the callerid of the current channel.</para>
557  </description>
558  </agi>
559  <agi name="set context" language="en_US">
560  <synopsis>
561  Sets channel context.
562  </synopsis>
563  <syntax>
564  <parameter name="desired context" required="true" />
565  </syntax>
566  <description>
567  <para>Sets the context for continuation upon exiting the application.</para>
568  </description>
569  </agi>
570  <agi name="set extension" language="en_US">
571  <synopsis>
572  Changes channel extension.
573  </synopsis>
574  <syntax>
575  <parameter name="new extension" required="true" />
576  </syntax>
577  <description>
578  <para>Changes the extension for continuation upon exiting the application.</para>
579  </description>
580  </agi>
581  <agi name="set music" language="en_US">
582  <synopsis>
583  Enable/Disable Music on hold generator
584  </synopsis>
585  <syntax>
586  <parameter required="true">
587  <enumlist>
588  <enum>
589  <parameter name="on" literal="true" required="true" />
590  </enum>
591  <enum>
592  <parameter name="off" literal="true" required="true" />
593  </enum>
594  </enumlist>
595  </parameter>
596  <parameter name="class" required="true" />
597  </syntax>
598  <description>
599  <para>Enables/Disables the music on hold generator. If <replaceable>class</replaceable>
600  is not specified, then the <literal>default</literal> music on hold class will be
601  used. This generator will be stopped automatically when playing a file.</para>
602  <para>Always returns <literal>0</literal>.</para>
603  </description>
604  </agi>
605  <agi name="set priority" language="en_US">
606  <synopsis>
607  Set channel dialplan priority.
608  </synopsis>
609  <syntax>
610  <parameter name="priority" required="true" />
611  </syntax>
612  <description>
613  <para>Changes the priority for continuation upon exiting the application.
614  The priority must be a valid priority or label.</para>
615  </description>
616  </agi>
617  <agi name="set variable" language="en_US">
618  <synopsis>
619  Sets a channel variable.
620  </synopsis>
621  <syntax>
622  <parameter name="variablename" required="true" />
623  <parameter name="value" required="true" />
624  </syntax>
625  <description>
626  <para>Sets a variable to the current channel.</para>
627  </description>
628  </agi>
629  <agi name="stream file" language="en_US">
630  <synopsis>
631  Sends audio file on channel.
632  </synopsis>
633  <syntax>
634  <parameter name="filename" required="true">
635  <para>File name to play. The file extension must not be
636  included in the <replaceable>filename</replaceable>.</para>
637  </parameter>
638  <parameter name="escape_digits" required="true">
639  <para>Use double quotes for the digits if you wish none to be
640  permitted.</para>
641  </parameter>
642  <parameter name="sample offset">
643  <para>If sample offset is provided then the audio will seek to sample
644  offset before play starts.</para>
645  </parameter>
646  </syntax>
647  <description>
648  <para>Send the given file, allowing playback to be interrupted by the given
649  digits, if any. Returns <literal>0</literal> if playback completes without a digit
650  being pressed, or the ASCII numerical value of the digit if one was pressed,
651  or <literal>-1</literal> on error or if the channel was disconnected. If
652  musiconhold is playing before calling stream file it will be automatically
653  stopped and will not be restarted after completion.</para>
654  </description>
655  <see-also>
656  <ref type="agi">control stream file</ref>
657  </see-also>
658  </agi>
659  <agi name="tdd mode" language="en_US">
660  <synopsis>
661  Toggles TDD mode (for the deaf).
662  </synopsis>
663  <syntax>
664  <parameter name="boolean" required="true">
665  <enumlist>
666  <enum name="on" />
667  <enum name="off" />
668  </enumlist>
669  </parameter>
670  </syntax>
671  <description>
672  <para>Enable/Disable TDD transmission/reception on a channel. Returns <literal>1</literal> if
673  successful, or <literal>0</literal> if channel is not TDD-capable.</para>
674  </description>
675  </agi>
676  <agi name="verbose" language="en_US">
677  <synopsis>
678  Logs a message to the asterisk verbose log.
679  </synopsis>
680  <syntax>
681  <parameter name="message" required="true" />
682  <parameter name="level" required="true" />
683  </syntax>
684  <description>
685  <para>Sends <replaceable>message</replaceable> to the console via verbose
686  message system. <replaceable>level</replaceable> is the verbose level (1-4).
687  Always returns <literal>1</literal></para>
688  </description>
689  </agi>
690  <agi name="wait for digit" language="en_US">
691  <synopsis>
692  Waits for a digit to be pressed.
693  </synopsis>
694  <syntax>
695  <parameter name="timeout" required="true" />
696  </syntax>
697  <description>
698  <para>Waits up to <replaceable>timeout</replaceable> milliseconds for channel to
699  receive a DTMF digit. Returns <literal>-1</literal> on channel failure, <literal>0</literal>
700  if no digit is received in the timeout, or the numerical value of the ascii of the digit if
701  one is received. Use <literal>-1</literal> for the <replaceable>timeout</replaceable> value if
702  you desire the call to block indefinitely.</para>
703  </description>
704  </agi>
705  <agi name="speech create" language="en_US">
706  <synopsis>
707  Creates a speech object.
708  </synopsis>
709  <syntax>
710  <parameter name="engine" required="true" />
711  </syntax>
712  <description>
713  <para>Create a speech object to be used by the other Speech AGI commands.</para>
714  </description>
715  </agi>
716  <agi name="speech set" language="en_US">
717  <synopsis>
718  Sets a speech engine setting.
719  </synopsis>
720  <syntax>
721  <parameter name="name" required="true" />
722  <parameter name="value" required="true" />
723  </syntax>
724  <description>
725  <para>Set an engine-specific setting.</para>
726  </description>
727  </agi>
728  <agi name="speech destroy" language="en_US">
729  <synopsis>
730  Destroys a speech object.
731  </synopsis>
732  <syntax>
733  </syntax>
734  <description>
735  <para>Destroy the speech object created by <literal>SPEECH CREATE</literal>.</para>
736  </description>
737  <see-also>
738  <ref type="agi">speech create</ref>
739  </see-also>
740  </agi>
741  <agi name="speech load grammar" language="en_US">
742  <synopsis>
743  Loads a grammar.
744  </synopsis>
745  <syntax>
746  <parameter name="grammar name" required="true" />
747  <parameter name="path to grammar" required="true" />
748  </syntax>
749  <description>
750  <para>Loads the specified grammar as the specified name.</para>
751  </description>
752  </agi>
753  <agi name="speech unload grammar" language="en_US">
754  <synopsis>
755  Unloads a grammar.
756  </synopsis>
757  <syntax>
758  <parameter name="grammar name" required="true" />
759  </syntax>
760  <description>
761  <para>Unloads the specified grammar.</para>
762  </description>
763  </agi>
764  <agi name="speech activate grammar" language="en_US">
765  <synopsis>
766  Activates a grammar.
767  </synopsis>
768  <syntax>
769  <parameter name="grammar name" required="true" />
770  </syntax>
771  <description>
772  <para>Activates the specified grammar on the speech object.</para>
773  </description>
774  </agi>
775  <agi name="speech deactivate grammar" language="en_US">
776  <synopsis>
777  Deactivates a grammar.
778  </synopsis>
779  <syntax>
780  <parameter name="grammar name" required="true" />
781  </syntax>
782  <description>
783  <para>Deactivates the specified grammar on the speech object.</para>
784  </description>
785  </agi>
786  <agi name="speech recognize" language="en_US">
787  <synopsis>
788  Recognizes speech.
789  </synopsis>
790  <syntax>
791  <parameter name="prompt" required="true" />
792  <parameter name="timeout" required="true" />
793  <parameter name="offset" />
794  </syntax>
795  <description>
796  <para>Plays back given <replaceable>prompt</replaceable> while listening for
797  speech and dtmf.</para>
798  </description>
799  </agi>
800  <application name="AGI" language="en_US">
801  <synopsis>
802  Executes an AGI compliant application.
803  </synopsis>
804  <syntax>
805  <parameter name="command" required="true" />
806  <parameter name="args">
807  <argument name="arg1" required="true" />
808  <argument name="arg2" multiple="yes" />
809  </parameter>
810  </syntax>
811  <description>
812  <para>Executes an Asterisk Gateway Interface compliant
813  program on a channel. AGI allows Asterisk to launch external programs written
814  in any language to control a telephony channel, play audio, read DTMF digits,
815  etc. by communicating with the AGI protocol on <emphasis>stdin</emphasis> and
816  <emphasis>stdout</emphasis>. As of <literal>1.6.0</literal>, this channel will
817  not stop dialplan execution on hangup inside of this application. Dialplan
818  execution will continue normally, even upon hangup until the AGI application
819  signals a desire to stop (either by exiting or, in the case of a net script, by
820  closing the connection). A locally executed AGI script will receive SIGHUP on
821  hangup from the channel except when using DeadAGI. A fast AGI server will
822  correspondingly receive a HANGUP inline with the command dialog. Both of theses
823  signals may be disabled by setting the <variable>AGISIGHUP</variable> channel
824  variable to <literal>no</literal> before executing the AGI application.</para>
825  <para>Use the CLI command <literal>agi show commands</literal> to list available agi
826  commands.</para>
827  <para>This application sets the following channel variable upon completion:</para>
828  <variablelist>
829  <variable name="AGISTATUS">
830  <para>The status of the attempt to the run the AGI script
831  text string, one of:</para>
832  <value name="SUCCESS" />
833  <value name="FAILURE" />
834  <value name="NOTFOUND" />
835  <value name="HANGUP" />
836  </variable>
837  </variablelist>
838  </description>
839  <see-also>
840  <ref type="application">EAGI</ref>
841  <ref type="application">DeadAGI</ref>
842  </see-also>
843  </application>
844  <application name="EAGI" language="en_US">
845  <synopsis>
846  Executes an EAGI compliant application.
847  </synopsis>
848  <syntax>
849  <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='command'])" />
850  <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='args'])" />
851  </syntax>
852  <description>
853  <para>Using 'EAGI' provides enhanced AGI, with incoming audio available out of band
854  on file descriptor 3.</para>
855  <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/para)" />
856  <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/variablelist)" />
857  </description>
858  <see-also>
859  <ref type="application">AGI</ref>
860  <ref type="application">DeadAGI</ref>
861  </see-also>
862  </application>
863  <application name="DeadAGI" language="en_US">
864  <synopsis>
865  Executes AGI on a hungup channel.
866  </synopsis>
867  <syntax>
868  <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='command'])" />
869  <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='args'])" />
870  </syntax>
871  <description>
872  <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/para)" />
873  <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/variablelist)" />
874  </description>
875  <see-also>
876  <ref type="application">AGI</ref>
877  <ref type="application">EAGI</ref>
878  </see-also>
879  </application>
880  <manager name="AGI" language="en_US">
881  <synopsis>
882  Add an AGI command to execute by Async AGI.
883  </synopsis>
884  <syntax>
885  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
886  <parameter name="Channel" required="true">
887  <para>Channel that is currently in Async AGI.</para>
888  </parameter>
889  <parameter name="Command" required="true">
890  <para>Application to execute.</para>
891  </parameter>
892  <parameter name="CommandID">
893  <para>This will be sent back in CommandID header of AsyncAGI exec
894  event notification.</para>
895  </parameter>
896  </syntax>
897  <description>
898  <para>Add an AGI command to the execute queue of the channel in Async AGI.</para>
899  </description>
900  </manager>
901  ***/
902 
903 #define MAX_ARGS 128
904 #define MAX_CMD_LEN 80
905 #define AGI_NANDFS_RETRY 3
906 #define AGI_BUF_LEN 2048
907 #define SRV_PREFIX "_agi._tcp."
908 
909 static char *app = "AGI";
910 
911 static char *eapp = "EAGI";
912 
913 static char *deadapp = "DeadAGI";
914 
915 static int agidebug = 0;
916 
917 #define TONE_BLOCK_SIZE 200
918 
919 /* Max time to connect to an AGI remote host */
920 #define MAX_AGI_CONNECT 2000
921 
922 #define AGI_PORT 4573
923 
924 /*! Special return code for "asyncagi break" command. */
925 #define ASYNC_AGI_BREAK 3
926 
934 };
935 
936 static agi_command *find_command(const char * const cmds[], int exact);
937 
939 #define AGI_BUF_INITSIZE 256
940 
941 int AST_OPTIONAL_API_NAME(ast_agi_send)(int fd, struct ast_channel *chan, char *fmt, ...)
942 {
943  int res = 0;
944  va_list ap;
945  struct ast_str *buf;
946 
948  return -1;
949 
950  va_start(ap, fmt);
951  res = ast_str_set_va(&buf, 0, fmt, ap);
952  va_end(ap);
953 
954  if (res == -1) {
955  ast_log(LOG_ERROR, "Out of memory\n");
956  return -1;
957  }
958 
959  if (agidebug) {
960  if (chan) {
961  ast_verbose("<%s>AGI Tx >> %s", chan->name, ast_str_buffer(buf));
962  } else {
963  ast_verbose("AGI Tx >> %s", ast_str_buffer(buf));
964  }
965  }
966 
967  return ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
968 }
969 
970 /* linked list of AGI commands ready to be executed by Async AGI */
971 struct agi_cmd {
972  char *cmd_buffer;
973  char *cmd_id;
975 };
976 
977 static void free_agi_cmd(struct agi_cmd *cmd)
978 {
979  ast_free(cmd->cmd_buffer);
980  ast_free(cmd->cmd_id);
981  ast_free(cmd);
982 }
983 
984 /* AGI datastore destructor */
985 static void agi_destroy_commands_cb(void *data)
986 {
987  struct agi_cmd *cmd;
988  AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
989  AST_LIST_LOCK(chan_cmds);
990  while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
991  free_agi_cmd(cmd);
992  }
993  AST_LIST_UNLOCK(chan_cmds);
994  AST_LIST_HEAD_DESTROY(chan_cmds);
995  ast_free(chan_cmds);
996 }
997 
998 /* channel datastore to keep the queue of AGI commands in the channel */
1000  .type = "AsyncAGI",
1001  .destroy = agi_destroy_commands_cb
1002 };
1003 
1004 static struct agi_cmd *get_agi_cmd(struct ast_channel *chan)
1005 {
1006  struct ast_datastore *store;
1007  struct agi_cmd *cmd;
1009 
1010  ast_channel_lock(chan);
1012  ast_channel_unlock(chan);
1013  if (!store) {
1014  ast_log(LOG_ERROR, "Huh? Async AGI datastore disappeared on Channel %s!\n",
1015  chan->name);
1016  return NULL;
1017  }
1018  agi_commands = store->data;
1022  return cmd;
1023 }
1024 
1025 /* channel is locked when calling this one either from the CLI or manager thread */
1026 static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
1027 {
1028  struct ast_datastore *store;
1029  struct agi_cmd *cmd;
1031 
1033  if (!store) {
1034  ast_log(LOG_WARNING, "Channel %s is not setup for Async AGI.\n", chan->name);
1035  return -1;
1036  }
1037  agi_commands = store->data;
1038  cmd = ast_calloc(1, sizeof(*cmd));
1039  if (!cmd) {
1040  return -1;
1041  }
1042  cmd->cmd_buffer = ast_strdup(cmd_buff);
1043  if (!cmd->cmd_buffer) {
1044  ast_free(cmd);
1045  return -1;
1046  }
1047  cmd->cmd_id = ast_strdup(cmd_id);
1048  if (!cmd->cmd_id) {
1049  ast_free(cmd->cmd_buffer);
1050  ast_free(cmd);
1051  return -1;
1052  }
1056  return 0;
1057 }
1058 
1059 static int add_to_agi(struct ast_channel *chan)
1060 {
1061  struct ast_datastore *datastore;
1062  AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
1063 
1064  /* check if already on AGI */
1065  ast_channel_lock(chan);
1066  datastore = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
1067  ast_channel_unlock(chan);
1068  if (datastore) {
1069  /* we already have an AGI datastore, let's just
1070  return success */
1071  return 0;
1072  }
1073 
1074  /* the channel has never been on Async AGI,
1075  let's allocate it's datastore */
1076  datastore = ast_datastore_alloc(&agi_commands_datastore_info, "AGI");
1077  if (!datastore) {
1078  return -1;
1079  }
1080  agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
1081  if (!agi_cmds_list) {
1082  ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
1083  ast_datastore_free(datastore);
1084  return -1;
1085  }
1086  datastore->data = agi_cmds_list;
1087  AST_LIST_HEAD_INIT(agi_cmds_list);
1088  ast_channel_lock(chan);
1089  ast_channel_datastore_add(chan, datastore);
1090  ast_channel_unlock(chan);
1091  return 0;
1092 }
1093 
1094 /*!
1095  * \brief CLI command to add applications to execute in Async AGI
1096  * \param e
1097  * \param cmd
1098  * \param a
1099  *
1100  * \retval CLI_SUCCESS on success
1101  * \retval NULL when init or tab completion is used
1102 */
1103 static char *handle_cli_agi_add_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1104 {
1105  struct ast_channel *chan;
1106  switch (cmd) {
1107  case CLI_INIT:
1108  e->command = "agi exec";
1109  e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
1110  " Add AGI command to the execute queue of the specified channel in Async AGI\n";
1111  return NULL;
1112  case CLI_GENERATE:
1113  if (a->pos == 2)
1114  return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1115  return NULL;
1116  }
1117 
1118  if (a->argc < 4) {
1119  return CLI_SHOWUSAGE;
1120  }
1121 
1122  if (!(chan = ast_channel_get_by_name(a->argv[2]))) {
1123  ast_cli(a->fd, "Channel %s does not exist.\n", a->argv[2]);
1124  return CLI_FAILURE;
1125  }
1126 
1127  ast_channel_lock(chan);
1128 
1129  if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
1130  ast_cli(a->fd, "Failed to add AGI command to queue of channel %s\n", chan->name);
1131  ast_channel_unlock(chan);
1132  chan = ast_channel_unref(chan);
1133  return CLI_FAILURE;
1134  }
1135 
1136  ast_debug(1, "Added AGI command to channel %s queue\n", chan->name);
1137 
1138  ast_channel_unlock(chan);
1139  chan = ast_channel_unref(chan);
1140 
1141  return CLI_SUCCESS;
1142 }
1143 
1144 /*!
1145  * \brief Add a new command to execute by the Async AGI application
1146  * \param s
1147  * \param m
1148  *
1149  * It will append the application to the specified channel's queue
1150  * if the channel is not inside Async AGI application it will return an error
1151  * \retval 0 on success or incorrect use
1152  * \retval 1 on failure to add the command ( most likely because the channel
1153  * is not in Async AGI loop )
1154 */
1155 static int action_add_agi_cmd(struct mansession *s, const struct message *m)
1156 {
1157  const char *channel = astman_get_header(m, "Channel");
1158  const char *cmdbuff = astman_get_header(m, "Command");
1159  const char *cmdid = astman_get_header(m, "CommandID");
1160  struct ast_channel *chan;
1161  char buf[256];
1162 
1163  if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
1164  astman_send_error(s, m, "Both, Channel and Command are *required*");
1165  return 0;
1166  }
1167 
1168  if (!(chan = ast_channel_get_by_name(channel))) {
1169  snprintf(buf, sizeof(buf), "Channel %s does not exist.", channel);
1170  astman_send_error(s, m, buf);
1171  return 0;
1172  }
1173 
1174  ast_channel_lock(chan);
1175 
1176  if (add_agi_cmd(chan, cmdbuff, cmdid)) {
1177  snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", chan->name);
1178  astman_send_error(s, m, buf);
1179  ast_channel_unlock(chan);
1180  chan = ast_channel_unref(chan);
1181  return 0;
1182  }
1183 
1184  ast_channel_unlock(chan);
1185  chan = ast_channel_unref(chan);
1186 
1187  astman_send_ack(s, m, "Added AGI command to queue");
1188 
1189  return 0;
1190 }
1191 
1192 static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead);
1193 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[]);
1194 
1195 /*!
1196  * \internal
1197  * \brief Read and handle a channel frame for Async AGI.
1198  *
1199  * \param chan Channel to read a frame from.
1200  *
1201  * \retval AGI_RESULT_SUCCESS on success.
1202  * \retval AGI_RESULT_HANGUP on hangup.
1203  * \retval AGI_RESULT_FAILURE on error.
1204  */
1206 {
1207  struct ast_frame *f;
1208 
1209  f = ast_read(chan);
1210  if (!f) {
1211  ast_debug(3, "No frame read on channel %s, going out ...\n", chan->name);
1212  return AGI_RESULT_HANGUP;
1213  }
1214  if (f->frametype == AST_FRAME_CONTROL) {
1215  /*
1216  * Is there any other frame we should care about besides
1217  * AST_CONTROL_HANGUP?
1218  */
1219  switch (f->subclass.integer) {
1220  case AST_CONTROL_HANGUP:
1221  ast_debug(3, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
1222  ast_frfree(f);
1223  return AGI_RESULT_HANGUP;
1224  default:
1225  break;
1226  }
1227  }
1228  ast_frfree(f);
1229 
1230  return AGI_RESULT_SUCCESS;
1231 }
1232 
1233 static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], int *efd)
1234 {
1235 /* This buffer sizes might cause truncation if the AGI command writes more data
1236  than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command
1237  that writes a response larger than 1024 bytes?, I don't think so, most of
1238  them are just result=blah stuff. However probably if GET VARIABLE is called
1239  and the variable has large amount of data, that could be a problem. We could
1240  make this buffers dynamic, but let's leave that as a second step.
1241 
1242  AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe
1243  number. Some characters of AGI buf will be url encoded to be sent to manager
1244  clients. An URL encoded character will take 3 bytes, but again, to cause
1245  truncation more than about 70% of the AGI buffer should be URL encoded for
1246  that to happen. Not likely at all.
1247 
1248  On the other hand. I wonder if read() could eventually return less data than
1249  the amount already available in the pipe? If so, how to deal with that?
1250  So far, my tests on Linux have not had any problems.
1251  */
1252 #define AGI_BUF_SIZE 1024
1253 #define AMI_BUF_SIZE 2048
1254  enum agi_result cmd_status;
1255  struct agi_cmd *cmd;
1256  int res;
1257  int fds[2];
1258  int hungup;
1259  int timeout = 100;
1260  char agi_buffer[AGI_BUF_SIZE + 1];
1261  char ami_buffer[AMI_BUF_SIZE];
1262  enum agi_result returnstatus = AGI_RESULT_SUCCESS;
1263  AGI async_agi;
1264 
1265  if (efd) {
1266  ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
1267  return AGI_RESULT_FAILURE;
1268  }
1269 
1270  /* add AsyncAGI datastore to the channel */
1271  if (add_to_agi(chan)) {
1272  ast_log(LOG_ERROR, "Failed to start Async AGI on channel %s\n", chan->name);
1273  return AGI_RESULT_FAILURE;
1274  }
1275 
1276  /* this pipe allows us to create a "fake" AGI struct to use
1277  the AGI commands */
1278  res = pipe(fds);
1279  if (res) {
1280  ast_log(LOG_ERROR, "Failed to create Async AGI pipe\n");
1281  /*
1282  * Intentionally do not remove the datastore added with
1283  * add_to_agi() the from channel. It will be removed when the
1284  * channel is hung up anyway.
1285  */
1286  return AGI_RESULT_FAILURE;
1287  }
1288 
1289  /* handlers will get the pipe write fd and we read the AGI responses
1290  from the pipe read fd */
1291  async_agi.fd = fds[1];
1292  async_agi.ctrl = fds[1];
1293  async_agi.audio = -1; /* no audio support */
1294  async_agi.fast = 0;
1295  async_agi.speech = NULL;
1296 
1297  /* notify possible manager users of a new channel ready to
1298  receive commands */
1299  setup_env(chan, "async", fds[1], 0, 0, NULL);
1300  /* read the environment */
1301  res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
1302  if (res <= 0) {
1303  ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
1304  chan->name, res < 0 ? strerror(errno) : "EOF");
1305  returnstatus = AGI_RESULT_FAILURE;
1306  goto async_agi_abort;
1307  }
1308  agi_buffer[res] = '\0';
1309  /* encode it and send it thru the manager so whoever is going to take
1310  care of AGI commands on this channel can decide which AGI commands
1311  to execute based on the setup info */
1312  ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
1313  manager_event(EVENT_FLAG_AGI, "AsyncAGI",
1314  "SubEvent: Start\r\n"
1315  "Channel: %s\r\n"
1316  "Env: %s\r\n", chan->name, ami_buffer);
1317  hungup = ast_check_hangup(chan);
1318  for (;;) {
1319  /*
1320  * Process as many commands as we can. Commands are added via
1321  * the manager or the cli threads.
1322  */
1323  while (!hungup && (cmd = get_agi_cmd(chan))) {
1324  /* OK, we have a command, let's call the command handler. */
1325  cmd_status = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
1326 
1327  /*
1328  * The command handler must have written to our fake AGI struct
1329  * fd (the pipe), let's read the response.
1330  */
1331  res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
1332  if (res <= 0) {
1333  ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
1334  chan->name, res < 0 ? strerror(errno) : "EOF");
1335  free_agi_cmd(cmd);
1336  returnstatus = AGI_RESULT_FAILURE;
1337  goto async_agi_done;
1338  }
1339  /*
1340  * We have a response, let's send the response thru the manager.
1341  * Include the CommandID if it was specified when the command
1342  * was added.
1343  */
1344  agi_buffer[res] = '\0';
1345  ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
1346  if (ast_strlen_zero(cmd->cmd_id)) {
1347  manager_event(EVENT_FLAG_AGI, "AsyncAGI",
1348  "SubEvent: Exec\r\n"
1349  "Channel: %s\r\n"
1350  "Result: %s\r\n", chan->name, ami_buffer);
1351  } else {
1352  manager_event(EVENT_FLAG_AGI, "AsyncAGI",
1353  "SubEvent: Exec\r\n"
1354  "Channel: %s\r\n"
1355  "CommandID: %s\r\n"
1356  "Result: %s\r\n", chan->name, cmd->cmd_id, ami_buffer);
1357  }
1358  free_agi_cmd(cmd);
1359 
1360  /*
1361  * Check the command status to determine if we should continue
1362  * executing more commands.
1363  */
1364  hungup = ast_check_hangup(chan);
1365  switch (cmd_status) {
1366  case AGI_RESULT_FAILURE:
1367  if (!hungup) {
1368  /* The failure was not because of a hangup. */
1369  returnstatus = AGI_RESULT_FAILURE;
1370  goto async_agi_done;
1371  }
1372  break;
1374  /* Only the "asyncagi break" command does this. */
1375  returnstatus = AGI_RESULT_SUCCESS_ASYNC;
1376  goto async_agi_done;
1377  default:
1378  break;
1379  }
1380  }
1381 
1382  if (!hungup) {
1383  /* Wait a bit for a frame to read or to poll for a new command. */
1384  res = ast_waitfor(chan, timeout);
1385  if (res < 0) {
1386  ast_debug(1, "ast_waitfor returned <= 0 on chan %s\n", chan->name);
1387  returnstatus = AGI_RESULT_FAILURE;
1388  break;
1389  }
1390  } else {
1391  /*
1392  * Read the channel control queue until it is dry so we can
1393  * quit.
1394  */
1395  res = 1;
1396  }
1397  if (0 < res) {
1398  do {
1399  cmd_status = async_agi_read_frame(chan);
1400  if (cmd_status != AGI_RESULT_SUCCESS) {
1401  returnstatus = cmd_status;
1402  goto async_agi_done;
1403  }
1404  hungup = ast_check_hangup(chan);
1405  } while (hungup);
1406  } else {
1407  hungup = ast_check_hangup(chan);
1408  }
1409  }
1410 async_agi_done:
1411 
1412  if (async_agi.speech) {
1413  ast_speech_destroy(async_agi.speech);
1414  }
1415  /* notify manager users this channel cannot be
1416  controlled anymore by Async AGI */
1417  manager_event(EVENT_FLAG_AGI, "AsyncAGI",
1418  "SubEvent: End\r\n"
1419  "Channel: %s\r\n", chan->name);
1420 
1421 async_agi_abort:
1422  /* close the pipe */
1423  close(fds[0]);
1424  close(fds[1]);
1425 
1426  /*
1427  * Intentionally do not remove the datastore added with
1428  * add_to_agi() the from channel. There might be commands still
1429  * in the queue or in-flight to us and AsyncAGI may get called
1430  * again. The datastore destructor will be called on channel
1431  * destruction anyway.
1432  */
1433 
1434  if (returnstatus == AGI_RESULT_SUCCESS) {
1435  returnstatus = AGI_RESULT_SUCCESS_ASYNC;
1436  }
1437  return returnstatus;
1438 
1439 #undef AGI_BUF_SIZE
1440 #undef AMI_BUF_SIZE
1441 }
1442 
1443 /* launch_netscript: The fastagi handler.
1444  FastAGI defaults to port 4573 */
1445 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
1446 {
1447  int s, flags, res, port = AGI_PORT;
1448  struct pollfd pfds[1];
1449  char *host, *c, *script;
1450  struct sockaddr_in addr_in;
1451  struct hostent *hp;
1452  struct ast_hostent ahp;
1453 
1454  /* agiurl is "agi://host.domain[:port][/script/name]" */
1455  host = ast_strdupa(agiurl + 6); /* Remove agi:// */
1456  /* Strip off any script name */
1457  if ((script = strchr(host, '/'))) {
1458  *script++ = '\0';
1459  } else {
1460  script = "";
1461  }
1462 
1463  if ((c = strchr(host, ':'))) {
1464  *c++ = '\0';
1465  port = atoi(c);
1466  }
1467  if (!(hp = ast_gethostbyname(host, &ahp))) {
1468  ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
1469  return AGI_RESULT_FAILURE;
1470  }
1471  if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1472  ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1473  return AGI_RESULT_FAILURE;
1474  }
1475  if ((flags = fcntl(s, F_GETFL)) < 0) {
1476  ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
1477  close(s);
1478  return AGI_RESULT_FAILURE;
1479  }
1480  if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
1481  ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
1482  close(s);
1483  return AGI_RESULT_FAILURE;
1484  }
1485  memset(&addr_in, 0, sizeof(addr_in));
1486  addr_in.sin_family = AF_INET;
1487  addr_in.sin_port = htons(port);
1488  memcpy(&addr_in.sin_addr, hp->h_addr, sizeof(addr_in.sin_addr));
1489  if (connect(s, (struct sockaddr *)&addr_in, sizeof(addr_in)) && (errno != EINPROGRESS)) {
1490  ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
1491  close(s);
1492  return AGI_RESULT_FAILURE;
1493  }
1494 
1495  pfds[0].fd = s;
1496  pfds[0].events = POLLOUT;
1497  while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
1498  if (errno != EINTR) {
1499  if (!res) {
1500  ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
1501  agiurl, MAX_AGI_CONNECT);
1502  } else
1503  ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
1504  close(s);
1505  return AGI_RESULT_FAILURE;
1506  }
1507  }
1508 
1509  if (ast_agi_send(s, NULL, "agi_network: yes\n") < 0) {
1510  if (errno != EINTR) {
1511  ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
1512  close(s);
1513  return AGI_RESULT_FAILURE;
1514  }
1515  }
1516 
1517  /* If we have a script parameter, relay it to the fastagi server */
1518  /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
1519  if (!ast_strlen_zero(script))
1520  ast_agi_send(s, NULL, "agi_network_script: %s\n", script);
1521 
1522  ast_debug(4, "Wow, connected!\n");
1523  fds[0] = s;
1524  fds[1] = s;
1525  return AGI_RESULT_SUCCESS_FAST;
1526 }
1527 
1528 /*!
1529  * \internal
1530  * \brief The HA fastagi handler.
1531  * \param agiurl The request URL as passed to Agi() in the dial plan
1532  * \param argv The parameters after the URL passed to Agi() in the dial plan
1533  * \param fds Input/output file descriptors
1534  *
1535  * Uses SRV lookups to try to connect to a list of FastAGI servers. The hostname in
1536  * the URI is prefixed with _agi._tcp. prior to the DNS resolution. For
1537  * example, if you specify the URI \a hagi://agi.example.com/foo.agi the DNS
1538  * query would be for \a _agi._tcp.agi.example.com and you'll need to make sure
1539  * this resolves.
1540  *
1541  * This function parses the URI, resolves the SRV service name, forms new URIs
1542  * with the results of the DNS lookup, and then calls launch_netscript on the
1543  * new URIs until one succeeds.
1544  *
1545  * \return the result of the AGI operation.
1546  */
1547 static enum agi_result launch_ha_netscript(char *agiurl, char *argv[], int *fds)
1548 {
1549  char *host, *script;
1550  enum agi_result result;
1551  struct srv_context *context = NULL;
1552  int srv_ret;
1553  char service[256];
1554  char resolved_uri[1024];
1555  const char *srvhost;
1556  unsigned short srvport;
1557 
1558  /* format of agiurl is "hagi://host.domain[:port][/script/name]" */
1559  if (strlen(agiurl) < 7) { /* Remove hagi:// */
1560  ast_log(LOG_WARNING, "An error occurred parsing the AGI URI: %s", agiurl);
1561  return AGI_RESULT_FAILURE;
1562  }
1563  host = ast_strdupa(agiurl + 7);
1564 
1565  /* Strip off any script name */
1566  if ((script = strchr(host, '/'))) {
1567  *script++ = '\0';
1568  } else {
1569  script = "";
1570  }
1571 
1572  if (strchr(host, ':')) {
1573  ast_log(LOG_WARNING, "Specifying a port number disables SRV lookups: %s\n", agiurl);
1574  return launch_netscript(agiurl + 1, argv, fds); /* +1 to strip off leading h from hagi:// */
1575  }
1576 
1577  snprintf(service, sizeof(service), "%s%s", SRV_PREFIX, host);
1578 
1579  while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
1580  snprintf(resolved_uri, sizeof(resolved_uri), "agi://%s:%d/%s", srvhost, srvport, script);
1581  result = launch_netscript(resolved_uri, argv, fds);
1582  if (result == AGI_RESULT_FAILURE || result == AGI_RESULT_NOTFOUND) {
1583  ast_log(LOG_WARNING, "AGI request failed for host '%s' (%s:%d)\n", host, srvhost, srvport);
1584  } else {
1585  /* The script launched so we must cleanup the context. */
1586  ast_srv_cleanup(&context);
1587  return result;
1588  }
1589  }
1590  /*
1591  * The DNS SRV lookup failed or we ran out of servers to check.
1592  * ast_srv_lookup() has already cleaned up the context for us.
1593  */
1594  if (srv_ret < 0) {
1595  ast_log(LOG_WARNING, "SRV lookup failed for %s\n", agiurl);
1596  }
1597 
1598  return AGI_RESULT_FAILURE;
1599 }
1600 
1601 static enum agi_result launch_script(struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
1602 {
1603  char tmp[256];
1604  int pid, toast[2], fromast[2], audio[2], res;
1605  struct stat st;
1606 
1607  if (!strncasecmp(script, "agi://", 6)) {
1608  return (efd == NULL) ? launch_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
1609  }
1610  if (!strncasecmp(script, "hagi://", 7)) {
1611  return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
1612  }
1613  if (!strncasecmp(script, "agi:async", sizeof("agi:async") - 1)) {
1614  return launch_asyncagi(chan, argv, efd);
1615  }
1616 
1617  if (script[0] != '/') {
1618  snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
1619  script = tmp;
1620  }
1621 
1622  /* Before even trying let's see if the file actually exists */
1623  if (stat(script, &st)) {
1624  ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
1625  return AGI_RESULT_NOTFOUND;
1626  }
1627 
1628  if (pipe(toast)) {
1629  ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
1630  return AGI_RESULT_FAILURE;
1631  }
1632  if (pipe(fromast)) {
1633  ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
1634  close(toast[0]);
1635  close(toast[1]);
1636  return AGI_RESULT_FAILURE;
1637  }
1638  if (efd) {
1639  if (pipe(audio)) {
1640  ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
1641  close(fromast[0]);
1642  close(fromast[1]);
1643  close(toast[0]);
1644  close(toast[1]);
1645  return AGI_RESULT_FAILURE;
1646  }
1647  res = fcntl(audio[1], F_GETFL);
1648  if (res > -1)
1649  res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
1650  if (res < 0) {
1651  ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
1652  close(fromast[0]);
1653  close(fromast[1]);
1654  close(toast[0]);
1655  close(toast[1]);
1656  close(audio[0]);
1657  close(audio[1]);
1658  return AGI_RESULT_FAILURE;
1659  }
1660  }
1661 
1662  if ((pid = ast_safe_fork(1)) < 0) {
1663  ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
1664  return AGI_RESULT_FAILURE;
1665  }
1666  if (!pid) {
1667  /* Pass paths to AGI via environmental variables */
1668  setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
1669  setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
1670  setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
1671  setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
1672  setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
1673  setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
1674  setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
1675  setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
1676  setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
1677  setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
1678  setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
1679 
1680  /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
1681  ast_set_priority(0);
1682 
1683  /* Redirect stdin and out, provide enhanced audio channel if desired */
1684  dup2(fromast[0], STDIN_FILENO);
1685  dup2(toast[1], STDOUT_FILENO);
1686  if (efd)
1687  dup2(audio[0], STDERR_FILENO + 1);
1688  else
1689  close(STDERR_FILENO + 1);
1690 
1691  /* Close everything but stdin/out/error */
1692  ast_close_fds_above_n(STDERR_FILENO + 1);
1693 
1694  /* Execute script */
1695  /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
1696  execv(script, argv);
1697  /* Can't use ast_log since FD's are closed */
1698  ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
1699  /* Special case to set status of AGI to failure */
1700  fprintf(stdout, "failure\n");
1701  fflush(stdout);
1702  _exit(1);
1703  }
1704  ast_verb(3, "Launched AGI Script %s\n", script);
1705  fds[0] = toast[0];
1706  fds[1] = fromast[1];
1707  if (efd)
1708  *efd = audio[1];
1709  /* close what we're not using in the parent */
1710  close(toast[1]);
1711  close(fromast[0]);
1712 
1713  if (efd)
1714  close(audio[0]);
1715 
1716  *opid = pid;
1717  return AGI_RESULT_SUCCESS;
1718 }
1719 
1720 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
1721 {
1722  int count;
1723 
1724  /* Print initial environment, with agi_request always being the first
1725  thing */
1726  ast_agi_send(fd, chan, "agi_request: %s\n", request);
1727  ast_agi_send(fd, chan, "agi_channel: %s\n", chan->name);
1728  ast_agi_send(fd, chan, "agi_language: %s\n", chan->language);
1729  ast_agi_send(fd, chan, "agi_type: %s\n", chan->tech->type);
1730  ast_agi_send(fd, chan, "agi_uniqueid: %s\n", chan->uniqueid);
1731  ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version());
1732 
1733  /* ANI/DNIS */
1734  ast_agi_send(fd, chan, "agi_callerid: %s\n",
1735  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "unknown"));
1736  ast_agi_send(fd, chan, "agi_calleridname: %s\n",
1737  S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "unknown"));
1738  ast_agi_send(fd, chan, "agi_callingpres: %d\n",
1740  ast_agi_send(fd, chan, "agi_callingani2: %d\n", chan->caller.ani2);
1741  ast_agi_send(fd, chan, "agi_callington: %d\n", chan->caller.id.number.plan);
1742  ast_agi_send(fd, chan, "agi_callingtns: %d\n", chan->dialed.transit_network_select);
1743  ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(chan->dialed.number.str, "unknown"));
1744  ast_agi_send(fd, chan, "agi_rdnis: %s\n",
1745  S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, "unknown"));
1746 
1747  /* Context information */
1748  ast_agi_send(fd, chan, "agi_context: %s\n", chan->context);
1749  ast_agi_send(fd, chan, "agi_extension: %s\n", chan->exten);
1750  ast_agi_send(fd, chan, "agi_priority: %d\n", chan->priority);
1751  ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
1752 
1753  /* User information */
1754  ast_agi_send(fd, chan, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
1755  ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self());
1756 
1757  /* Send any parameters to the fastagi server that have been passed via the agi application */
1758  /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
1759  for(count = 1; count < argc; count++)
1760  ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]);
1761 
1762  /* End with empty return */
1763  ast_agi_send(fd, chan, "\n");
1764 }
1765 
1766 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
1767 {
1768  int res = 0;
1769 
1770  /* Answer the channel */
1771  if (chan->_state != AST_STATE_UP)
1772  res = ast_answer(chan);
1773 
1774  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1775  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1776 }
1777 
1778 static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
1779 {
1780  ast_agi_send(agi->fd, chan, "200 result=0\n");
1781  return ASYNC_AGI_BREAK;
1782 }
1783 
1784 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
1785 {
1786  int res, to;
1787 
1788  if (argc != 4)
1789  return RESULT_SHOWUSAGE;
1790  if (sscanf(argv[3], "%30d", &to) != 1)
1791  return RESULT_SHOWUSAGE;
1792  res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
1793  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1794  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1795 }
1796 
1797 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
1798 {
1799  int res;
1800 
1801  if (argc != 3)
1802  return RESULT_SHOWUSAGE;
1803 
1804  /* At the moment, the parser (perhaps broken) returns with
1805  the last argument PLUS the newline at the end of the input
1806  buffer. This probably needs to be fixed, but I wont do that
1807  because other stuff may break as a result. The right way
1808  would probably be to strip off the trailing newline before
1809  parsing, then here, add a newline at the end of the string
1810  before sending it to ast_sendtext --DUDE */
1811  res = ast_sendtext(chan, argv[2]);
1812  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1813  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1814 }
1815 
1816 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
1817 {
1818  int res;
1819 
1820  if (argc != 3)
1821  return RESULT_SHOWUSAGE;
1822 
1823  res = ast_recvchar(chan,atoi(argv[2]));
1824  if (res == 0) {
1825  ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res);
1826  return RESULT_SUCCESS;
1827  }
1828  if (res > 0) {
1829  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1830  return RESULT_SUCCESS;
1831  }
1832  ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res);
1833  return RESULT_FAILURE;
1834 }
1835 
1836 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
1837 {
1838  char *buf;
1839 
1840  if (argc != 3)
1841  return RESULT_SHOWUSAGE;
1842 
1843  buf = ast_recvtext(chan, atoi(argv[2]));
1844  if (buf) {
1845  ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf);
1846  ast_free(buf);
1847  } else {
1848  ast_agi_send(agi->fd, chan, "200 result=-1\n");
1849  }
1850  return RESULT_SUCCESS;
1851 }
1852 
1853 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
1854 {
1855  int res, x;
1856 
1857  if (argc != 3)
1858  return RESULT_SHOWUSAGE;
1859 
1860  if (!strncasecmp(argv[2],"on",2)) {
1861  x = 1;
1862  } else {
1863  x = 0;
1864  }
1865  if (!strncasecmp(argv[2],"mate",4)) {
1866  x = 2;
1867  }
1868  if (!strncasecmp(argv[2],"tdd",3)) {
1869  x = 1;
1870  }
1871  res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
1872  if (res) {
1873  /* Set channel option failed */
1874  ast_agi_send(agi->fd, chan, "200 result=0\n");
1875  } else {
1876  ast_agi_send(agi->fd, chan, "200 result=1\n");
1877  }
1878  return RESULT_SUCCESS;
1879 }
1880 
1881 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
1882 {
1883  int res;
1884 
1885  if (argc != 3) {
1886  return RESULT_SHOWUSAGE;
1887  }
1888 
1889  res = ast_send_image(chan, argv[2]);
1890  if (!ast_check_hangup(chan)) {
1891  res = 0;
1892  }
1893  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1894  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1895 }
1896 
1897 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
1898 {
1899  int res = 0, skipms = 3000;
1900  const char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */
1901 
1902  if (argc < 5 || argc > 9) {
1903  return RESULT_SHOWUSAGE;
1904  }
1905 
1906  if (!ast_strlen_zero(argv[4])) {
1907  stop = argv[4];
1908  }
1909 
1910  if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) {
1911  return RESULT_SHOWUSAGE;
1912  }
1913 
1914  if (argc > 6 && !ast_strlen_zero(argv[6])) {
1915  fwd = argv[6];
1916  }
1917 
1918  if (argc > 7 && !ast_strlen_zero(argv[7])) {
1919  rev = argv[7];
1920  }
1921 
1922  if (argc > 8 && !ast_strlen_zero(argv[8])) {
1923  suspend = argv[8];
1924  }
1925 
1926  res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, NULL);
1927 
1928  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1929 
1930  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1931 }
1932 
1933 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
1934 {
1935  int res;
1936  struct ast_filestream *fs, *vfs;
1937  long sample_offset = 0, max_length;
1938  const char *edigits = "";
1939 
1940  if (argc < 4 || argc > 5)
1941  return RESULT_SHOWUSAGE;
1942 
1943  if (argv[3])
1944  edigits = argv[3];
1945 
1946  if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1))
1947  return RESULT_SHOWUSAGE;
1948 
1949  if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
1950  ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
1951  return RESULT_FAILURE;
1952  }
1953 
1954  if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
1955  ast_debug(1, "Ooh, found a video stream, too\n");
1956 
1957  ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
1958 
1959  ast_seekstream(fs, 0, SEEK_END);
1960  max_length = ast_tellstream(fs);
1961  ast_seekstream(fs, sample_offset, SEEK_SET);
1962  res = ast_applystream(chan, fs);
1963  if (vfs)
1964  ast_applystream(chan, vfs);
1965  ast_playstream(fs);
1966  if (vfs)
1967  ast_playstream(vfs);
1968 
1969  res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
1970  /* this is to check for if ast_waitstream closed the stream, we probably are at
1971  * the end of the stream, return that amount, else check for the amount */
1972  sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
1973  ast_stopstream(chan);
1974  if (res == 1) {
1975  /* Stop this command, don't print a result line, as there is a new command */
1976  return RESULT_SUCCESS;
1977  }
1978  ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
1979  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1980 }
1981 
1982 /*! \brief get option - really similar to the handle_streamfile, but with a timeout */
1983 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
1984 {
1985  int res;
1986  struct ast_filestream *fs, *vfs;
1987  long sample_offset = 0, max_length;
1988  int timeout = 0;
1989  const char *edigits = "";
1990 
1991  if ( argc < 4 || argc > 5 )
1992  return RESULT_SHOWUSAGE;
1993 
1994  if ( argv[3] )
1995  edigits = argv[3];
1996 
1997  if ( argc == 5 )
1998  timeout = atoi(argv[4]);
1999  else if (chan->pbx->dtimeoutms) {
2000  /* by default dtimeout is set to 5sec */
2001  timeout = chan->pbx->dtimeoutms; /* in msec */
2002  }
2003 
2004  if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
2005  ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
2006  ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
2007  return RESULT_FAILURE;
2008  }
2009 
2010  if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
2011  ast_debug(1, "Ooh, found a video stream, too\n");
2012 
2013  ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
2014 
2015  ast_seekstream(fs, 0, SEEK_END);
2016  max_length = ast_tellstream(fs);
2017  ast_seekstream(fs, sample_offset, SEEK_SET);
2018  res = ast_applystream(chan, fs);
2019  if (vfs)
2020  ast_applystream(chan, vfs);
2021  ast_playstream(fs);
2022  if (vfs)
2023  ast_playstream(vfs);
2024 
2025  res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
2026  /* this is to check for if ast_waitstream closed the stream, we probably are at
2027  * the end of the stream, return that amount, else check for the amount */
2028  sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
2029  ast_stopstream(chan);
2030  if (res == 1) {
2031  /* Stop this command, don't print a result line, as there is a new command */
2032  return RESULT_SUCCESS;
2033  }
2034 
2035  /* If the user didnt press a key, wait for digitTimeout*/
2036  if (res == 0 ) {
2037  res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
2038  /* Make sure the new result is in the escape digits of the GET OPTION */
2039  if ( !strchr(edigits,res) )
2040  res=0;
2041  }
2042 
2043  ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
2044  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2045 }
2046 
2047 
2048 
2049 
2050 /*! \brief Say number in various language syntaxes */
2051 /* While waiting, we're sending a NULL. */
2052 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2053 {
2054  int res, num;
2055 
2056  if (argc < 4 || argc > 5)
2057  return RESULT_SHOWUSAGE;
2058  if (sscanf(argv[2], "%30d", &num) != 1)
2059  return RESULT_SHOWUSAGE;
2060  res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
2061  if (res == 1)
2062  return RESULT_SUCCESS;
2063  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2064  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2065 }
2066 
2067 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2068 {
2069  int res, num;
2070 
2071  if (argc != 4)
2072  return RESULT_SHOWUSAGE;
2073  if (sscanf(argv[2], "%30d", &num) != 1)
2074  return RESULT_SHOWUSAGE;
2075 
2076  res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
2077  if (res == 1) /* New command */
2078  return RESULT_SUCCESS;
2079  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2080  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2081 }
2082 
2083 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2084 {
2085  int res;
2086 
2087  if (argc != 4)
2088  return RESULT_SHOWUSAGE;
2089 
2090  res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
2091  if (res == 1) /* New command */
2092  return RESULT_SUCCESS;
2093  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2094  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2095 }
2096 
2097 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2098 {
2099  int res, num;
2100 
2101  if (argc != 4)
2102  return RESULT_SHOWUSAGE;
2103  if (sscanf(argv[2], "%30d", &num) != 1)
2104  return RESULT_SHOWUSAGE;
2105  res = ast_say_date(chan, num, argv[3], chan->language);
2106  if (res == 1)
2107  return RESULT_SUCCESS;
2108  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2109  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2110 }
2111 
2112 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2113 {
2114  int res, num;
2115 
2116  if (argc != 4)
2117  return RESULT_SHOWUSAGE;
2118  if (sscanf(argv[2], "%30d", &num) != 1)
2119  return RESULT_SHOWUSAGE;
2120  res = ast_say_time(chan, num, argv[3], chan->language);
2121  if (res == 1)
2122  return RESULT_SUCCESS;
2123  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2124  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2125 }
2126 
2127 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2128 {
2129  int res = 0;
2130  time_t unixtime;
2131  const char *format, *zone = NULL;
2132 
2133  if (argc < 4)
2134  return RESULT_SHOWUSAGE;
2135 
2136  if (argc > 4) {
2137  format = argv[4];
2138  } else {
2139  /* XXX this doesn't belong here, but in the 'say' module */
2140  if (!strcasecmp(chan->language, "de")) {
2141  format = "A dBY HMS";
2142  } else {
2143  format = "ABdY 'digits/at' IMp";
2144  }
2145  }
2146 
2147  if (argc > 5 && !ast_strlen_zero(argv[5]))
2148  zone = argv[5];
2149 
2150  if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
2151  return RESULT_SHOWUSAGE;
2152 
2153  res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
2154  if (res == 1)
2155  return RESULT_SUCCESS;
2156 
2157  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2158  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2159 }
2160 
2161 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2162 {
2163  int res;
2164 
2165  if (argc != 4)
2166  return RESULT_SHOWUSAGE;
2167 
2168  res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
2169  if (res == 1) /* New command */
2170  return RESULT_SUCCESS;
2171  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2172  return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2173 }
2174 
2175 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2176 {
2177  int res, max, timeout;
2178  char data[1024];
2179 
2180  if (argc < 3)
2181  return RESULT_SHOWUSAGE;
2182  if (argc >= 4)
2183  timeout = atoi(argv[3]);
2184  else
2185  timeout = 0;
2186  if (argc >= 5)
2187  max = atoi(argv[4]);
2188  else
2189  max = 1024;
2190  res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
2191  if (res == 2) /* New command */
2192  return RESULT_SUCCESS;
2193  else if (res == 1)
2194  ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
2195  else if (res < 0 )
2196  ast_agi_send(agi->fd, chan, "200 result=-1\n");
2197  else
2198  ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
2199  return RESULT_SUCCESS;
2200 }
2201 
2202 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2203 {
2204 
2205  if (argc != 3)
2206  return RESULT_SHOWUSAGE;
2207  ast_copy_string(chan->context, argv[2], sizeof(chan->context));
2208  ast_agi_send(agi->fd, chan, "200 result=0\n");
2209  return RESULT_SUCCESS;
2210 }
2211 
2212 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2213 {
2214  if (argc != 3)
2215  return RESULT_SHOWUSAGE;
2216  ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
2217  ast_agi_send(agi->fd, chan, "200 result=0\n");
2218  return RESULT_SUCCESS;
2219 }
2220 
2221 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2222 {
2223  int pri;
2224 
2225  if (argc != 3)
2226  return RESULT_SHOWUSAGE;
2227 
2228  if (sscanf(argv[2], "%30d", &pri) != 1) {
2229  pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2],
2230  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
2231  if (pri < 1)
2232  return RESULT_SHOWUSAGE;
2233  }
2234 
2235  ast_explicit_goto(chan, NULL, NULL, pri);
2236  ast_agi_send(agi->fd, chan, "200 result=0\n");
2237  return RESULT_SUCCESS;
2238 }
2239 
2240 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2241 {
2242  struct ast_filestream *fs;
2243  struct ast_frame *f;
2244  struct timeval start;
2245  long sample_offset = 0;
2246  int res = 0;
2247  int ms;
2248 
2249  struct ast_dsp *sildet=NULL; /* silence detector dsp */
2250  int totalsilence = 0;
2251  int dspsilence = 0;
2252  int silence = 0; /* amount of silence to allow */
2253  int gotsilence = 0; /* did we timeout for silence? */
2254  char *silencestr = NULL;
2255  int rfmt = 0;
2256 
2257  /* XXX EAGI FIXME XXX */
2258 
2259  if (argc < 6)
2260  return RESULT_SHOWUSAGE;
2261  if (sscanf(argv[5], "%30d", &ms) != 1)
2262  return RESULT_SHOWUSAGE;
2263 
2264  if (argc > 6)
2265  silencestr = strchr(argv[6],'s');
2266  if ((argc > 7) && (!silencestr))
2267  silencestr = strchr(argv[7],'s');
2268  if ((argc > 8) && (!silencestr))
2269  silencestr = strchr(argv[8],'s');
2270 
2271  if (silencestr) {
2272  if (strlen(silencestr) > 2) {
2273  if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
2274  silencestr++;
2275  silencestr++;
2276  if (silencestr)
2277  silence = atoi(silencestr);
2278  if (silence > 0)
2279  silence *= 1000;
2280  }
2281  }
2282  }
2283 
2284  if (silence > 0) {
2285  rfmt = chan->readformat;
2287  if (res < 0) {
2288  ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
2289  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2290  return RESULT_FAILURE;
2291  }
2292  sildet = ast_dsp_new();
2293  if (!sildet) {
2294  ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
2295  ast_agi_send(agi->fd, chan, "200 result=-1\n");
2296  return RESULT_FAILURE;
2297  }
2299  }
2300 
2301  /* backward compatibility, if no offset given, arg[6] would have been
2302  * caught below and taken to be a beep, else if it is a digit then it is a
2303  * offset */
2304  if ((argc >6) && (sscanf(argv[6], "%30ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
2305  res = ast_streamfile(chan, "beep", chan->language);
2306 
2307  if ((argc > 7) && (!strchr(argv[7], '=')))
2308  res = ast_streamfile(chan, "beep", chan->language);
2309 
2310  if (!res)
2311  res = ast_waitstream(chan, argv[4]);
2312  if (res) {
2313  ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
2314  } else {
2315  fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
2316  if (!fs) {
2317  res = -1;
2318  ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
2319  if (sildet)
2320  ast_dsp_free(sildet);
2321  return RESULT_FAILURE;
2322  }
2323 
2324  /* Request a video update */
2326 
2327  chan->stream = fs;
2328  ast_applystream(chan,fs);
2329  /* really should have checks */
2330  ast_seekstream(fs, sample_offset, SEEK_SET);
2331  ast_truncstream(fs);
2332 
2333  start = ast_tvnow();
2334  while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
2335  res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start));
2336  if (res < 0) {
2337  ast_closestream(fs);
2338  ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
2339  if (sildet)
2340  ast_dsp_free(sildet);
2341  return RESULT_FAILURE;
2342  }
2343  f = ast_read(chan);
2344  if (!f) {
2345  ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
2346  ast_closestream(fs);
2347  if (sildet)
2348  ast_dsp_free(sildet);
2349  return RESULT_FAILURE;
2350  }
2351  switch(f->frametype) {
2352  case AST_FRAME_DTMF:
2353  if (strchr(argv[4], f->subclass.integer)) {
2354  /* This is an interrupting chracter, so rewind to chop off any small
2355  amount of DTMF that may have been recorded
2356  */
2357  ast_stream_rewind(fs, 200);
2358  ast_truncstream(fs);
2359  sample_offset = ast_tellstream(fs);
2360  ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset);
2361  ast_closestream(fs);
2362  ast_frfree(f);
2363  if (sildet)
2364  ast_dsp_free(sildet);
2365  return RESULT_SUCCESS;
2366  }
2367  break;
2368  case AST_FRAME_VOICE:
2369  ast_writestream(fs, f);
2370  /* this is a safe place to check progress since we know that fs
2371  * is valid after a write, and it will then have our current
2372  * location */
2373  sample_offset = ast_tellstream(fs);
2374  if (silence > 0) {
2375  dspsilence = 0;
2376  ast_dsp_silence(sildet, f, &dspsilence);
2377  if (dspsilence) {
2378  totalsilence = dspsilence;
2379  } else {
2380  totalsilence = 0;
2381  }
2382  if (totalsilence > silence) {
2383  /* Ended happily with silence */
2384  gotsilence = 1;
2385  break;
2386  }
2387  }
2388  break;
2389  case AST_FRAME_VIDEO:
2390  ast_writestream(fs, f);
2391  default:
2392  /* Ignore all other frames */
2393  break;
2394  }
2395  ast_frfree(f);
2396  if (gotsilence)
2397  break;
2398  }
2399 
2400  if (gotsilence) {
2401  ast_stream_rewind(fs, silence-1000);
2402  ast_truncstream(fs);
2403  sample_offset = ast_tellstream(fs);
2404  }
2405  ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
2406  ast_closestream(fs);
2407  }
2408 
2409  if (silence > 0) {
2410  res = ast_set_read_format(chan, rfmt);
2411  if (res)
2412  ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
2413  ast_dsp_free(sildet);
2414  }
2415 
2416  return RESULT_SUCCESS;
2417 }
2418 
2419 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2420 {
2421  double timeout;
2422  struct timeval whentohangup = { 0, 0 };
2423 
2424  if (argc != 3)
2425  return RESULT_SHOWUSAGE;
2426  if (sscanf(argv[2], "%30lf", &timeout) != 1)
2427  return RESULT_SHOWUSAGE;
2428  if (timeout < 0)
2429  timeout = 0;
2430  if (timeout) {
2431  whentohangup.tv_sec = timeout;
2432  whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
2433  }
2434  ast_channel_setwhentohangup_tv(chan, whentohangup);
2435  ast_agi_send(agi->fd, chan, "200 result=0\n");
2436  return RESULT_SUCCESS;
2437 }
2438 
2439 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2440 {
2441  struct ast_channel *c;
2442 
2443  if (argc == 1) {
2444  /* no argument: hangup the current channel */
2445  ast_set_hangupsource(chan, "dialplan/agi", 0);
2447  ast_agi_send(agi->fd, chan, "200 result=1\n");
2448  return RESULT_SUCCESS;
2449  } else if (argc == 2) {
2450  /* one argument: look for info on the specified channel */
2451  if ((c = ast_channel_get_by_name(argv[1]))) {
2452  /* we have a matching channel */
2453  ast_set_hangupsource(c, "dialplan/agi", 0);
2455  c = ast_channel_unref(c);
2456  ast_agi_send(agi->fd, chan, "200 result=1\n");
2457  return RESULT_SUCCESS;
2458  }
2459  /* if we get this far no channel name matched the argument given */
2460  ast_agi_send(agi->fd, chan, "200 result=-1\n");
2461  return RESULT_SUCCESS;
2462  } else {
2463  return RESULT_SHOWUSAGE;
2464  }
2465 }
2466 
2467 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2468 {
2469  int res, workaround;
2470  struct ast_app *app_to_exec;
2471 
2472  if (argc < 2)
2473  return RESULT_SHOWUSAGE;
2474 
2475  ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
2476 
2477  if ((app_to_exec = pbx_findapp(argv[1]))) {
2478  if (!(workaround = ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS))) {
2480  }
2481  if (ast_compat_res_agi && argc >= 3 && !ast_strlen_zero(argv[2])) {
2482  char *compat = ast_alloca(strlen(argv[2]) * 2 + 1), *cptr;
2483  const char *vptr;
2484  for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
2485  if (*vptr == ',') {
2486  *cptr++ = '\\';
2487  *cptr++ = ',';
2488  } else if (*vptr == '|') {
2489  *cptr++ = ',';
2490  } else {
2491  *cptr++ = *vptr;
2492  }
2493  }
2494  *cptr = '\0';
2495  res = pbx_exec(chan, app_to_exec, compat);
2496  } else {
2497  res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
2498  }
2499  if (!workaround) {
2501  }
2502  } else {
2503  ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
2504  res = -2;
2505  }
2506  ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2507 
2508  /* Even though this is wrong, users are depending upon this result. */
2509  return res;
2510 }
2511 
2512 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2513 {
2514  char tmp[256]="";
2515  char *l = NULL, *n = NULL;
2516 
2517  if (argv[2]) {
2518  ast_copy_string(tmp, argv[2], sizeof(tmp));
2519  ast_callerid_parse(tmp, &n, &l);
2520  if (l)
2522  else
2523  l = "";
2524  if (!n)
2525  n = "";
2526  ast_set_callerid(chan, l, n, NULL);
2527  }
2528 
2529  ast_agi_send(agi->fd, chan, "200 result=1\n");
2530  return RESULT_SUCCESS;
2531 }
2532 
2533 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2534 {
2535  struct ast_channel *c;
2536  if (argc == 2) {
2537  /* no argument: supply info on the current channel */
2538  ast_agi_send(agi->fd, chan, "200 result=%u\n", chan->_state);
2539  return RESULT_SUCCESS;
2540  } else if (argc == 3) {
2541  /* one argument: look for info on the specified channel */
2542  if ((c = ast_channel_get_by_name(argv[2]))) {
2543  ast_agi_send(agi->fd, chan, "200 result=%u\n", c->_state);
2544  c = ast_channel_unref(c);
2545  return RESULT_SUCCESS;
2546  }
2547  /* if we get this far no channel name matched the argument given */
2548  ast_agi_send(agi->fd, chan, "200 result=-1\n");
2549  return RESULT_SUCCESS;
2550  } else {
2551  return RESULT_SHOWUSAGE;
2552  }
2553 }
2554 
2555 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2556 {
2557  if (argv[3])
2558  pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
2559 
2560  ast_agi_send(agi->fd, chan, "200 result=1\n");
2561  return RESULT_SUCCESS;
2562 }
2563 
2564 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2565 {
2566  char *ret;
2567  char tempstr[1024] = "";
2568 
2569  if (argc != 3)
2570  return RESULT_SHOWUSAGE;
2571 
2572  /* check if we want to execute an ast_custom_function */
2573  if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
2574  ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
2575  } else {
2576  pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
2577  }
2578 
2579  if (ret)
2580  ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
2581  else
2582  ast_agi_send(agi->fd, chan, "200 result=0\n");
2583 
2584  return RESULT_SUCCESS;
2585 }
2586 
2587 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2588 {
2589  struct ast_channel *chan2 = NULL;
2590 
2591  if (argc != 4 && argc != 5) {
2592  return RESULT_SHOWUSAGE;
2593  }
2594 
2595  if (argc == 5) {
2596  chan2 = ast_channel_get_by_name(argv[4]);
2597  } else {
2598  chan2 = ast_channel_ref(chan);
2599  }
2600 
2601  if (chan2) {
2602  struct ast_str *str = ast_str_create(16);
2603  if (!str) {
2604  ast_agi_send(agi->fd, chan, "200 result=0\n");
2605  return RESULT_SUCCESS;
2606  }
2607  ast_str_substitute_variables(&str, 0, chan2, argv[3]);
2608  ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(str));
2609  ast_free(str);
2610  } else {
2611  ast_agi_send(agi->fd, chan, "200 result=0\n");
2612  }
2613 
2614  if (chan2) {
2615  chan2 = ast_channel_unref(chan2);
2616  }
2617 
2618  return RESULT_SUCCESS;
2619 }
2620 
2621 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2622 {
2623  int level = 0;
2624 
2625  if (argc < 2)
2626  return RESULT_SHOWUSAGE;
2627 
2628  if (argv[2])
2629  sscanf(argv[2], "%30d", &level);
2630 
2631  ast_verb(level, "%s: %s\n", chan->data, argv[1]);
2632 
2633  ast_agi_send(agi->fd, chan, "200 result=1\n");
2634 
2635  return RESULT_SUCCESS;
2636 }
2637 
2638 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2639 {
2640  int res;
2641  struct ast_str *buf;
2642 
2643  if (argc != 4)
2644  return RESULT_SHOWUSAGE;
2645 
2646  if (!(buf = ast_str_create(16))) {
2647  ast_agi_send(agi->fd, chan, "200 result=-1\n");
2648  return RESULT_SUCCESS;
2649  }
2650 
2651  do {
2652  res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
2653  ast_str_update(buf);
2654  if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
2655  break;
2656  }
2657  if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
2658  break;
2659  }
2660  } while (1);
2661 
2662  if (res)
2663  ast_agi_send(agi->fd, chan, "200 result=0\n");
2664  else
2665  ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
2666 
2667  ast_free(buf);
2668  return RESULT_SUCCESS;
2669 }
2670 
2671 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2672 {
2673  int res;
2674 
2675  if (argc != 5)
2676  return RESULT_SHOWUSAGE;
2677  res = ast_db_put(argv[2], argv[3], argv[4]);
2678  ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
2679  return RESULT_SUCCESS;
2680 }
2681 
2682 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2683 {
2684  int res;
2685 
2686  if (argc != 4)
2687  return RESULT_SHOWUSAGE;
2688  res = ast_db_del(argv[2], argv[3]);
2689  ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
2690  return RESULT_SUCCESS;
2691 }
2692 
2693 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2694 {
2695  int num_deleted;
2696 
2697  if ((argc < 3) || (argc > 4)) {
2698  return RESULT_SHOWUSAGE;
2699  }
2700  if (argc == 4) {
2701  num_deleted = ast_db_deltree(argv[2], argv[3]);
2702  } else {
2703  num_deleted = ast_db_deltree(argv[2], NULL);
2704  }
2705 
2706  ast_agi_send(agi->fd, chan, "200 result=%c\n", num_deleted > 0 ? '0' : '1');
2707  return RESULT_SUCCESS;
2708 }
2709 
2710 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2711 {
2712  switch (cmd) {
2713  case CLI_INIT:
2714  e->command = "agi set debug [on|off]";
2715  e->usage =
2716  "Usage: agi set debug [on|off]\n"
2717  " Enables/disables dumping of AGI transactions for\n"
2718  " debugging purposes.\n";
2719  return NULL;
2720 
2721  case CLI_GENERATE:
2722  return NULL;
2723  }
2724 
2725  if (a->argc != e->args)
2726  return CLI_SHOWUSAGE;
2727 
2728  if (strncasecmp(a->argv[3], "off", 3) == 0) {
2729  agidebug = 0;
2730  } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
2731  agidebug = 1;
2732  } else {
2733  return CLI_SHOWUSAGE;
2734  }
2735  ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
2736  return CLI_SUCCESS;
2737 }
2738 
2739 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, const char * const argv[])
2740 {
2741  ast_agi_send(agi->fd, chan, "200 result=0\n");
2742  return RESULT_SUCCESS;
2743 }
2744 
2745 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2746 {
2747  if (argc < 3) {
2748  return RESULT_SHOWUSAGE;
2749  }
2750  if (!strncasecmp(argv[2], "on", 2))
2751  ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
2752  else if (!strncasecmp(argv[2], "off", 3))
2753  ast_moh_stop(chan);
2754  ast_agi_send(agi->fd, chan, "200 result=0\n");
2755  return RESULT_SUCCESS;
2756 }
2757 
2758 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2759 {
2760  /* If a structure already exists, return an error */
2761  if (agi->speech) {
2762  ast_agi_send(agi->fd, chan, "200 result=0\n");
2763  return RESULT_SUCCESS;
2764  }
2765 
2766  if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
2767  ast_agi_send(agi->fd, chan, "200 result=1\n");
2768  else
2769  ast_agi_send(agi->fd, chan, "200 result=0\n");
2770 
2771  return RESULT_SUCCESS;
2772 }
2773 
2774 static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2775 {
2776  /* Check for minimum arguments */
2777  if (argc != 4)
2778  return RESULT_SHOWUSAGE;
2779 
2780  /* Check to make sure speech structure exists */
2781  if (!agi->speech) {
2782  ast_agi_send(agi->fd, chan, "200 result=0\n");
2783  return RESULT_SUCCESS;
2784  }
2785 
2786  ast_speech_change(agi->speech, argv[2], argv[3]);
2787  ast_agi_send(agi->fd, chan, "200 result=1\n");
2788 
2789  return RESULT_SUCCESS;
2790 }
2791 
2792 static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2793 {
2794  if (agi->speech) {
2795  ast_speech_destroy(agi->speech);
2796  agi->speech = NULL;
2797  ast_agi_send(agi->fd, chan, "200 result=1\n");
2798  } else {
2799  ast_agi_send(agi->fd, chan, "200 result=0\n");
2800  }
2801 
2802  return RESULT_SUCCESS;
2803 }
2804 
2805 static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2806 {
2807  if (argc != 5)
2808  return RESULT_SHOWUSAGE;
2809 
2810  if (!agi->speech) {
2811  ast_agi_send(agi->fd, chan, "200 result=0\n");
2812  return RESULT_SUCCESS;
2813  }
2814 
2815  if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
2816  ast_agi_send(agi->fd, chan, "200 result=0\n");
2817  else
2818  ast_agi_send(agi->fd, chan, "200 result=1\n");
2819 
2820  return RESULT_SUCCESS;
2821 }
2822 
2823 static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2824 {
2825  if (argc != 4)
2826  return RESULT_SHOWUSAGE;
2827 
2828  if (!agi->speech) {
2829  ast_agi_send(agi->fd, chan, "200 result=0\n");
2830  return RESULT_SUCCESS;
2831  }
2832 
2833  if (ast_speech_grammar_unload(agi->speech, argv[3]))
2834  ast_agi_send(agi->fd, chan, "200 result=0\n");
2835  else
2836  ast_agi_send(agi->fd, chan, "200 result=1\n");
2837 
2838  return RESULT_SUCCESS;
2839 }
2840 
2841 static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2842 {
2843  if (argc != 4)
2844  return RESULT_SHOWUSAGE;
2845 
2846  if (!agi->speech) {
2847  ast_agi_send(agi->fd, chan, "200 result=0\n");
2848  return RESULT_SUCCESS;
2849  }
2850 
2851  if (ast_speech_grammar_activate(agi->speech, argv[3]))
2852  ast_agi_send(agi->fd, chan, "200 result=0\n");
2853  else
2854  ast_agi_send(agi->fd, chan, "200 result=1\n");
2855 
2856  return RESULT_SUCCESS;
2857 }
2858 
2859 static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2860 {
2861  if (argc != 4)
2862  return RESULT_SHOWUSAGE;
2863 
2864  if (!agi->speech) {
2865  ast_agi_send(agi->fd, chan, "200 result=0\n");
2866  return RESULT_SUCCESS;
2867  }
2868 
2869  if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
2870  ast_agi_send(agi->fd, chan, "200 result=0\n");
2871  else
2872  ast_agi_send(agi->fd, chan, "200 result=1\n");
2873 
2874  return RESULT_SUCCESS;
2875 }
2876 
2877 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
2878 {
2879  struct ast_filestream *fs = NULL;
2880 
2881  if (!(fs = ast_openstream(chan, filename, preflang)))
2882  return -1;
2883 
2884  if (offset)
2885  ast_seekstream(fs, offset, SEEK_SET);
2886 
2887  if (ast_applystream(chan, fs))
2888  return -1;
2889 
2890  if (ast_playstream(fs))
2891  return -1;
2892 
2893  return 0;
2894 }
2895 
2896 static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
2897 {
2898  struct ast_speech *speech = agi->speech;
2899  const char *prompt;
2900  char dtmf = 0, tmp[4096] = "", *buf = tmp;
2901  int timeout = 0, offset = 0, res = 0, i = 0;
2902  long current_offset = 0;
2903  const char *reason = NULL;
2904  struct ast_frame *fr = NULL;
2905  struct ast_speech_result *result = NULL;
2906  size_t left = sizeof(tmp);
2907  time_t start = 0, current;
2908 
2909  if (argc < 4)
2910  return RESULT_SHOWUSAGE;
2911 
2912  if (!speech) {
2913  ast_agi_send(agi->fd, chan, "200 result=0\n");
2914  return RESULT_SUCCESS;
2915  }
2916 
2917  prompt = argv[2];
2918  timeout = atoi(argv[3]);
2919 
2920  /* If offset is specified then convert from text to integer */
2921  if (argc == 5)
2922  offset = atoi(argv[4]);
2923 
2924  /* We want frames coming in signed linear */
2926  ast_agi_send(agi->fd, chan, "200 result=0\n");
2927  return RESULT_SUCCESS;
2928  }
2929 
2930  /* Setup speech structure */
2931  if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
2933  ast_speech_start(speech);
2934  }
2935 
2936  /* Start playing prompt */
2937  speech_streamfile(chan, prompt, chan->language, offset);
2938 
2939  /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
2940  while (ast_strlen_zero(reason)) {
2941  /* Run scheduled items */
2942  ast_sched_runq(chan->sched);
2943 
2944  /* See maximum time of waiting */
2945  if ((res = ast_sched_wait(chan->sched)) < 0)
2946  res = 1000;
2947 
2948  /* Wait for frame */
2949  if (ast_waitfor(chan, res) > 0) {
2950  if (!(fr = ast_read(chan))) {
2951  reason = "hangup";
2952  break;
2953  }
2954  }
2955 
2956  /* Perform timeout check */
2957  if ((timeout > 0) && (start > 0)) {
2958  time(&current);
2959  if ((current - start) >= timeout) {
2960  reason = "timeout";
2961  if (fr)
2962  ast_frfree(fr);
2963  break;
2964  }
2965  }
2966 
2967  /* Check the speech structure for any changes */
2968  ast_mutex_lock(&speech->lock);
2969 
2970  /* See if we need to quiet the audio stream playback */
2971  if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
2972  current_offset = ast_tellstream(chan->stream);
2973  ast_stopstream(chan);
2975  }
2976 
2977  /* Check each state */
2978  switch (speech->state) {
2980  /* If the stream is done, start timeout calculation */
2981  if ((timeout > 0) && start == 0 && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
2982  ast_stopstream(chan);
2983  time(&start);
2984  }
2985  /* Write audio frame data into speech engine if possible */
2986  if (fr && fr->frametype == AST_FRAME_VOICE)
2987  ast_speech_write(speech, fr->data.ptr, fr->datalen);
2988  break;
2989  case AST_SPEECH_STATE_WAIT:
2990  /* Cue waiting sound if not already playing */
2991  if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
2992  ast_stopstream(chan);
2993  /* If a processing sound exists, or is not none - play it */
2994  if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
2995  speech_streamfile(chan, speech->processing_sound, chan->language, 0);
2996  }
2997  break;
2998  case AST_SPEECH_STATE_DONE:
2999  /* Get the results */
3000  speech->results = ast_speech_results_get(speech);
3001  /* Change state to not ready */
3003  reason = "speech";
3004  break;
3005  default:
3006  break;
3007  }
3008  ast_mutex_unlock(&speech->lock);
3009 
3010  /* Check frame for DTMF or hangup */
3011  if (fr) {
3012  if (fr->frametype == AST_FRAME_DTMF) {
3013  reason = "dtmf";
3014  dtmf = fr->subclass.integer;
3015  } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_HANGUP) {
3016  reason = "hangup";
3017  }
3018  ast_frfree(fr);
3019  }
3020  }
3021 
3022  if (!strcasecmp(reason, "speech")) {
3023  /* Build string containing speech results */
3024  for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
3025  /* Build result string */
3026  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);
3027  /* Increment result count */
3028  i++;
3029  }
3030  /* Print out */
3031  ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
3032  } else if (!strcasecmp(reason, "dtmf")) {
3033  ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
3034  } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
3035  ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
3036  } else {
3037  ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
3038  }
3039 
3040  return RESULT_SUCCESS;
3041 }
3042 
3043 /*!
3044  * \brief AGI commands list
3045  */
3046 static struct agi_command commands[] = {
3047  { { "answer", NULL }, handle_answer, NULL, NULL, 0 },
3048  { { "asyncagi", "break", NULL }, handle_asyncagi_break, NULL, NULL, 1 },
3049  { { "channel", "status", NULL }, handle_channelstatus, NULL, NULL, 0 },
3050  { { "database", "del", NULL }, handle_dbdel, NULL, NULL, 1 },
3051  { { "database", "deltree", NULL }, handle_dbdeltree, NULL, NULL, 1 },
3052  { { "database", "get", NULL }, handle_dbget, NULL, NULL, 1 },
3053  { { "database", "put", NULL }, handle_dbput, NULL, NULL, 1 },
3054  { { "exec", NULL }, handle_exec, NULL, NULL, 1 },
3055  { { "get", "data", NULL }, handle_getdata, NULL, NULL, 0 },
3056  { { "get", "full", "variable", NULL }, handle_getvariablefull, NULL, NULL, 1 },
3057  { { "get", "option", NULL }, handle_getoption, NULL, NULL, 0 },
3058  { { "get", "variable", NULL }, handle_getvariable, NULL, NULL, 1 },
3059  { { "hangup", NULL }, handle_hangup, NULL, NULL, 0 },
3060  { { "noop", NULL }, handle_noop, NULL, NULL, 1 },
3061  { { "receive", "char", NULL }, handle_recvchar, NULL, NULL, 0 },
3062  { { "receive", "text", NULL }, handle_recvtext, NULL, NULL, 0 },
3063  { { "record", "file", NULL }, handle_recordfile, NULL, NULL, 0 },
3064  { { "say", "alpha", NULL }, handle_sayalpha, NULL, NULL, 0},
3065  { { "say", "digits", NULL }, handle_saydigits, NULL, NULL, 0 },
3066  { { "say", "number", NULL }, handle_saynumber, NULL, NULL, 0 },
3067  { { "say", "phonetic", NULL }, handle_sayphonetic, NULL, NULL, 0},
3068  { { "say", "date", NULL }, handle_saydate, NULL, NULL, 0},
3069  { { "say", "time", NULL }, handle_saytime, NULL, NULL, 0},
3070  { { "say", "datetime", NULL }, handle_saydatetime, NULL, NULL, 0},
3071  { { "send", "image", NULL }, handle_sendimage, NULL, NULL, 0},
3072  { { "send", "text", NULL }, handle_sendtext, NULL, NULL, 0},
3073  { { "set", "autohangup", NULL }, handle_autohangup, NULL, NULL, 0},
3074  { { "set", "callerid", NULL }, handle_setcallerid, NULL, NULL, 0},
3075  { { "set", "context", NULL }, handle_setcontext, NULL, NULL, 0},
3076  { { "set", "extension", NULL }, handle_setextension, NULL, NULL, 0},
3077  { { "set", "music", NULL }, handle_setmusic, NULL, NULL, 0 },
3078  { { "set", "priority", NULL }, handle_setpriority, NULL, NULL, 0 },
3079  { { "set", "variable", NULL }, handle_setvariable, NULL, NULL, 1 },
3080  { { "stream", "file", NULL }, handle_streamfile, NULL, NULL, 0 },
3081  { { "control", "stream", "file", NULL }, handle_controlstreamfile, NULL, NULL, 0 },
3082  { { "tdd", "mode", NULL }, handle_tddmode, NULL, NULL, 0 },
3083  { { "verbose", NULL }, handle_verbose, NULL, NULL, 1 },
3084  { { "wait", "for", "digit", NULL }, handle_waitfordigit, NULL, NULL, 0 },
3085  { { "speech", "create", NULL }, handle_speechcreate, NULL, NULL, 0 },
3086  { { "speech", "set", NULL }, handle_speechset, NULL, NULL, 0 },
3087  { { "speech", "destroy", NULL }, handle_speechdestroy, NULL, NULL, 1 },
3088  { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, NULL, NULL, 0 },
3089  { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, NULL, NULL, 1 },
3090  { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, NULL, NULL, 0 },
3091  { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, NULL, NULL, 0 },
3092  { { "speech", "recognize", NULL }, handle_speechrecognize, NULL, NULL, 0 },
3093 };
3094 
3096 
3097 static char *help_workhorse(int fd, const char * const match[])
3098 {
3099  char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
3100  struct agi_command *e;
3101 
3102  if (match)
3103  ast_join(matchstr, sizeof(matchstr), match);
3104 
3105  ast_cli(fd, "%5.5s %30.30s %s\n","Dead","Command","Description");
3108  if (!e->cmda[0])
3109  break;
3110  /* Hide commands that start with '_' */
3111  if ((e->cmda[0])[0] == '_')
3112  continue;
3113  ast_join(fullcmd, sizeof(fullcmd), e->cmda);
3114  if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
3115  continue;
3116  ast_cli(fd, "%5.5s %30.30s %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
3117  }
3119 
3120  return CLI_SUCCESS;
3121 }
3122 
3124 {
3125  char fullcmd[MAX_CMD_LEN];
3126 
3127  ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
3128 
3129  if (!find_command(cmd->cmda, 1)) {
3130  *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
3131  if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
3132 #ifdef AST_XML_DOCS
3133  *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd, NULL);
3134  *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd, NULL);
3135  *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd, NULL);
3136  *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd, NULL);
3137  *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
3138 #endif
3139 #ifndef HAVE_NULLSAFE_PRINTF
3140  if (!cmd->summary) {
3141  *((char **) &cmd->summary) = ast_strdup("");
3142  }
3143  if (!cmd->usage) {
3144  *((char **) &cmd->usage) = ast_strdup("");
3145  }
3146  if (!cmd->syntax) {
3147  *((char **) &cmd->syntax) = ast_strdup("");
3148  }
3149  if (!cmd->seealso) {
3150  *((char **) &cmd->seealso) = ast_strdup("");
3151  }
3152 #endif
3153  }
3154 
3155  cmd->mod = mod;
3157  AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
3159  if (mod != ast_module_info->self)
3161  ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
3162  return 1;
3163  } else {
3164  ast_log(LOG_WARNING, "Command already registered!\n");
3165  return 0;
3166  }
3167 }
3168 
3170 {
3171  struct agi_command *e;
3172  int unregistered = 0;
3173  char fullcmd[MAX_CMD_LEN];
3174 
3175  ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
3176 
3179  if (cmd == e) {
3181  if (mod != ast_module_info->self)
3183 #ifdef AST_XML_DOCS
3184  if (e->docsrc == AST_XML_DOC) {
3185  ast_free((char *) e->summary);
3186  ast_free((char *) e->usage);
3187  ast_free((char *) e->syntax);
3188  ast_free((char *) e->seealso);
3189  *((char **) &e->summary) = NULL;
3190  *((char **) &e->usage) = NULL;
3191  *((char **) &e->syntax) = NULL;
3192  *((char **) &e->seealso) = NULL;
3193  }
3194 #endif
3195  unregistered=1;
3196  break;
3197  }
3198  }
3201  if (unregistered)
3202  ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
3203  else
3204  ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
3205  return unregistered;
3206 }
3207 
3208 int AST_OPTIONAL_API_NAME(ast_agi_register_multiple)(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
3209 {
3210  unsigned int i, x = 0;
3211 
3212  for (i = 0; i < len; i++) {
3213  if (ast_agi_register(mod, cmd + i) == 1) {
3214  x++;
3215  continue;
3216  }
3217 
3218  /* registration failed, unregister everything
3219  that had been registered up to that point
3220  */
3221  for (; x > 0; x--) {
3222  /* we are intentionally ignoring the
3223  result of ast_agi_unregister() here,
3224  but it should be safe to do so since
3225  we just registered these commands and
3226  the only possible way for unregistration
3227  to fail is if the command is not
3228  registered
3229  */
3230  (void) ast_agi_unregister(mod, cmd + x - 1);
3231  }
3232  return -1;
3233  }
3234 
3235  return 0;
3236 }
3237 
3239 {
3240  unsigned int i;
3241  int res = 0;
3242 
3243  for (i = 0; i < len; i++) {
3244  /* remember whether any of the unregistration
3245  attempts failed... there is no recourse if
3246  any of them do
3247  */
3248  res |= ast_agi_unregister(mod, cmd + i);
3249  }
3250 
3251  return res;
3252 }
3253 
3254 static agi_command *find_command(const char * const cmds[], int exact)
3255 {
3256  int y, match;
3257  struct agi_command *e;
3258 
3261  if (!e->cmda[0])
3262  break;
3263  /* start optimistic */
3264  match = 1;
3265  for (y = 0; match && cmds[y]; y++) {
3266  /* If there are no more words in the command (and we're looking for
3267  an exact match) or there is a difference between the two words,
3268  then this is not a match */
3269  if (!e->cmda[y] && !exact)
3270  break;
3271  /* don't segfault if the next part of a command doesn't exist */
3272  if (!e->cmda[y]) {
3274  return NULL;
3275  }
3276  if (strcasecmp(e->cmda[y], cmds[y]))
3277  match = 0;
3278  }
3279  /* If more words are needed to complete the command then this is not
3280  a candidate (unless we're looking for a really inexact answer */
3281  if ((exact > -1) && e->cmda[y])
3282  match = 0;
3283  if (match) {
3285  return e;
3286  }
3287  }
3289  return NULL;
3290 }
3291 
3292 static int parse_args(char *s, int *max, const char *argv[])
3293 {
3294  int x = 0, quoted = 0, escaped = 0, whitespace = 1;
3295  char *cur;
3296 
3297  cur = s;
3298  while(*s) {
3299  switch(*s) {
3300  case '"':
3301  /* If it's escaped, put a literal quote */
3302  if (escaped)
3303  goto normal;
3304  else
3305  quoted = !quoted;
3306  if (quoted && whitespace) {
3307  /* If we're starting a quote, coming off white space start a new word, too */
3308  argv[x++] = cur;
3309  whitespace=0;
3310  }
3311  escaped = 0;
3312  break;
3313  case ' ':
3314  case '\t':
3315  if (!quoted && !escaped) {
3316  /* If we're not quoted, mark this as whitespace, and
3317  end the previous argument */
3318  whitespace = 1;
3319  *(cur++) = '\0';
3320  } else
3321  /* Otherwise, just treat it as anything else */
3322  goto normal;
3323  break;
3324  case '\\':
3325  /* If we're escaped, print a literal, otherwise enable escaping */
3326  if (escaped) {
3327  goto normal;
3328  } else {
3329  escaped=1;
3330  }
3331  break;
3332  default:
3333 normal:
3334  if (whitespace) {
3335  if (x >= MAX_ARGS -1) {
3336  ast_log(LOG_WARNING, "Too many arguments, truncating\n");
3337  break;
3338  }
3339  /* Coming off of whitespace, start the next argument */
3340  argv[x++] = cur;
3341  whitespace=0;
3342  }
3343  *(cur++) = *s;
3344  escaped=0;
3345  }
3346  s++;
3347  }
3348  /* Null terminate */
3349  *(cur++) = '\0';
3350  argv[x] = NULL;
3351  *max = x;
3352  return 0;
3353 }
3354 
3355 static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
3356 {
3357  const char *argv[MAX_ARGS];
3358  int argc = MAX_ARGS;
3359  int res;
3360  agi_command *c;
3361  const char *ami_res;
3362  char *ami_cmd = ast_strdupa(buf);
3363  int command_id = ast_random();
3364  int resultcode;
3365 
3366  manager_event(EVENT_FLAG_AGI, "AGIExec",
3367  "SubEvent: Start\r\n"
3368  "Channel: %s\r\n"
3369  "CommandId: %d\r\n"
3370  "Command: %s\r\n", chan->name, command_id, ami_cmd);
3371  parse_args(buf, &argc, argv);
3372  c = find_command(argv, 0);
3373  if (c && (!dead || (dead && c->dead))) {
3374  /* if this command wasn't registered by res_agi, be sure to usecount
3375  the module we are using */
3376  if (c->mod != ast_module_info->self)
3377  ast_module_ref(c->mod);
3378  /* If the AGI command being executed is an actual application (using agi exec)
3379  the app field will be updated in pbx_exec via handle_exec */
3380  if (chan->cdr && !ast_check_hangup(chan) && strcasecmp(argv[0], "EXEC"))
3381  ast_cdr_setapp(chan->cdr, "AGI", buf);
3382 
3383  res = c->handler(chan, agi, argc, argv);
3384  if (c->mod != ast_module_info->self)
3385  ast_module_unref(c->mod);
3386  switch (res) {
3387  case RESULT_SHOWUSAGE:
3388  ami_res = "Usage";
3389  resultcode = 520;
3390  break;
3391  case RESULT_FAILURE:
3392  ami_res = "Failure";
3393  resultcode = -1;
3394  break;
3395  case ASYNC_AGI_BREAK:
3396  case RESULT_SUCCESS:
3397  ami_res = "Success";
3398  resultcode = 200;
3399  break;
3400  default:
3401  ami_res = "Unknown Result";
3402  resultcode = 200;
3403  break;
3404  }
3405  manager_event(EVENT_FLAG_AGI, "AGIExec",
3406  "SubEvent: End\r\n"
3407  "Channel: %s\r\n"
3408  "CommandId: %d\r\n"
3409  "Command: %s\r\n"
3410  "ResultCode: %d\r\n"
3411  "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
3412  switch (res) {
3413  case RESULT_SHOWUSAGE:
3414  if (ast_strlen_zero(c->usage)) {
3415  ast_agi_send(agi->fd, chan, "520 Invalid command syntax. Proper usage not available.\n");
3416  } else {
3417  ast_agi_send(agi->fd, chan, "520-Invalid command syntax. Proper usage follows:\n");
3418  ast_agi_send(agi->fd, chan, "%s", c->usage);
3419  ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
3420  }
3421  break;
3422  case ASYNC_AGI_BREAK:
3423  return AGI_RESULT_SUCCESS_ASYNC;
3424  case RESULT_FAILURE:
3425  /* The RESULT_FAILURE code is usually because the channel hungup. */
3426  return AGI_RESULT_FAILURE;
3427  default:
3428  break;
3429  }
3430  } else if (c) {
3431  ast_agi_send(agi->fd, chan, "511 Command Not Permitted on a dead channel\n");
3432  manager_event(EVENT_FLAG_AGI, "AGIExec",
3433  "SubEvent: End\r\n"
3434  "Channel: %s\r\n"
3435  "CommandId: %d\r\n"
3436  "Command: %s\r\n"
3437  "ResultCode: 511\r\n"
3438  "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
3439  } else {
3440  ast_agi_send(agi->fd, chan, "510 Invalid or unknown command\n");
3441  manager_event(EVENT_FLAG_AGI, "AGIExec",
3442  "SubEvent: End\r\n"
3443  "Channel: %s\r\n"
3444  "CommandId: %d\r\n"
3445  "Command: %s\r\n"
3446  "ResultCode: 510\r\n"
3447  "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
3448  }
3449  return AGI_RESULT_SUCCESS;
3450 }
3451 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
3452 {
3453  struct ast_channel *c;
3454  int outfd;
3455  int ms;
3456  int needhup = 0;
3457  enum agi_result returnstatus = AGI_RESULT_SUCCESS;
3458  struct ast_frame *f;
3459  char buf[AGI_BUF_LEN];
3460  char *res = NULL;
3461  FILE *readf;
3462  /* how many times we'll retry if ast_waitfor_nandfs will return without either
3463  channel or file descriptor in case select is interrupted by a system call (EINTR) */
3464  int retry = AGI_NANDFS_RETRY;
3465  int send_sighup;
3466  const char *sighup_str;
3467 
3468  ast_channel_lock(chan);
3469  sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
3470  send_sighup = ast_strlen_zero(sighup_str) || !ast_false(sighup_str);
3471  ast_channel_unlock(chan);
3472 
3473  if (!(readf = fdopen(agi->ctrl, "r"))) {
3474  ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
3475  if (send_sighup && pid > -1)
3476  kill(pid, SIGHUP);
3477  close(agi->ctrl);
3478  return AGI_RESULT_FAILURE;
3479  }
3480 
3481  setlinebuf(readf);
3482  setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
3483  for (;;) {
3484  if (needhup) {
3485  needhup = 0;
3486  dead = 1;
3487  if (send_sighup) {
3488  if (pid > -1) {
3489  kill(pid, SIGHUP);
3490  } else if (agi->fast) {
3491  ast_agi_send(agi->fd, chan, "HANGUP\n");
3492  }
3493  }
3494  }
3495  ms = -1;
3496  if (dead) {
3497  c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
3498  } else if (!ast_check_hangup(chan)) {
3499  c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
3500  } else {
3501  /*
3502  * Read the channel control queue until it is dry so we can
3503  * switch to dead mode.
3504  */
3505  c = chan;
3506  }
3507  if (c) {
3508  retry = AGI_NANDFS_RETRY;
3509  /* Idle the channel until we get a command */
3510  f = ast_read(c);
3511  if (!f) {
3512  ast_debug(1, "%s hungup\n", chan->name);
3513  needhup = 1;
3514  if (!returnstatus) {
3515  returnstatus = AGI_RESULT_HANGUP;
3516  }
3517  } else {
3518  /* If it's voice, write it to the audio pipe */
3519  if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
3520  /* Write, ignoring errors */
3521  if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
3522  }
3523  }
3524  ast_frfree(f);
3525  }
3526  } else if (outfd > -1) {
3527  size_t len = sizeof(buf);
3528  size_t buflen = 0;
3529  enum agi_result cmd_status;
3530 
3531  retry = AGI_NANDFS_RETRY;
3532  buf[0] = '\0';
3533 
3534  while (len > 1) {
3535  res = fgets(buf + buflen, len, readf);
3536  if (feof(readf))
3537  break;
3538  if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
3539  break;
3540  if (res != NULL && !agi->fast)
3541  break;
3542  buflen = strlen(buf);
3543  if (buflen && buf[buflen - 1] == '\n')
3544  break;
3545  len = sizeof(buf) - buflen;
3546  if (agidebug)
3547  ast_verbose("AGI Rx << temp buffer %s - errno %s\nNo \\n received, checking again.\n", buf, strerror(errno));
3548  }
3549 
3550  if (!buf[0]) {
3551  /* Program terminated */
3552  ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
3553  if (pid > 0)
3554  waitpid(pid, status, 0);
3555  /* No need to kill the pid anymore, since they closed us */
3556  pid = -1;
3557  break;
3558  }
3559 
3560  /* Special case for inability to execute child process */
3561  if (*buf && strncasecmp(buf, "failure", 7) == 0) {
3562  returnstatus = AGI_RESULT_FAILURE;
3563  break;
3564  }
3565 
3566  /* get rid of trailing newline, if any */
3567  buflen = strlen(buf);
3568  if (buflen && buf[buflen - 1] == '\n') {
3569  buf[buflen - 1] = '\0';
3570  }
3571 
3572  if (agidebug)
3573  ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
3574  cmd_status = agi_handle_command(chan, agi, buf, dead);
3575  switch (cmd_status) {
3576  case AGI_RESULT_FAILURE:
3577  if (dead || !ast_check_hangup(chan)) {
3578  /* The failure was not because of a hangup. */
3579  returnstatus = AGI_RESULT_FAILURE;
3580  }
3581  break;
3582  default:
3583  break;
3584  }
3585  } else {
3586  if (--retry <= 0) {
3587  ast_log(LOG_WARNING, "No channel, no fd?\n");
3588  returnstatus = AGI_RESULT_FAILURE;
3589  break;
3590  }
3591  }
3592  }
3593  if (agi->speech) {
3594  ast_speech_destroy(agi->speech);
3595  }
3596  /* Notify process */
3597  if (send_sighup) {
3598  if (pid > -1) {
3599  if (kill(pid, SIGHUP)) {
3600  ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
3601  } else { /* Give the process a chance to die */
3602  usleep(1);
3603  }
3604  waitpid(pid, status, WNOHANG);
3605  } else if (agi->fast) {
3606  ast_agi_send(agi->fd, chan, "HANGUP\n");
3607  }
3608  }
3609  fclose(readf);
3610  return returnstatus;
3611 }
3612 
3613 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3614 {
3615  struct agi_command *command;
3616  char fullcmd[MAX_CMD_LEN];
3617  int error = 0;
3618 
3619  switch (cmd) {
3620  case CLI_INIT:
3621  e->command = "agi show commands [topic]";
3622  e->usage =
3623  "Usage: agi show commands [topic] <topic>\n"
3624  " When called with a topic as an argument, displays usage\n"
3625  " information on the given command. If called without a\n"
3626  " topic, it provides a list of AGI commands.\n";
3627  return NULL;
3628  case CLI_GENERATE:
3629  return NULL;
3630  }
3631  if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
3632  return CLI_SHOWUSAGE;
3633  if (a->argc > e->args - 1) {
3634  command = find_command(a->argv + e->args, 1);
3635  if (command) {
3636  char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL;
3637  char info[30 + MAX_CMD_LEN]; /* '-= Info about...' */
3638  char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS]; /* '-= Info about...' with colors */
3639  char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Syntax]\n with colors */
3640  char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Description]\n with colors */
3641  char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Runs Dead]\n with colors */
3642  char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS]; /* 'Yes' or 'No' with colors */
3643  char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS]; /* [See Also]\n with colors */
3644  char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Syntax]\n with colors */
3645  size_t synlen, desclen, seealsolen, stxlen;
3646 
3647  term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle));
3648  term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle));
3649  term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle));
3650  term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle));
3651  term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle));
3652  term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent));
3653 
3654  ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
3655  snprintf(info, sizeof(info), "\n -= Info about agi '%s' =- ", fullcmd);
3656  term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle));
3657 #ifdef AST_XML_DOCS
3658  if (command->docsrc == AST_XML_DOC) {
3659  synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
3660  description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
3661  seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
3662  if (!seealso || !description || !synopsis) {
3663  error = 1;
3664  goto return_cleanup;
3665  }
3666  } else
3667 #endif
3668  {
3669  synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
3670  synopsis = ast_malloc(synlen);
3671 
3672  desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
3673  description = ast_malloc(desclen);
3674 
3675  seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
3676  seealso = ast_malloc(seealsolen);
3677 
3678  if (!synopsis || !description || !seealso) {
3679  error = 1;
3680  goto return_cleanup;
3681  }
3682  term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen);
3683  term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen);
3684  term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen);
3685  }
3686 
3687  stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
3688  syntax = ast_malloc(stxlen);
3689  if (!syntax) {
3690  error = 1;
3691  goto return_cleanup;
3692  }
3693  term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen);
3694 
3695  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,
3696  desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
3697  seealsotitle, seealso);
3698 return_cleanup:
3699  ast_free(synopsis);
3700  ast_free(description);
3701  ast_free(syntax);
3702  ast_free(seealso);
3703  } else {
3704  if (find_command(a->argv + e->args, -1)) {
3705  return help_workhorse(a->fd, a->argv + e->args);
3706  } else {
3707  ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
3708  ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
3709  }
3710  }
3711  } else {
3712  return help_workhorse(a->fd, NULL);
3713  }
3714  return (error ? CLI_FAILURE : CLI_SUCCESS);
3715 }
3716 
3717 /*! \brief Convert string to use HTML escaped characters
3718  \note Maybe this should be a generic function?
3719 */
3720 static void write_html_escaped(FILE *htmlfile, char *str)
3721 {
3722  char *cur = str;
3723 
3724  while(*cur) {
3725  switch (*cur) {
3726  case '<':
3727  fprintf(htmlfile, "%s", "&lt;");
3728  break;
3729  case '>':
3730  fprintf(htmlfile, "%s", "&gt;");
3731  break;
3732  case '&':
3733  fprintf(htmlfile, "%s", "&amp;");
3734  break;
3735  case '"':
3736  fprintf(htmlfile, "%s", "&quot;");
3737  break;
3738  default:
3739  fprintf(htmlfile, "%c", *cur);
3740  break;
3741  }
3742  cur++;
3743  }
3744 
3745  return;
3746 }
3747 
3748 static int write_htmldump(const char *filename)
3749 {
3750  struct agi_command *command;
3751  char fullcmd[MAX_CMD_LEN];
3752  FILE *htmlfile;
3753 
3754  if (!(htmlfile = fopen(filename, "wt")))
3755  return -1;
3756 
3757  fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
3758  fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
3759  fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
3760 
3762  AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
3763  char *tempstr, *stringp;
3764 
3765  if (!command->cmda[0]) /* end ? */
3766  break;
3767  /* Hide commands that start with '_' */
3768  if ((command->cmda[0])[0] == '_')
3769  continue;
3770  ast_join(fullcmd, sizeof(fullcmd), command->cmda);
3771 
3772  fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
3773  fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
3774 #ifdef AST_XML_DOCS
3775  stringp = ast_xmldoc_printable(command->usage, 0);
3776 #else
3777  stringp = ast_strdup(command->usage);
3778 #endif
3779  tempstr = strsep(&stringp, "\n");
3780 
3781  fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
3782  write_html_escaped(htmlfile, tempstr);
3783  fprintf(htmlfile, "</TD></TR>\n");
3784  fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
3785 
3786  while ((tempstr = strsep(&stringp, "\n")) != NULL) {
3787  write_html_escaped(htmlfile, tempstr);
3788  fprintf(htmlfile, "<BR>\n");
3789  }
3790  fprintf(htmlfile, "</TD></TR>\n");
3791  fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
3792  ast_free(stringp);
3793  }
3795  fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
3796  fclose(htmlfile);
3797  return 0;
3798 }
3799 
3800 static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3801 {
3802  switch (cmd) {
3803  case CLI_INIT:
3804  e->command = "agi dump html";
3805  e->usage =
3806  "Usage: agi dump html <filename>\n"
3807  " Dumps the AGI command list in HTML format to the given\n"
3808  " file.\n";
3809  return NULL;
3810  case CLI_GENERATE:
3811  return NULL;
3812  }
3813  if (a->argc != e->args + 1)
3814  return CLI_SHOWUSAGE;
3815 
3816  if (write_htmldump(a->argv[e->args]) < 0) {
3817  ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
3818  return CLI_SHOWUSAGE;
3819  }
3820  ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
3821  return CLI_SUCCESS;
3822 }
3823 
3824 static int agi_exec_full(struct ast_channel *chan, const char *data, int enhanced, int dead)
3825 {
3826  enum agi_result res;
3827  char *buf;
3828  int fds[2], efd = -1, pid = -1;
3830  AST_APP_ARG(arg)[MAX_ARGS];
3831  );
3832  AGI agi;
3833 
3834  if (ast_strlen_zero(data)) {
3835  ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
3836  return -1;
3837  }
3838  if (dead)
3839  ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
3840  memset(&agi, 0, sizeof(agi));
3841  buf = ast_strdupa(data);
3843  args.argv[args.argc] = NULL;
3844 #if 0
3845  /* Answer if need be */
3846  if (chan->_state != AST_STATE_UP) {
3847  if (ast_answer(chan))
3848  return -1;
3849  }
3850 #endif
3851  res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
3852  /* Async AGI do not require run_agi(), so just proceed if normal AGI
3853  or Fast AGI are setup with success. */
3854  if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
3855  int status = 0;
3856  agi.fd = fds[1];
3857  agi.ctrl = fds[0];
3858  agi.audio = efd;
3859  agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
3860  res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
3861  /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
3862  if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
3863  res = AGI_RESULT_FAILURE;
3864  if (fds[1] != fds[0])
3865  close(fds[1]);
3866  if (efd > -1)
3867  close(efd);
3868  }
3870 
3871  switch (res) {
3872  case AGI_RESULT_SUCCESS:
3875  pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
3876  break;
3877  case AGI_RESULT_FAILURE:
3878  pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
3879  break;
3880  case AGI_RESULT_NOTFOUND:
3881  pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
3882  break;
3883  case AGI_RESULT_HANGUP:
3884  pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
3885  return -1;
3886  }
3887 
3888  return 0;
3889 }
3890 
3891 static int agi_exec(struct ast_channel *chan, const char *data)
3892 {
3893  if (!ast_check_hangup(chan))
3894  return agi_exec_full(chan, data, 0, 0);
3895  else
3896  return agi_exec_full(chan, data, 0, 1);
3897 }
3898 
3899 static int eagi_exec(struct ast_channel *chan, const char *data)
3900 {
3901  int readformat, res;
3902 
3903  if (ast_check_hangup(chan)) {
3904  ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
3905  return 0;
3906  }
3907  readformat = chan->readformat;
3909  ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
3910  return -1;
3911  }
3912  res = agi_exec_full(chan, data, 1, 0);
3913  if (!res) {
3914  if (ast_set_read_format(chan, readformat)) {
3915  ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
3916  }
3917  }
3918  return res;
3919 }
3920 
3921 static int deadagi_exec(struct ast_channel *chan, const char *data)
3922 {
3923  ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
3924  return agi_exec(chan, data);
3925 }
3926 
3927 static struct ast_cli_entry cli_agi[] = {
3928  AST_CLI_DEFINE(handle_cli_agi_add_cmd, "Add AGI command to a channel in Async AGI"),
3929  AST_CLI_DEFINE(handle_cli_agi_debug, "Enable/Disable AGI debugging"),
3930  AST_CLI_DEFINE(handle_cli_agi_show, "List AGI commands or specific help"),
3931  AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format")
3932 };
3933 
3934 #ifdef TEST_FRAMEWORK
3935 AST_TEST_DEFINE(test_agi_null_docs)
3936 {
3937  int res = AST_TEST_PASS;
3938  struct agi_command noop_command =
3939  { { "testnoop", NULL }, handle_noop, NULL, NULL, 0 };
3940 
3941  switch (cmd) {
3942  case TEST_INIT:
3943  info->name = "null_agi_docs";
3944  info->category = "/res/agi/";
3945  info->summary = "AGI command with no documentation";
3946  info->description = "Test whether an AGI command with no documentation will crash Asterisk";
3947  return AST_TEST_NOT_RUN;
3948  case TEST_EXECUTE:
3949  break;
3950  }
3951 
3952  if (ast_agi_register(ast_module_info->self, &noop_command) == 0) {
3953  ast_test_status_update(test, "Unable to register testnoop command, because res_agi is not loaded.\n");
3954  return AST_TEST_NOT_RUN;
3955  }
3956 
3957 #ifndef HAVE_NULLSAFE_PRINTF
3958  /* Test for condition without actually crashing Asterisk */
3959  if (noop_command.usage == NULL) {
3960  ast_test_status_update(test, "AGI testnoop usage was not updated properly.\n");
3961  res = AST_TEST_FAIL;
3962  }
3963  if (noop_command.syntax == NULL) {
3964  ast_test_status_update(test, "AGI testnoop syntax was not updated properly.\n");
3965  res = AST_TEST_FAIL;
3966  }
3967 #endif
3968 
3969  ast_agi_unregister(ast_module_info->self, &noop_command);
3970  return res;
3971 }
3972 #endif
3973 
3974 static int unload_module(void)
3975 {
3977  /* we can safely ignore the result of ast_agi_unregister_multiple() here, since it cannot fail, as
3978  we know that these commands were registered by this module and are still registered
3979  */
3982  ast_unregister_application(deadapp);
3983  ast_manager_unregister("AGI");
3984  AST_TEST_UNREGISTER(test_agi_null_docs);
3985  return ast_unregister_application(app);
3986 }
3987 
3988 static int load_module(void)
3989 {
3991  /* we can safely ignore the result of ast_agi_register_multiple() here, since it cannot fail, as
3992  no other commands have been registered yet
3993  */
3998  AST_TEST_REGISTER(test_agi_null_docs);
4000 }
4001 
4003  .load = load_module,
4004  .unload = unload_module,
4005  .load_pri = AST_MODPRI_APP_DEPEND,
4006  );
const char * type
Definition: datastore.h:32
const char *const summary
Definition: agi.h:48
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:81
const char * ast_config_AST_KEY_DIR
Definition: asterisk.c:265
static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2841
union ast_frame_subclass subclass
Definition: frame.h:146
const char *const seealso
Definition: agi.h:56
int ast_recvchar(struct ast_channel *chan, int timeout)
Receives a text character from a channel.
Definition: channel.c:4642
int state
Definition: speech.h:59
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition: channel.c:7051
#define ast_channel_lock(chan)
Definition: channel.h:2466
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
Definition: pbx.c:4177
Main Channel structure associated with a channel.
Definition: channel.h:742
static char * help_workhorse(int fd, const char *const match[])
Definition: res_agi.c:3097
Music on hold handling.
struct agi_command::@140 list
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
char * str
Subscriber phone number (Malloced)
Definition: channel.h:241
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:946
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
const char *const type
Definition: channel.h:508
static int load_module(void)
Definition: res_agi.c:3988
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
int(*const handler)(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: agi.h:46
static void agi_destroy_commands_cb(void *data)
Definition: res_agi.c:985
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
char * str
Subscriber phone number (Malloced)
Definition: channel.h:336
void ast_module_unref(struct ast_module *)
Definition: loader.c:1312
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
char * strsep(char **str, const char *delims)
agi_result
Definition: res_agi.c:927
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: pbx.c:1537
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child...
Definition: app.c:2242
Generic Speech Recognition API.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
Definition: linkedlists.h:332
int priority
Definition: channel.h:841
static int parse_args(char *s, int *max, const char *argv[])
Definition: res_agi.c:3292
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx.c:1497
static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2587
const ast_string_field uniqueid
Definition: channel.h:787
String manipulation functions.
static struct agi_cmd * get_agi_cmd(struct ast_channel *chan)
Definition: res_agi.c:1004
int ast_speech_destroy(struct ast_speech *speech)
Destroy a speech structure.
Definition: res_speech.c:224
static int agidebug
Definition: res_agi.c:915
#define ast_strdup(a)
Definition: astmm.h:109
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
static enum agi_result async_agi_read_frame(struct ast_channel *chan)
Definition: res_agi.c:1205
void ast_speech_start(struct ast_speech *speech)
Indicate to the speech engine that audio is now going to start being written.
Definition: res_speech.c:123
static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2564
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: utils.h:653
Asterisk version information.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
int ast_control_streamfile(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *pause, const char *restart, int skipms, long *offsetms)
Stream a file with fast forward, pause, reverse, restart.
Definition: app.c:683
int ast_db_get(const char *family, const char *key, char *out, int outlen)
Get key value specified by family/key.
Definition: db.c:348
#define ast_test_flag(p, flag)
Definition: utils.h:63
void ast_channel_setwhentohangup_tv(struct ast_channel *chan, struct timeval offset)
Set when to hang a channel up.
Definition: channel.c:871
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4393
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:482
struct ast_party_name name
Subscriber name.
Definition: channel.h:290
int ast_agi_register(struct ast_module *mod, agi_command *cmd)
Registers an AGI command.
Definition: res_agi.c:3123
#define RESULT_SHOWUSAGE
Definition: cli.h:40
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:449
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1650
int ast_agi_register_multiple(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
Registers a group of AGI commands, provided as an array of struct agi_command entries.
Definition: res_agi.c:3208
const char * ast_config_AST_MODULE_DIR
Definition: asterisk.c:258
void * ptr
Definition: frame.h:160
int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
Try to write string, but wait no more than ms milliseconds before timing out.
Definition: utils.c:1328
const char * ast_get_version(void)
Retrieve the Asterisk version string.
Definition: version.c:14
Convenient Signal Processing routines.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
AGI Extension interfaces - Asterisk Gateway Interface.
#define ast_set_flag(p, flag)
Definition: utils.h:70
descriptor for a cli entry.
Definition: cli.h:165
const int argc
Definition: cli.h:154
#define LOG_WARNING
Definition: logger.h:144
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
Support for DNS SRV records, used in to locate SIP services.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
Definition: res_agi.c:1026
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:2151
#define AGI_NANDFS_RETRY
Definition: res_agi.c:905
void ast_verbose(const char *fmt,...)
Definition: logger.c:1568
#define COLOR_CYAN
Definition: term.h:59
struct ast_dsp * ast_dsp_new(void)
Definition: dsp.c:1607
#define AST_FRAME_DTMF
Definition: frame.h:128
const char *const usage
Definition: agi.h:50
static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:1797
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
char * ast_xmldoc_build_description(const char *type, const char *name, const char *module)
Generate description documentation from XML.
Definition: xmldoc.c:1899
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
#define ast_compat_res_agi
Definition: options.h:143
void ast_safe_fork_cleanup(void)
Common routine to cleanup after fork&#39;ed process is complete (if reaping was stopped) ...
Definition: app.c:2306
static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:1766
void ast_srv_cleanup(struct srv_context **context)
Cleanup resources associated with ast_srv_lookup.
Definition: srv.c:251
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
Definition: strings.h:792
#define AST_OPTION_TDD
Definition: frame.h:445
struct ast_module * mod
Definition: agi.h:60
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Definition: pbx.c:4468
Test Framework API.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4383
struct ast_party_redirecting redirecting
Redirecting/Diversion information.
Definition: channel.h:814
enum ast_cc_service_type service
Definition: chan_sip.c:821
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
Definition: cli.h:146
#define AMI_BUF_SIZE
Structure for a data store type.
Definition: datastore.h:31
char * str
Subscriber name (Malloced)
Definition: channel.h:214
unsigned int stop
Definition: app_meetme.c:969
struct ast_speech_result * ast_speech_results_get(struct ast_speech *speech)
Get speech recognition results.
Definition: res_speech.c:91
int ctrl
Definition: agi.h:37
static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
Definition: res_agi.c:2877
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2805
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8708
static char * deadapp
Definition: res_agi.c:913
const char * ast_config_AST_RUN_DIR
Definition: asterisk.c:266
#define ast_mutex_lock(a)
Definition: lock.h:155
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2135
struct ast_cdr * cdr
Definition: channel.h:766
static agi_command * find_command(const char *const cmds[], int exact)
Definition: res_agi.c:3254
static int eagi_exec(struct ast_channel *chan, const char *data)
Definition: res_agi.c:3899
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:374
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:90
char * ast_uri_encode(const char *string, char *outbuf, int buflen, int do_special_char)
Turn text string to URI-encoded XX version.
Definition: utils.c:398
Structure for a data store object.
Definition: datastore.h:54
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2604
const char * str
Definition: app_jack.c:144
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
const char * data
Definition: channel.h:755
char * ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module)
Generate synopsis documentation from XML.
Definition: xmldoc.c:1894
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7795
static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2419
static int action_add_agi_cmd(struct mansession *s, const struct message *m)
Add a new command to execute by the Async AGI application.
Definition: res_agi.c:1155
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
#define AST_FILE_MODE
Definition: asterisk.h:36
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:8051
static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2240
static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
get option - really similar to the handle_streamfile, but with a timeout
Definition: res_agi.c:1983
struct ast_channel * ast_waitfor_nandfds(struct ast_channel **chan, int n, int *fds, int nfds, int *exception, int *outfd, int *ms)
Waits for activity on a group of channels.
Definition: channel.c:3188
static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], int *efd)
Definition: res_agi.c:1233
ast_doc_src
From where the documentation come from, this structure is useful for use it inside application/functi...
Definition: xmldoc.h:28
#define ast_verb(level,...)
Definition: logger.h:243
struct agi_cmd::@321 entry
static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2774
const char * line
Definition: cli.h:156
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:65
char * grammar
Definition: speech.h:114
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Definition: pbx.c:10475
int ast_send_image(struct ast_channel *chan, const char *filename)
Sends an image.
Definition: image.c:159
int totalsilence
Definition: dsp.c:393
Utility functions.
int args
This gets set in ast_cli_register()
Definition: cli.h:179
#define MAX_CMD_LEN
Definition: res_agi.c:904
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:1860
char * cmd_id
Definition: res_agi.c:973
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:638
off_t ast_tellstream(struct ast_filestream *fs)
Tell where we are in a stream.
Definition: file.c:889
void ast_child_verbose(int level, const char *fmt,...)
Definition: logger.c:430
static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2682
#define AST_TERM_MAX_ESCAPE_CHARS
Maximum number of characters needed for a color escape sequence, plus a null char.
Definition: term.h:67
struct ast_party_id id
Caller party ID.
Definition: channel.h:370
const int dead
Definition: agi.h:52
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
const char * ast_config_AST_CONFIG_FILE
Definition: asterisk.c:257
SAY_EXTERN int(* ast_say_date)(struct ast_channel *chan, time_t t, const char *ints, const char *lang) SAY_INIT(ast_say_date)
Definition: say.h:164
int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
get values from config variables.
Definition: utils.c:2118
int ast_set_read_format(struct ast_channel *chan, format_t format)
Sets read format on channel chan Set read format for channel to whichever component of &quot;format&quot; is be...
Definition: channel.c:5301
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
General Asterisk channel definitions for image handling.
static int agi_exec(struct ast_channel *chan, const char *data)
Definition: res_agi.c:3891
int ast_speech_grammar_deactivate(struct ast_speech *speech, const char *grammar_name)
Deactivate a grammar on a speech structure.
Definition: res_speech.c:73
#define ASYNC_AGI_BREAK
Definition: res_agi.c:925
int ast_playstream(struct ast_filestream *s)
Play a open stream on a channel.
Definition: file.c:867
int ast_build_string(char **buffer, size_t *space, const char *fmt,...)
Build a string in a buffer, designed to be called repeatedly.
Definition: utils.c:1521
struct ast_module * self
Definition: module.h:227
struct ast_filestream * ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
Opens stream for use in seeking, playing.
Definition: file.c:681
static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2758
General Asterisk PBX channel definitions.
struct ast_party_dialed::@155 number
Dialed/Called number.
void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force)
Set the source of the hangup in this channel and it&#39;s bridge.
Definition: channel.c:2769
Asterisk file paths, configured in asterisk.conf.
int ast_str_make_space(struct ast_str **buf, size_t new_len)
Definition: strings.h:588
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
const char * ast_config_AST_AGI_DIR
Definition: asterisk.c:264
const int fd
Definition: cli.h:153
Definition: dsp.c:390
int ast_speech_change_state(struct ast_speech *speech, int state)
Change state of a speech structure.
Definition: res_speech.c:249
static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2745
#define ast_manager_register_xml(a, b, c)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:172
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
const int n
Definition: cli.h:159
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
Definition: res_agi.c:1720
int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
Full version with audiofd and controlfd. NOTE: returns &#39;2&#39; on ctrlfd available, not &#39;1&#39; like other fu...
Definition: app.c:231
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
int datalen
Definition: frame.h:148
static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2512
static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
Definition: res_agi.c:3451
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:83
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
Definition: channel.c:2746
static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2067
static struct agi_command commands[]
AGI commands list.
Definition: res_agi.c:3046
long int ast_random(void)
Definition: utils.c:1640
static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:1836
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:565
static char * handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: res_agi.c:2710
struct sched_context * sched
Definition: channel.h:756
const char *const syntax
Definition: agi.h:54
static struct ast_cli_entry cli_agi[]
Definition: res_agi.c:3927
int streamid
Definition: channel.h:835
#define EVENT_FLAG_AGI
Definition: manager.h:84
int(* timingfunc)(const void *data)
Definition: channel.h:759
static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2533
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
int ast_speech_grammar_unload(struct ast_speech *speech, const char *grammar_name)
Unload a grammar.
Definition: res_speech.c:85
static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:1897
struct ast_speech_result * results
Definition: speech.h:65
Core PBX routines and definitions.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:806
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:1650
SAY_EXTERN int(* ast_say_phonetic_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, int audiofd, int ctrlfd) SAY_INIT(ast_say_phonetic_str_full)
Definition: say.h:159
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:542
static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2792
Wrapper for network related headers, masking differences between various operating systems...
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set threshold value for silence.
Definition: dsp.c:1655
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Definition: term.c:184
const char *const * argv
Definition: cli.h:155
struct ast_party_dialed dialed
Dialed/Called information.
Definition: channel.h:797
const char * ast_config_AST_DATA_DIR
Definition: asterisk.c:262
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
static int agi_exec_full(struct ast_channel *chan, const char *data, int enhanced, int dead)
Definition: res_agi.c:3824
static int skipms
char * ast_getformatname(format_t format)
Get the name of a format.
Definition: frame.c:578
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
static enum agi_result launch_ha_netscript(char *agiurl, char *argv[], int *fds)
Definition: res_agi.c:1547
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2859
int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
Applys a open stream to a channel.
Definition: file.c:861
static struct @350 args
#define CLI_SHOWUSAGE
Definition: cli.h:44
const char * ast_config_AST_CONFIG_DIR
Definition: asterisk.c:256
void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
Retrieve the value of a builtin variable or variable from the channel variable stack.
Definition: pbx.c:3434
int plan
Q.931 Type-Of-Number and Numbering-Plan encoded fields.
Definition: channel.h:243
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
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:4653
static int add_to_agi(struct ast_channel *chan)
Definition: res_agi.c:1059
const char *const cmda[AST_MAX_CMD_LEN]
Definition: agi.h:43
int setenv(const char *name, const char *value, int overwrite)
int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
Rewind stream ms.
Definition: file.c:899
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
Definition: pbx.c:5405
int ast_speech_grammar_activate(struct ast_speech *speech, const char *grammar_name)
Activate a grammar on a speech structure.
Definition: res_speech.c:67
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int ani2
Automatic Number Identification 2 (Info Digits)
Definition: channel.h:380
SAY_EXTERN int(* ast_say_character_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, int audiofd, int ctrlfd) SAY_INIT(ast_say_character_str_full)
Definition: say.h:154
enum ast_channel_state _state
Definition: channel.h:839
int fd
Definition: agi.h:35
static int write_htmldump(const char *filename)
Definition: res_agi.c:3748
#define AGI_BUF_INITSIZE
Definition: res_agi.c:939
const ast_string_field name
Definition: channel.h:787
struct ast_filestream * ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts writing a file.
Definition: file.c:1049
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:8040
struct ast_speech * speech
Definition: agi.h:39
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2083
struct ast_datastore * ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
Definition: datastore.c:98
static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Say number in various language syntaxes.
Definition: res_agi.c:2052
static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:1778
static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2638
const char * ast_config_AST_LOG_DIR
Definition: asterisk.c:263
static char * synopsis
Definition: func_enum.c:156
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
Definition: file.c:879
static char * handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: res_agi.c:3613
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
#define ast_channel_unlock(chan)
Definition: channel.h:2467
int audio
Definition: agi.h:36
#define CLI_FAILURE
Definition: cli.h:45
int errno
static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2097
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:611
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
const char * ast_config_AST_MONITOR_DIR
Definition: asterisk.c:260
static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2112
static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:1853
void ast_join(char *s, size_t len, const char *const w[])
Definition: utils.c:1690
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:904
static char * app
Definition: res_agi.c:909
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
Definition: app.c:2237
static struct ast_format f[]
Definition: format_g726.c:181
int ast_agi_unregister_multiple(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
Unregisters a group of AGI commands, provided as an array of struct agi_command entries.
Definition: res_agi.c:3238
Asterisk XML Documentation API.
static void suspend(struct cc_core_instance *core_instance)
Definition: ccss.c:2919
const char * word
Definition: cli.h:157
#define MAX_AGI_CONNECT
Definition: res_agi.c:920
static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2439
void ast_cdr_setapp(struct ast_cdr *cdr, const char *app, const char *data)
Set the last executed application.
Definition: cdr.c:822
static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
Definition: res_agi.c:3355
#define AGI_BUF_SIZE
const char * ast_config_AST_SPOOL_DIR
Definition: asterisk.c:259
char * ast_xmldoc_printable(const char *bwinput, int withcolors)
Colorize and put delimiters (instead of tags) to the xmldoc output.
Definition: xmldoc.c:315
static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:1933
char * ast_xmldoc_build_syntax(const char *type, const char *name, const char *module)
Get the syntax for a specified application or function.
Definition: xmldoc.c:1156
char * ast_xmldoc_build_seealso(const char *type, const char *name, const char *module)
Parse the &lt;see-also&gt; node content.
Definition: xmldoc.c:1461
#define ast_clear_flag(p, flag)
Definition: utils.h:77
static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, const char *const argv[])
Definition: res_agi.c:2739
static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2221
int ast_truncstream(struct ast_filestream *fs)
Trunc stream at current location.
Definition: file.c:884
static struct agi_commands agi_commands
int ast_sched_runq(struct sched_context *con)
Runs the queue.
Definition: sched.c:600
const char * usage
Definition: cli.h:171
int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int ctrlfd)
Wait for a digit Same as ast_waitfordigit() with audio fd for outputting read audio and ctrlfd to mon...
Definition: channel.c:3616
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
Definition: pbx.c:10546
unsigned int fast
Definition: agi.h:38
int ast_srv_lookup(struct srv_context **context, const char *service, const char **host, unsigned short *port)
Retrieve set of SRV lookups, in order.
Definition: srv.c:206
ast_mutex_t lock
Definition: speech.h:53
#define CLI_SUCCESS
Definition: cli.h:43
static struct ast_threadstorage agi_buf
Definition: res_agi.c:938
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:471
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Return non-zero if this is silence. Updates &quot;totalsilence&quot; with the total number of seconds of silenc...
Definition: dsp.c:1355
static char * eapp
Definition: res_agi.c:911
void * data
Definition: datastore.h:56
int transit_network_select
Transit Network Select.
Definition: channel.h:347
struct hostent * ast_gethostbyname(const char *host, struct ast_hostent *hp)
Thread-safe gethostbyname function to use in Asterisk.
Definition: utils.c:195
int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int monfd)
Definition: file.c:1348
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition: mod_format.h:100
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2491
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3539
int dtimeoutms
Definition: pbx.h:180
SAY_EXTERN int(* ast_say_digit_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, int audiofd, int ctrlfd) SAY_INIT(ast_say_digit_str_full)
Definition: say.h:140
Standard Command Line Interface.
format_t readformat
Definition: channel.h:853
static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2896
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: db.c:365
#define ast_calloc(a, b)
Definition: astmm.h:82
#define AGI_PORT
Definition: res_agi.c:922
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
Definition: strings.h:446
char * cmd_buffer
Definition: res_agi.c:972
static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2693
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
ast_app: A registered application
Definition: pbx.c:971
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition: file.c:150
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is &quot;false&quot;...
Definition: utils.c:1550
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
const int pos
Definition: cli.h:158
SAY_EXTERN int(* ast_say_date_with_format)(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *timezone) SAY_INIT(ast_say_date_with_format)
Definition: say.h:168
static char * handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: res_agi.c:3800
static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:1816
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1343
int ast_sched_wait(struct sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place Determine the number of s...
Definition: sched.c:334
static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2202
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:3086
#define MAX_ARGS
Definition: res_agi.c:903
static void free_agi_cmd(struct agi_cmd *cmd)
Definition: res_agi.c:977
static int deadagi_exec(struct ast_channel *chan, const char *data)
Definition: res_agi.c:3921
static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2212
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define AGI_BUF_LEN
Definition: res_agi.c:906
const ast_string_field accountcode
Definition: channel.h:787
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Definition: cli.c:1547
Data structure associated with a single frame of data.
Definition: frame.h:142
#define AST_TEST_DEFINE(hdr)
Definition: test.h:126
char * processing_sound
Definition: speech.h:57
SAY_EXTERN int(* ast_say_number_full)(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) SAY_INIT(ast_say_number_full)
Definition: say.h:86
static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2467
Handy terminal functions for vt* terms.
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: db.c:260
Definition: agi.h:34
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
enum ast_frame_type frametype
Definition: frame.h:144
static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2671
#define AST_OPTIONAL_API_NAME(name)
Definition: optional_api.h:217
static void write_html_escaped(FILE *htmlfile, char *str)
Convert string to use HTML escaped characters.
Definition: res_agi.c:3720
struct ast_filestream * vfs
Definition: mod_format.h:109
#define ast_frfree(fr)
Definition: frame.h:583
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:229
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
static struct ast_str * prompt
Definition: asterisk.c:2395
static char * handle_cli_agi_add_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command to add applications to execute in Async AGI.
Definition: res_agi.c:1103
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
SAY_EXTERN int(* ast_say_time)(struct ast_channel *chan, time_t t, const char *ints, const char *lang) SAY_INIT(ast_say_time)
Definition: say.h:162
int ast_speech_write(struct ast_speech *speech, void *data, int len)
Write audio to the speech engine.
Definition: res_speech.c:145
static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2161
int ast_speech_grammar_load(struct ast_speech *speech, const char *grammar_name, const char *grammar)
Load a grammar on a speech structure (not globally)
Definition: res_speech.c:79
enum ast_doc_src docsrc
Definition: agi.h:58
struct ast_filestream * stream
Definition: channel.h:757
void ast_shrink_phone_number(char *n)
Shrink a phone number in place to just digits (more accurately it just removes ()&#39;s, .&#39;s, and -&#39;s...
Definition: callerid.c:948
static enum agi_result launch_script(struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
Definition: res_agi.c:1601
Say numbers and dates (maybe words one day too)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:219
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1803
#define RESULT_SUCCESS
Definition: cli.h:39
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:1880
#define ast_malloc(a)
Definition: astmm.h:91
static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2555
#define SRV_PREFIX
Definition: res_agi.c:907
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:2130
Asterisk module definitions.
static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:1784
static struct hostent * hp
Definition: chan_skinny.c:1048
static struct ast_datastore_info agi_commands_datastore_info
Definition: res_agi.c:999
const char * ast_config_AST_VAR_DIR
Definition: asterisk.c:261
static snd_pcm_format_t format
Definition: chan_alsa.c:93
union ast_frame::@172 data
struct ast_channel_tech * tech
Definition: channel.h:743
static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2069
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2590
Persistant data storage (akin to *doze registry)
int ast_speech_change(struct ast_speech *speech, const char *name, const char *value)
Change an engine specific attribute.
Definition: res_speech.c:170
static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2127
static int unload_module(void)
Definition: res_agi.c:3974
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:247
static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:1881
static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2175
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:602
const ast_string_field language
Definition: channel.h:787
int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
Unregisters an AGI command.
Definition: res_agi.c:3169
int ast_agi_send(int fd, struct ast_channel *chan, char *fmt,...)
Sends a string of text to an application connected via AGI.
Definition: res_agi.c:941
char exten[AST_MAX_EXTENSION]
Definition: channel.h:869
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:128
int ast_db_deltree(const char *family, const char *keytree)
Delete one or more entries in astdb If both parameters are NULL, the entire database will be purged...
Definition: db.c:241
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2823
#define RESULT_FAILURE
Definition: cli.h:41
static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
Definition: res_agi.c:1445
struct ast_filestream * ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
Opens stream for use in seeking, playing.
Definition: file.c:636
int ast_manager_unregister(char *action)
Unregister a registered manager command.
Definition: manager.c:5355
jack_status_t status
Definition: app_jack.c:143
struct ast_speech * ast_speech_new(const char *engine_name, int formats)
Create a new speech structure.
Definition: res_speech.c:176
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
#define COLOR_MAGENTA
Definition: term.h:57
#define ast_mutex_unlock(a)
Definition: lock.h:156
struct ast_pbx * pbx
Definition: channel.h:761
int ast_sendtext(struct ast_channel *chan, const char *text)
Sends text to a channel.
Definition: channel.c:4687
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)
Definition: callerid.c:1009
static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Definition: res_agi.c:2621
struct ast_module * ast_module_ref(struct ast_module *)
Definition: loader.c:1300
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:292