Wed Jan 27 20:02:13 2016

Asterisk developer's documentation


res_agi.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief AGI - the Asterisk Gateway Interface
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  *
00025  * \todo Convert the rest of the AGI commands over to XML documentation
00026  */
00027 
00028 /*** MODULEINFO
00029    <support_level>core</support_level>
00030  ***/
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426363 $")
00035 
00036 #include <math.h>
00037 #include <signal.h>
00038 #include <sys/time.h>
00039 #include <sys/wait.h>
00040 #include <sys/stat.h>
00041 #include <pthread.h>
00042 
00043 #include "asterisk/paths.h"   /* use many ast_config_AST_*_DIR */
00044 #include "asterisk/network.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/channel.h"
00047 #include "asterisk/pbx.h"
00048 #include "asterisk/module.h"
00049 #include "asterisk/astdb.h"
00050 #include "asterisk/callerid.h"
00051 #include "asterisk/cli.h"
00052 #include "asterisk/image.h"
00053 #include "asterisk/say.h"
00054 #include "asterisk/app.h"
00055 #include "asterisk/dsp.h"
00056 #include "asterisk/musiconhold.h"
00057 #include "asterisk/utils.h"
00058 #include "asterisk/lock.h"
00059 #include "asterisk/strings.h"
00060 #include "asterisk/manager.h"
00061 #include "asterisk/ast_version.h"
00062 #include "asterisk/speech.h"
00063 #include "asterisk/manager.h"
00064 #include "asterisk/term.h"
00065 #include "asterisk/xmldoc.h"
00066 #include "asterisk/srv.h"
00067 #include "asterisk/test.h"
00068 
00069 #define AST_API_MODULE
00070 #include "asterisk/agi.h"
00071 
00072 /*** DOCUMENTATION
00073    <agi name="answer" language="en_US">
00074       <synopsis>
00075          Answer channel
00076       </synopsis>
00077       <syntax />
00078       <description>
00079          <para>Answers channel if not already in answer state. Returns <literal>-1</literal> on
00080          channel failure, or <literal>0</literal> if successful.</para>
00081       </description>
00082       <see-also>
00083          <ref type="agi">hangup</ref>
00084       </see-also>
00085    </agi>
00086    <agi name="asyncagi break" language="en_US">
00087       <synopsis>
00088          Interrupts Async AGI
00089       </synopsis>
00090       <syntax />
00091       <description>
00092          <para>Interrupts expected flow of Async AGI commands and returns control to previous source
00093          (typically, the PBX dialplan).</para>
00094       </description>
00095       <see-also>
00096          <ref type="agi">hangup</ref>
00097       </see-also>
00098    </agi>
00099    <agi name="channel status" language="en_US">
00100       <synopsis>
00101          Returns status of the connected channel.
00102       </synopsis>
00103       <syntax>
00104          <parameter name="channelname" />
00105       </syntax>
00106       <description>
00107          <para>Returns the status of the specified <replaceable>channelname</replaceable>.
00108          If no channel name is given then returns the status of the current channel.</para>
00109          <para>Return values:</para>
00110          <enumlist>
00111             <enum name="0">
00112                <para>Channel is down and available.</para>
00113             </enum>
00114             <enum name="1">
00115                <para>Channel is down, but reserved.</para>
00116             </enum>
00117             <enum name="2">
00118                <para>Channel is off hook.</para>
00119             </enum>
00120             <enum name="3">
00121                <para>Digits (or equivalent) have been dialed.</para>
00122             </enum>
00123             <enum name="4">
00124                <para>Line is ringing.</para>
00125             </enum>
00126             <enum name="5">
00127                <para>Remote end is ringing.</para>
00128             </enum>
00129             <enum name="6">
00130                <para>Line is up.</para>
00131             </enum>
00132             <enum name="7">
00133                <para>Line is busy.</para>
00134             </enum>
00135          </enumlist>
00136       </description>
00137    </agi>
00138    <agi name="control stream file" language="en_US">
00139       <synopsis>
00140          Sends audio file on channel and allows the listener to control the stream.
00141       </synopsis>
00142       <syntax>
00143          <parameter name="filename" required="true">
00144             <para>The file extension must not be included in the filename.</para>
00145          </parameter>
00146          <parameter name="escape_digits" required="true" />
00147          <parameter name="skipms" />
00148          <parameter name="ffchar">
00149             <para>Defaults to <literal>#</literal></para>
00150          </parameter>
00151          <parameter name="rewchr">
00152             <para>Defaults to <literal>*</literal></para>
00153          </parameter>
00154          <parameter name="pausechr" />
00155       </syntax>
00156       <description>
00157          <para>Send the given file, allowing playback to be controlled by the given
00158          digits, if any. Use double quotes for the digits if you wish none to be
00159          permitted. Returns <literal>0</literal> if playback completes without a digit
00160          being pressed, or the ASCII numerical value of the digit if one was pressed,
00161          or <literal>-1</literal> on error or if the channel was disconnected.</para>
00162       </description>
00163    </agi>
00164    <agi name="database del" language="en_US">
00165       <synopsis>
00166          Removes database key/value
00167       </synopsis>
00168       <syntax>
00169          <parameter name="family" required="true" />
00170          <parameter name="key" required="true" />
00171       </syntax>
00172       <description>
00173          <para>Deletes an entry in the Asterisk database for a given
00174          <replaceable>family</replaceable> and <replaceable>key</replaceable>.</para>
00175          <para>Returns <literal>1</literal> if successful, <literal>0</literal>
00176          otherwise.</para>
00177       </description>
00178    </agi>
00179    <agi name="database deltree" language="en_US">
00180       <synopsis>
00181          Removes database keytree/value
00182       </synopsis>
00183       <syntax>
00184          <parameter name="family" required="true" />
00185          <parameter name="keytree" />
00186       </syntax>
00187       <description>
00188          <para>Deletes a <replaceable>family</replaceable> or specific <replaceable>keytree</replaceable>
00189          within a <replaceable>family</replaceable> in the Asterisk database.</para>
00190          <para>Returns <literal>1</literal> if successful, <literal>0</literal> otherwise.</para>
00191       </description>
00192    </agi>
00193    <agi name="database get" language="en_US">
00194       <synopsis>
00195          Gets database value
00196       </synopsis>
00197       <syntax>
00198          <parameter name="family" required="true" />
00199          <parameter name="key" required="true" />
00200       </syntax>
00201       <description>
00202          <para>Retrieves an entry in the Asterisk database for a given <replaceable>family</replaceable>
00203          and <replaceable>key</replaceable>.</para>
00204          <para>Returns <literal>0</literal> if <replaceable>key</replaceable> is not set.
00205          Returns <literal>1</literal> if <replaceable>key</replaceable> is set and returns the variable
00206          in parenthesis.</para>
00207          <para>Example return code: 200 result=1 (testvariable)</para>
00208       </description>
00209    </agi>
00210    <agi name="database put" language="en_US">
00211       <synopsis>
00212          Adds/updates database value
00213       </synopsis>
00214       <syntax>
00215          <parameter name="family" required="true" />
00216          <parameter name="key" required="true" />
00217          <parameter name="value" required="true" />
00218       </syntax>
00219       <description>
00220          <para>Adds or updates an entry in the Asterisk database for a given
00221          <replaceable>family</replaceable>, <replaceable>key</replaceable>, and
00222          <replaceable>value</replaceable>.</para>
00223          <para>Returns <literal>1</literal> if successful, <literal>0</literal> otherwise.</para>
00224       </description>
00225    </agi>
00226    <agi name="exec" language="en_US">
00227       <synopsis>
00228          Executes a given Application
00229       </synopsis>
00230       <syntax>
00231          <parameter name="application" required="true" />
00232          <parameter name="options" required="true" />
00233       </syntax>
00234       <description>
00235          <para>Executes <replaceable>application</replaceable> with given
00236          <replaceable>options</replaceable>.</para>
00237          <para>Returns whatever the <replaceable>application</replaceable> returns, or
00238          <literal>-2</literal> on failure to find <replaceable>application</replaceable>.</para>
00239       </description>
00240    </agi>
00241    <agi name="get data" language="en_US">
00242       <synopsis>
00243          Prompts for DTMF on a channel
00244       </synopsis>
00245       <syntax>
00246          <parameter name="file" required="true" />
00247          <parameter name="timeout" />
00248          <parameter name="maxdigits" />
00249       </syntax>
00250       <description>
00251          <para>Stream the given <replaceable>file</replaceable>, and receive DTMF data.</para>
00252          <para>Returns the digits received from the channel at the other end.</para>
00253       </description>
00254    </agi>
00255    <agi name="get full variable" language="en_US">
00256       <synopsis>
00257          Evaluates a channel expression
00258       </synopsis>
00259       <syntax>
00260          <parameter name="variablename" required="true" />
00261          <parameter name="channel name" />
00262       </syntax>
00263       <description>
00264          <para>Returns <literal>0</literal> if <replaceable>variablename</replaceable> is not set
00265          or channel does not exist. Returns <literal>1</literal> if <replaceable>variablename</replaceable>
00266          is set and returns the variable in parenthesis. Understands complex variable names and builtin
00267          variables, unlike GET VARIABLE.</para>
00268          <para>Example return code: 200 result=1 (testvariable)</para>
00269       </description>
00270    </agi>
00271    <agi name="get option" language="en_US">
00272       <synopsis>
00273          Stream file, prompt for DTMF, with timeout.
00274       </synopsis>
00275       <syntax>
00276          <parameter name="filename" required="true" />
00277          <parameter name="escape_digits" required="true" />
00278          <parameter name="timeout" />
00279       </syntax>
00280       <description>
00281          <para>Behaves similar to STREAM FILE but used with a timeout option.</para>
00282       </description>
00283       <see-also>
00284          <ref type="agi">stream file</ref>
00285       </see-also>
00286    </agi>
00287    <agi name="get variable" language="en_US">
00288       <synopsis>
00289          Gets a channel variable.
00290       </synopsis>
00291       <syntax>
00292          <parameter name="variablename" required="true" />
00293       </syntax>
00294       <description>
00295          <para>Returns <literal>0</literal> if <replaceable>variablename</replaceable> is not set.
00296          Returns <literal>1</literal> if <replaceable>variablename</replaceable> is set and returns
00297          the variable in parentheses.</para>
00298          <para>Example return code: 200 result=1 (testvariable)</para>
00299       </description>
00300    </agi>
00301    <agi name="hangup" language="en_US">
00302       <synopsis>
00303          Hangup a channel.
00304       </synopsis>
00305       <syntax>
00306          <parameter name="channelname" />
00307       </syntax>
00308       <description>
00309          <para>Hangs up the specified channel. If no channel name is given, hangs
00310          up the current channel</para>
00311       </description>
00312    </agi>
00313    <agi name="noop" language="en_US">
00314       <synopsis>
00315          Does nothing.
00316       </synopsis>
00317       <syntax />
00318       <description>
00319          <para>Does nothing.</para>
00320       </description>
00321    </agi>
00322    <agi name="receive char" language="en_US">
00323       <synopsis>
00324          Receives one character from channels supporting it.
00325       </synopsis>
00326       <syntax>
00327          <parameter name="timeout" required="true">
00328             <para>The maximum time to wait for input in milliseconds, or <literal>0</literal>
00329             for infinite. Most channels</para>
00330          </parameter>
00331       </syntax>
00332       <description>
00333          <para>Receives a character of text on a channel. Most channels do not support
00334          the reception of text. Returns the decimal value of the character
00335          if one is received, or <literal>0</literal> if the channel does not support
00336          text reception. Returns <literal>-1</literal> only on error/hangup.</para>
00337       </description>
00338    </agi>
00339    <agi name="receive text" language="en_US">
00340       <synopsis>
00341          Receives text from channels supporting it.
00342       </synopsis>
00343       <syntax>
00344          <parameter name="timeout" required="true">
00345             <para>The timeout to be the maximum time to wait for input in
00346             milliseconds, or <literal>0</literal> for infinite.</para>
00347          </parameter>
00348       </syntax>
00349       <description>
00350          <para>Receives a string of text on a channel. Most channels 
00351          do not support the reception of text. Returns <literal>-1</literal> for failure
00352          or <literal>1</literal> for success, and the string in parenthesis.</para> 
00353       </description>
00354    </agi>
00355    <agi name="record file" language="en_US">
00356       <synopsis>
00357          Records to a given file.
00358       </synopsis>
00359       <syntax>
00360          <parameter name="filename" required="true" />
00361          <parameter name="format" required="true" />
00362          <parameter name="escape_digits" required="true" />
00363          <parameter name="timeout" required="true" />
00364          <parameter name="offset samples" />
00365          <parameter name="BEEP" />
00366          <parameter name="s=silence" />
00367       </syntax>
00368       <description>
00369          <para>Record to a file until a given dtmf digit in the sequence is received.
00370          Returns <literal>-1</literal> on hangup or error.  The format will specify what kind of file
00371          will be recorded. The <replaceable>timeout</replaceable> is the maximum record time in
00372          milliseconds, or <literal>-1</literal> for no <replaceable>timeout</replaceable>.
00373          <replaceable>offset samples</replaceable> is optional, and, if provided, will seek
00374          to the offset without exceeding the end of the file. <replaceable>silence</replaceable> is
00375          the number of seconds of silence allowed before the function returns despite the
00376          lack of dtmf digits or reaching <replaceable>timeout</replaceable>. <replaceable>silence</replaceable>
00377          value must be preceded by <literal>s=</literal> and is also optional.</para>
00378       </description>
00379    </agi>
00380    <agi name="say alpha" language="en_US">
00381       <synopsis>
00382          Says a given character string.
00383       </synopsis>
00384       <syntax>
00385          <parameter name="number" required="true" />
00386          <parameter name="escape_digits" required="true" />
00387       </syntax>
00388       <description>
00389          <para>Say a given character string, returning early if any of the given DTMF digits
00390          are received on the channel. Returns <literal>0</literal> if playback completes
00391          without a digit being pressed, or the ASCII numerical value of the digit if one
00392          was pressed or <literal>-1</literal> on error/hangup.</para>
00393       </description>
00394    </agi>
00395    <agi name="say digits" language="en_US">
00396       <synopsis>
00397          Says a given digit string.
00398       </synopsis>
00399       <syntax>
00400          <parameter name="number" required="true" />
00401          <parameter name="escape_digits" required="true" />
00402       </syntax>
00403       <description>
00404          <para>Say a given digit string, returning early if any of the given DTMF digits
00405          are received on the channel. Returns <literal>0</literal> if playback completes
00406          without a digit being pressed, or the ASCII numerical value of the digit if one
00407          was pressed or <literal>-1</literal> on error/hangup.</para>
00408       </description>
00409    </agi>
00410    <agi name="say number" language="en_US">
00411       <synopsis>
00412          Says a given number.
00413       </synopsis>
00414       <syntax>
00415          <parameter name="number" required="true" />
00416          <parameter name="escape_digits" required="true" />
00417          <parameter name="gender" />
00418       </syntax>
00419       <description>
00420          <para>Say a given number, returning early if any of the given DTMF digits
00421          are received on the channel.  Returns <literal>0</literal> if playback
00422          completes without a digit being pressed, or the ASCII numerical value of
00423          the digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
00424       </description>
00425    </agi>
00426    <agi name="say phonetic" language="en_US">
00427       <synopsis>
00428          Says a given character string with phonetics.
00429       </synopsis>
00430       <syntax>
00431          <parameter name="string" required="true" />
00432          <parameter name="escape_digits" required="true" />
00433       </syntax>
00434       <description>
00435          <para>Say a given character string with phonetics, returning early if any of the
00436          given DTMF digits are received on the channel. Returns <literal>0</literal> if
00437          playback completes without a digit pressed, the ASCII numerical value of the digit
00438          if one was pressed, or <literal>-1</literal> on error/hangup.</para>
00439       </description>
00440    </agi>
00441    <agi name="say date" language="en_US">
00442       <synopsis>
00443          Says a given date.
00444       </synopsis>
00445       <syntax>
00446          <parameter name="date" required="true">
00447             <para>Is number of seconds elapsed since 00:00:00 on January 1, 1970.
00448             Coordinated Universal Time (UTC).</para>
00449          </parameter>
00450          <parameter name="escape_digits" required="true" />
00451       </syntax>
00452       <description>
00453          <para>Say a given date, returning early if any of the given DTMF digits are
00454          received on the channel. Returns <literal>0</literal> if playback
00455          completes without a digit being pressed, or the ASCII numerical value of the
00456          digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
00457       </description>
00458    </agi>
00459    <agi name="say time" language="en_US">
00460       <synopsis>
00461          Says a given time.
00462       </synopsis>
00463       <syntax>
00464          <parameter name="time" required="true">
00465             <para>Is number of seconds elapsed since 00:00:00 on January 1, 1970.
00466             Coordinated Universal Time (UTC).</para>
00467          </parameter>
00468          <parameter name="escape_digits" required="true" />
00469       </syntax>
00470       <description>
00471          <para>Say a given time, returning early if any of the given DTMF digits are
00472          received on the channel. Returns <literal>0</literal> if playback completes
00473          without a digit being pressed, or the ASCII numerical value of the digit if
00474          one was pressed or <literal>-1</literal> on error/hangup.</para>
00475       </description>
00476    </agi>
00477    <agi name="say datetime" language="en_US">
00478       <synopsis>
00479          Says a given time as specified by the format given.
00480       </synopsis>
00481       <syntax>
00482          <parameter name="time" required="true">
00483             <para>Is number of seconds elapsed since 00:00:00
00484             on January 1, 1970, Coordinated Universal Time (UTC)</para>
00485          </parameter>
00486          <parameter name="escape_digits" required="true" />
00487          <parameter name="format">
00488             <para>Is the format the time should be said in. See
00489             <filename>voicemail.conf</filename> (defaults to <literal>ABdY
00490             'digits/at' IMp</literal>).</para>
00491          </parameter>
00492          <parameter name="timezone">
00493             <para>Acceptable values can be found in <filename>/usr/share/zoneinfo</filename>
00494             Defaults to machine default.</para>
00495          </parameter>
00496       </syntax>
00497       <description>
00498          <para>Say a given time, returning early if any of the given DTMF digits are
00499          received on the channel. Returns <literal>0</literal> if playback
00500          completes without a digit being pressed, or the ASCII numerical value of the
00501          digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
00502       </description>
00503    </agi>
00504    <agi name="send image" language="en_US">
00505       <synopsis>
00506          Sends images to channels supporting it.
00507       </synopsis>
00508       <syntax>
00509          <parameter name="image" required="true" />
00510       </syntax>
00511       <description>
00512          <para>Sends the given image on a channel. Most channels do not support the
00513          transmission of images. Returns <literal>0</literal> if image is sent, or if
00514          the channel does not support image transmission.  Returns <literal>-1</literal>
00515          only on error/hangup. Image names should not include extensions.</para>
00516       </description>
00517    </agi>
00518    <agi name="send text" language="en_US">
00519       <synopsis>
00520          Sends text to channels supporting it.
00521       </synopsis>
00522       <syntax>
00523          <parameter name="text to send" required="true">
00524             <para>Text consisting of greater than one word should be placed
00525             in quotes since the command only accepts a single argument.</para>
00526          </parameter>
00527       </syntax>
00528       <description>
00529          <para>Sends the given text on a channel. Most channels do not support the
00530          transmission of text. Returns <literal>0</literal> if text is sent, or if the
00531          channel does not support text transmission. Returns <literal>-1</literal> only
00532          on error/hangup.</para>
00533       </description>
00534    </agi>
00535    <agi name="set autohangup" language="en_US">
00536       <synopsis>
00537          Autohangup channel in some time.
00538       </synopsis>
00539       <syntax>
00540          <parameter name="time" required="true" />
00541       </syntax>
00542       <description>
00543          <para>Cause the channel to automatically hangup at <replaceable>time</replaceable>
00544          seconds in the future. Of course it can be hungup before then as well. Setting to
00545          <literal>0</literal> will cause the autohangup feature to be disabled on this channel.</para>
00546       </description>
00547    </agi>
00548    <agi name="set callerid" language="en_US">
00549       <synopsis>
00550          Sets callerid for the current channel.
00551       </synopsis>
00552       <syntax>
00553          <parameter name="number" required="true" />
00554       </syntax>
00555       <description>
00556          <para>Changes the callerid of the current channel.</para>
00557       </description>
00558    </agi>
00559    <agi name="set context" language="en_US">
00560       <synopsis>
00561          Sets channel context.
00562       </synopsis>
00563       <syntax>
00564          <parameter name="desired context" required="true" />
00565       </syntax>
00566       <description>
00567          <para>Sets the context for continuation upon exiting the application.</para>
00568       </description>
00569    </agi>
00570    <agi name="set extension" language="en_US">
00571       <synopsis>
00572          Changes channel extension.
00573       </synopsis>
00574       <syntax>
00575          <parameter name="new extension" required="true" />
00576       </syntax>
00577       <description>
00578          <para>Changes the extension for continuation upon exiting the application.</para>
00579       </description>
00580    </agi>
00581    <agi name="set music" language="en_US">
00582       <synopsis>
00583          Enable/Disable Music on hold generator
00584       </synopsis>
00585       <syntax>
00586          <parameter required="true">
00587             <enumlist>
00588                <enum>
00589                   <parameter name="on" literal="true" required="true" />
00590                </enum>
00591                <enum>
00592                   <parameter name="off" literal="true" required="true" />
00593                </enum>
00594             </enumlist>
00595          </parameter>
00596          <parameter name="class" required="true" />
00597       </syntax>
00598       <description>
00599          <para>Enables/Disables the music on hold generator. If <replaceable>class</replaceable>
00600          is not specified, then the <literal>default</literal> music on hold class will be
00601          used. This generator will be stopped automatically when playing a file.</para>
00602          <para>Always returns <literal>0</literal>.</para>
00603       </description>
00604    </agi>
00605    <agi name="set priority" language="en_US">
00606       <synopsis>
00607          Set channel dialplan priority.
00608       </synopsis>
00609       <syntax>
00610          <parameter name="priority" required="true" />
00611       </syntax>
00612       <description>
00613          <para>Changes the priority for continuation upon exiting the application.
00614          The priority must be a valid priority or label.</para>
00615       </description>
00616    </agi>
00617    <agi name="set variable" language="en_US">
00618       <synopsis>
00619          Sets a channel variable.
00620       </synopsis>
00621       <syntax>
00622          <parameter name="variablename" required="true" />
00623          <parameter name="value" required="true" />
00624       </syntax>
00625       <description>
00626          <para>Sets a variable to the current channel.</para>
00627       </description>
00628    </agi>
00629    <agi name="stream file" language="en_US">
00630       <synopsis>
00631          Sends audio file on channel.
00632       </synopsis>
00633       <syntax>
00634          <parameter name="filename" required="true">
00635             <para>File name to play. The file extension must not be
00636             included in the <replaceable>filename</replaceable>.</para>
00637          </parameter>
00638          <parameter name="escape_digits" required="true">
00639             <para>Use double quotes for the digits if you wish none to be
00640             permitted.</para>
00641          </parameter>
00642          <parameter name="sample offset">
00643             <para>If sample offset is provided then the audio will seek to sample
00644             offset before play starts.</para>
00645          </parameter>
00646       </syntax>
00647       <description>
00648          <para>Send the given file, allowing playback to be interrupted by the given
00649          digits, if any. Returns <literal>0</literal> if playback completes without a digit
00650          being pressed, or the ASCII numerical value of the digit if one was pressed,
00651          or <literal>-1</literal> on error or if the channel was disconnected. If
00652          musiconhold is playing before calling stream file it will be automatically
00653          stopped and will not be restarted after completion.</para>
00654       </description>
00655       <see-also>
00656          <ref type="agi">control stream file</ref>
00657       </see-also>
00658    </agi>
00659    <agi name="tdd mode" language="en_US">
00660       <synopsis>
00661          Toggles TDD mode (for the deaf).
00662       </synopsis>
00663       <syntax>
00664          <parameter name="boolean" required="true">
00665             <enumlist>
00666                <enum name="on" />
00667                <enum name="off" />
00668             </enumlist>
00669          </parameter>
00670       </syntax>
00671       <description>
00672          <para>Enable/Disable TDD transmission/reception on a channel. Returns <literal>1</literal> if
00673          successful, or <literal>0</literal> if channel is not TDD-capable.</para>
00674       </description>
00675    </agi>
00676    <agi name="verbose" language="en_US">
00677       <synopsis>
00678          Logs a message to the asterisk verbose log.
00679       </synopsis>
00680       <syntax>
00681          <parameter name="message" required="true" />
00682          <parameter name="level" required="true" />
00683       </syntax>
00684       <description>
00685          <para>Sends <replaceable>message</replaceable> to the console via verbose
00686          message system. <replaceable>level</replaceable> is the verbose level (1-4).
00687          Always returns <literal>1</literal></para>
00688       </description>
00689    </agi>
00690    <agi name="wait for digit" language="en_US">
00691       <synopsis>
00692          Waits for a digit to be pressed.
00693       </synopsis>
00694       <syntax>
00695          <parameter name="timeout" required="true" />
00696       </syntax>
00697       <description>
00698          <para>Waits up to <replaceable>timeout</replaceable> milliseconds for channel to
00699          receive a DTMF digit. Returns <literal>-1</literal> on channel failure, <literal>0</literal>
00700          if no digit is received in the timeout, or the numerical value of the ascii of the digit if
00701          one is received. Use <literal>-1</literal> for the <replaceable>timeout</replaceable> value if
00702          you desire the call to block indefinitely.</para>
00703       </description>
00704    </agi>
00705    <agi name="speech create" language="en_US">
00706       <synopsis>
00707          Creates a speech object.
00708       </synopsis>
00709       <syntax>
00710          <parameter name="engine" required="true" />
00711       </syntax>
00712       <description>
00713          <para>Create a speech object to be used by the other Speech AGI commands.</para>
00714       </description>
00715    </agi>
00716    <agi name="speech set" language="en_US">
00717       <synopsis>
00718          Sets a speech engine setting.
00719       </synopsis>
00720       <syntax>
00721          <parameter name="name" required="true" />
00722          <parameter name="value" required="true" />
00723       </syntax>
00724       <description>
00725          <para>Set an engine-specific setting.</para>
00726       </description>
00727    </agi>
00728    <agi name="speech destroy" language="en_US">
00729       <synopsis>
00730          Destroys a speech object.
00731       </synopsis>
00732       <syntax>
00733       </syntax>
00734       <description>
00735          <para>Destroy the speech object created by <literal>SPEECH CREATE</literal>.</para>
00736       </description>
00737       <see-also>
00738          <ref type="agi">speech create</ref>
00739       </see-also>
00740    </agi>
00741    <agi name="speech load grammar" language="en_US">
00742       <synopsis>
00743          Loads a grammar.
00744       </synopsis>
00745       <syntax>
00746          <parameter name="grammar name" required="true" />
00747          <parameter name="path to grammar" required="true" />
00748       </syntax>
00749       <description>
00750          <para>Loads the specified grammar as the specified name.</para>
00751       </description>
00752    </agi>
00753    <agi name="speech unload grammar" language="en_US">
00754       <synopsis>
00755          Unloads a grammar.
00756       </synopsis>
00757       <syntax>
00758          <parameter name="grammar name" required="true" />
00759       </syntax>
00760       <description>
00761          <para>Unloads the specified grammar.</para>
00762       </description>
00763    </agi>
00764    <agi name="speech activate grammar" language="en_US">
00765       <synopsis>
00766          Activates a grammar.
00767       </synopsis>
00768       <syntax>
00769          <parameter name="grammar name" required="true" />
00770       </syntax>
00771       <description>
00772          <para>Activates the specified grammar on the speech object.</para>
00773       </description>
00774    </agi>
00775    <agi name="speech deactivate grammar" language="en_US">
00776       <synopsis>
00777          Deactivates a grammar.
00778       </synopsis>
00779       <syntax>
00780          <parameter name="grammar name" required="true" />
00781       </syntax>
00782       <description>
00783          <para>Deactivates the specified grammar on the speech object.</para>
00784       </description>
00785    </agi>
00786    <agi name="speech recognize" language="en_US">
00787       <synopsis>
00788          Recognizes speech.
00789       </synopsis>
00790       <syntax>
00791          <parameter name="prompt" required="true" />
00792          <parameter name="timeout" required="true" />
00793          <parameter name="offset" />
00794       </syntax>
00795       <description>
00796          <para>Plays back given <replaceable>prompt</replaceable> while listening for
00797          speech and dtmf.</para>
00798       </description>
00799    </agi>
00800    <application name="AGI" language="en_US">
00801       <synopsis>
00802          Executes an AGI compliant application.
00803       </synopsis>
00804       <syntax>
00805          <parameter name="command" required="true" />
00806          <parameter name="args">
00807             <argument name="arg1" required="true" />
00808             <argument name="arg2" multiple="yes" />
00809          </parameter>
00810       </syntax>
00811       <description>
00812          <para>Executes an Asterisk Gateway Interface compliant
00813          program on a channel. AGI allows Asterisk to launch external programs written
00814          in any language to control a telephony channel, play audio, read DTMF digits,
00815          etc. by communicating with the AGI protocol on <emphasis>stdin</emphasis> and
00816          <emphasis>stdout</emphasis>. As of <literal>1.6.0</literal>, this channel will
00817          not stop dialplan execution on hangup inside of this application. Dialplan
00818          execution will continue normally, even upon hangup until the AGI application
00819          signals a desire to stop (either by exiting or, in the case of a net script, by
00820          closing the connection). A locally executed AGI script will receive SIGHUP on
00821          hangup from the channel except when using DeadAGI. A fast AGI server will
00822          correspondingly receive a HANGUP inline with the command dialog. Both of theses
00823          signals may be disabled by setting the <variable>AGISIGHUP</variable> channel
00824          variable to <literal>no</literal> before executing the AGI application.</para>
00825          <para>Use the CLI command <literal>agi show commands</literal> to list available agi
00826          commands.</para>
00827          <para>This application sets the following channel variable upon completion:</para>
00828          <variablelist>
00829             <variable name="AGISTATUS">
00830                <para>The status of the attempt to the run the AGI script
00831                text string, one of:</para>
00832                <value name="SUCCESS" />
00833                <value name="FAILURE" />
00834                <value name="NOTFOUND" />
00835                <value name="HANGUP" />
00836             </variable>
00837          </variablelist>
00838       </description>
00839       <see-also>
00840          <ref type="application">EAGI</ref>
00841          <ref type="application">DeadAGI</ref>
00842       </see-also>
00843    </application>
00844    <application name="EAGI" language="en_US">
00845       <synopsis>
00846          Executes an EAGI compliant application.
00847       </synopsis>
00848       <syntax>
00849          <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='command'])" />
00850          <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='args'])" />
00851       </syntax>
00852       <description>
00853          <para>Using 'EAGI' provides enhanced AGI, with incoming audio available out of band
00854          on file descriptor 3.</para>
00855          <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/para)" />
00856          <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/variablelist)" />
00857       </description>
00858       <see-also>
00859          <ref type="application">AGI</ref>
00860          <ref type="application">DeadAGI</ref>
00861       </see-also>
00862    </application>
00863    <application name="DeadAGI" language="en_US">
00864       <synopsis>
00865          Executes AGI on a hungup channel.
00866       </synopsis>
00867       <syntax>
00868          <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='command'])" />
00869          <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='args'])" />
00870       </syntax>
00871       <description>
00872          <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/para)" />
00873          <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/variablelist)" />
00874       </description>
00875       <see-also>
00876          <ref type="application">AGI</ref>
00877          <ref type="application">EAGI</ref>
00878       </see-also>
00879    </application>
00880    <manager name="AGI" language="en_US">
00881       <synopsis>
00882          Add an AGI command to execute by Async AGI.
00883       </synopsis>
00884       <syntax>
00885          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00886          <parameter name="Channel" required="true">
00887             <para>Channel that is currently in Async AGI.</para>
00888          </parameter>
00889          <parameter name="Command" required="true">
00890             <para>Application to execute.</para>
00891          </parameter>
00892          <parameter name="CommandID">
00893             <para>This will be sent back in CommandID header of AsyncAGI exec
00894             event notification.</para>
00895          </parameter>
00896       </syntax>
00897       <description>
00898          <para>Add an AGI command to the execute queue of the channel in Async AGI.</para>
00899       </description>
00900    </manager>
00901  ***/
00902 
00903 #define MAX_ARGS 128
00904 #define MAX_CMD_LEN 80
00905 #define AGI_NANDFS_RETRY 3
00906 #define AGI_BUF_LEN 2048
00907 #define SRV_PREFIX "_agi._tcp."
00908 
00909 static char *app = "AGI";
00910 
00911 static char *eapp = "EAGI";
00912 
00913 static char *deadapp = "DeadAGI";
00914 
00915 static int agidebug = 0;
00916 
00917 #define TONE_BLOCK_SIZE 200
00918 
00919 /* Max time to connect to an AGI remote host */
00920 #define MAX_AGI_CONNECT 2000
00921 
00922 #define AGI_PORT 4573
00923 
00924 /*! Special return code for "asyncagi break" command. */
00925 #define ASYNC_AGI_BREAK 3
00926 
00927 enum agi_result {
00928    AGI_RESULT_FAILURE = -1,
00929    AGI_RESULT_SUCCESS,
00930    AGI_RESULT_SUCCESS_FAST,
00931    AGI_RESULT_SUCCESS_ASYNC,
00932    AGI_RESULT_NOTFOUND,
00933    AGI_RESULT_HANGUP,
00934 };
00935 
00936 static agi_command *find_command(const char * const cmds[], int exact);
00937 
00938 AST_THREADSTORAGE(agi_buf);
00939 #define AGI_BUF_INITSIZE 256
00940 
00941 int AST_OPTIONAL_API_NAME(ast_agi_send)(int fd, struct ast_channel *chan, char *fmt, ...)
00942 {
00943    int res = 0;
00944    va_list ap;
00945    struct ast_str *buf;
00946 
00947    if (!(buf = ast_str_thread_get(&agi_buf, AGI_BUF_INITSIZE)))
00948       return -1;
00949 
00950    va_start(ap, fmt);
00951    res = ast_str_set_va(&buf, 0, fmt, ap);
00952    va_end(ap);
00953 
00954    if (res == -1) {
00955       ast_log(LOG_ERROR, "Out of memory\n");
00956       return -1;
00957    }
00958 
00959    if (agidebug) {
00960       if (chan) {
00961          ast_verbose("<%s>AGI Tx >> %s", chan->name, ast_str_buffer(buf));
00962       } else {
00963          ast_verbose("AGI Tx >> %s", ast_str_buffer(buf));
00964       }
00965    }
00966 
00967    return ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
00968 }
00969 
00970 /* linked list of AGI commands ready to be executed by Async AGI */
00971 struct agi_cmd {
00972    char *cmd_buffer;
00973    char *cmd_id;
00974    AST_LIST_ENTRY(agi_cmd) entry;
00975 };
00976 
00977 static void free_agi_cmd(struct agi_cmd *cmd)
00978 {
00979    ast_free(cmd->cmd_buffer);
00980    ast_free(cmd->cmd_id);
00981    ast_free(cmd);
00982 }
00983 
00984 /* AGI datastore destructor */
00985 static void agi_destroy_commands_cb(void *data)
00986 {
00987    struct agi_cmd *cmd;
00988    AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
00989    AST_LIST_LOCK(chan_cmds);
00990    while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
00991       free_agi_cmd(cmd);
00992    }
00993    AST_LIST_UNLOCK(chan_cmds);
00994    AST_LIST_HEAD_DESTROY(chan_cmds);
00995    ast_free(chan_cmds);
00996 }
00997 
00998 /* channel datastore to keep the queue of AGI commands in the channel */
00999 static const struct ast_datastore_info agi_commands_datastore_info = {
01000    .type = "AsyncAGI",
01001    .destroy = agi_destroy_commands_cb
01002 };
01003 
01004 static struct agi_cmd *get_agi_cmd(struct ast_channel *chan)
01005 {
01006    struct ast_datastore *store;
01007    struct agi_cmd *cmd;
01008    AST_LIST_HEAD(, agi_cmd) *agi_commands;
01009 
01010    ast_channel_lock(chan);
01011    store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
01012    ast_channel_unlock(chan);
01013    if (!store) {
01014       ast_log(LOG_ERROR, "Huh? Async AGI datastore disappeared on Channel %s!\n",
01015          chan->name);
01016       return NULL;
01017    }
01018    agi_commands = store->data;
01019    AST_LIST_LOCK(agi_commands);
01020    cmd = AST_LIST_REMOVE_HEAD(agi_commands, entry);
01021    AST_LIST_UNLOCK(agi_commands);
01022    return cmd;
01023 }
01024 
01025 /* channel is locked when calling this one either from the CLI or manager thread */
01026 static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
01027 {
01028    struct ast_datastore *store;
01029    struct agi_cmd *cmd;
01030    AST_LIST_HEAD(, agi_cmd) *agi_commands;
01031 
01032    store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
01033    if (!store) {
01034       ast_log(LOG_WARNING, "Channel %s is not setup for Async AGI.\n", chan->name);
01035       return -1;
01036    }
01037    agi_commands = store->data;
01038    cmd = ast_calloc(1, sizeof(*cmd));
01039    if (!cmd) {
01040       return -1;
01041    }
01042    cmd->cmd_buffer = ast_strdup(cmd_buff);
01043    if (!cmd->cmd_buffer) {
01044       ast_free(cmd);
01045       return -1;
01046    }
01047    cmd->cmd_id = ast_strdup(cmd_id);
01048    if (!cmd->cmd_id) {
01049       ast_free(cmd->cmd_buffer);
01050       ast_free(cmd);
01051       return -1;
01052    }
01053    AST_LIST_LOCK(agi_commands);
01054    AST_LIST_INSERT_TAIL(agi_commands, cmd, entry);
01055    AST_LIST_UNLOCK(agi_commands);
01056    return 0;
01057 }
01058 
01059 static int add_to_agi(struct ast_channel *chan)
01060 {
01061    struct ast_datastore *datastore;
01062    AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
01063 
01064    /* check if already on AGI */
01065    ast_channel_lock(chan);
01066    datastore = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
01067    ast_channel_unlock(chan);
01068    if (datastore) {
01069       /* we already have an AGI datastore, let's just
01070          return success */
01071       return 0;
01072    }
01073 
01074    /* the channel has never been on Async AGI,
01075       let's allocate it's datastore */
01076    datastore = ast_datastore_alloc(&agi_commands_datastore_info, "AGI");
01077    if (!datastore) {
01078       return -1;
01079    }
01080    agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
01081    if (!agi_cmds_list) {
01082       ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
01083       ast_datastore_free(datastore);
01084       return -1;
01085    }
01086    datastore->data = agi_cmds_list;
01087    AST_LIST_HEAD_INIT(agi_cmds_list);
01088    ast_channel_lock(chan);
01089    ast_channel_datastore_add(chan, datastore);
01090    ast_channel_unlock(chan);
01091    return 0;
01092 }
01093 
01094 /*!
01095  * \brief CLI command to add applications to execute in Async AGI
01096  * \param e
01097  * \param cmd
01098  * \param a
01099  *
01100  * \retval CLI_SUCCESS on success
01101  * \retval NULL when init or tab completion is used
01102 */
01103 static char *handle_cli_agi_add_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01104 {
01105    struct ast_channel *chan;
01106    switch (cmd) {
01107    case CLI_INIT:
01108       e->command = "agi exec";
01109       e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
01110             "       Add AGI command to the execute queue of the specified channel in Async AGI\n";
01111       return NULL;
01112    case CLI_GENERATE:
01113       if (a->pos == 2)
01114          return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
01115       return NULL;
01116    }
01117 
01118    if (a->argc < 4) {
01119       return CLI_SHOWUSAGE;
01120    }
01121 
01122    if (!(chan = ast_channel_get_by_name(a->argv[2]))) {
01123       ast_cli(a->fd, "Channel %s does not exist.\n", a->argv[2]);
01124       return CLI_FAILURE;
01125    }
01126 
01127    ast_channel_lock(chan);
01128 
01129    if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
01130       ast_cli(a->fd, "Failed to add AGI command to queue of channel %s\n", chan->name);
01131       ast_channel_unlock(chan);
01132       chan = ast_channel_unref(chan);
01133       return CLI_FAILURE;
01134    }
01135 
01136    ast_debug(1, "Added AGI command to channel %s queue\n", chan->name);
01137 
01138    ast_channel_unlock(chan);
01139    chan = ast_channel_unref(chan);
01140 
01141    return CLI_SUCCESS;
01142 }
01143 
01144 /*!
01145  * \brief Add a new command to execute by the Async AGI application
01146  * \param s
01147  * \param m
01148  *
01149  * It will append the application to the specified channel's queue
01150  * if the channel is not inside Async AGI application it will return an error
01151  * \retval 0 on success or incorrect use
01152  * \retval 1 on failure to add the command ( most likely because the channel
01153  * is not in Async AGI loop )
01154 */
01155 static int action_add_agi_cmd(struct mansession *s, const struct message *m)
01156 {
01157    const char *channel = astman_get_header(m, "Channel");
01158    const char *cmdbuff = astman_get_header(m, "Command");
01159    const char *cmdid   = astman_get_header(m, "CommandID");
01160    struct ast_channel *chan;
01161    char buf[256];
01162 
01163    if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
01164       astman_send_error(s, m, "Both, Channel and Command are *required*");
01165       return 0;
01166    }
01167 
01168    if (!(chan = ast_channel_get_by_name(channel))) {
01169       snprintf(buf, sizeof(buf), "Channel %s does not exist.", channel);
01170       astman_send_error(s, m, buf);
01171       return 0;
01172    }
01173 
01174    ast_channel_lock(chan);
01175 
01176    if (add_agi_cmd(chan, cmdbuff, cmdid)) {
01177       snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", chan->name);
01178       astman_send_error(s, m, buf);
01179       ast_channel_unlock(chan);
01180       chan = ast_channel_unref(chan);
01181       return 0;
01182    }
01183 
01184    ast_channel_unlock(chan);
01185    chan = ast_channel_unref(chan);
01186 
01187    astman_send_ack(s, m, "Added AGI command to queue");
01188 
01189    return 0;
01190 }
01191 
01192 static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead);
01193 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[]);
01194 
01195 /*!
01196  * \internal
01197  * \brief Read and handle a channel frame for Async AGI.
01198  *
01199  * \param chan Channel to read a frame from.
01200  *
01201  * \retval AGI_RESULT_SUCCESS on success.
01202  * \retval AGI_RESULT_HANGUP on hangup.
01203  * \retval AGI_RESULT_FAILURE on error.
01204  */
01205 static enum agi_result async_agi_read_frame(struct ast_channel *chan)
01206 {
01207    struct ast_frame *f;
01208 
01209    f = ast_read(chan);
01210    if (!f) {
01211       ast_debug(3, "No frame read on channel %s, going out ...\n", chan->name);
01212       return AGI_RESULT_HANGUP;
01213    }
01214    if (f->frametype == AST_FRAME_CONTROL) {
01215       /*
01216        * Is there any other frame we should care about besides
01217        * AST_CONTROL_HANGUP?
01218        */
01219       switch (f->subclass.integer) {
01220       case AST_CONTROL_HANGUP:
01221          ast_debug(3, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
01222          ast_frfree(f);
01223          return AGI_RESULT_HANGUP;
01224       default:
01225          break;
01226       }
01227    }
01228    ast_frfree(f);
01229 
01230    return AGI_RESULT_SUCCESS;
01231 }
01232 
01233 static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], int *efd)
01234 {
01235 /* This buffer sizes might cause truncation if the AGI command writes more data
01236    than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command
01237    that writes a response larger than 1024 bytes?, I don't think so, most of
01238    them are just result=blah stuff. However probably if GET VARIABLE is called
01239    and the variable has large amount of data, that could be a problem. We could
01240    make this buffers dynamic, but let's leave that as a second step.
01241 
01242    AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe
01243    number. Some characters of AGI buf will be url encoded to be sent to manager
01244    clients.  An URL encoded character will take 3 bytes, but again, to cause
01245    truncation more than about 70% of the AGI buffer should be URL encoded for
01246    that to happen.  Not likely at all.
01247 
01248    On the other hand. I wonder if read() could eventually return less data than
01249    the amount already available in the pipe? If so, how to deal with that?
01250    So far, my tests on Linux have not had any problems.
01251  */
01252 #define AGI_BUF_SIZE 1024
01253 #define AMI_BUF_SIZE 2048
01254    enum agi_result cmd_status;
01255    struct agi_cmd *cmd;
01256    int res;
01257    int fds[2];
01258    int hungup;
01259    int timeout = 100;
01260    char agi_buffer[AGI_BUF_SIZE + 1];
01261    char ami_buffer[AMI_BUF_SIZE];
01262    enum agi_result returnstatus = AGI_RESULT_SUCCESS;
01263    AGI async_agi;
01264 
01265    if (efd) {
01266       ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
01267       return AGI_RESULT_FAILURE;
01268    }
01269 
01270    /* add AsyncAGI datastore to the channel */
01271    if (add_to_agi(chan)) {
01272       ast_log(LOG_ERROR, "Failed to start Async AGI on channel %s\n", chan->name);
01273       return AGI_RESULT_FAILURE;
01274    }
01275 
01276    /* this pipe allows us to create a "fake" AGI struct to use
01277       the AGI commands */
01278    res = pipe(fds);
01279    if (res) {
01280       ast_log(LOG_ERROR, "Failed to create Async AGI pipe\n");
01281       /*
01282        * Intentionally do not remove the datastore added with
01283        * add_to_agi() the from channel.  It will be removed when the
01284        * channel is hung up anyway.
01285        */
01286       return AGI_RESULT_FAILURE;
01287    }
01288 
01289    /* handlers will get the pipe write fd and we read the AGI responses
01290       from the pipe read fd */
01291    async_agi.fd = fds[1];
01292    async_agi.ctrl = fds[1];
01293    async_agi.audio = -1; /* no audio support */
01294    async_agi.fast = 0;
01295    async_agi.speech = NULL;
01296 
01297    /* notify possible manager users of a new channel ready to
01298       receive commands */
01299    setup_env(chan, "async", fds[1], 0, 0, NULL);
01300    /* read the environment */
01301    res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
01302    if (res <= 0) {
01303       ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
01304          chan->name, res < 0 ? strerror(errno) : "EOF");
01305       returnstatus = AGI_RESULT_FAILURE;
01306       goto async_agi_abort;
01307    }
01308    agi_buffer[res] = '\0';
01309    /* encode it and send it thru the manager so whoever is going to take
01310       care of AGI commands on this channel can decide which AGI commands
01311       to execute based on the setup info */
01312    ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
01313    manager_event(EVENT_FLAG_AGI, "AsyncAGI",
01314       "SubEvent: Start\r\n"
01315       "Channel: %s\r\n"
01316       "Env: %s\r\n", chan->name, ami_buffer);
01317    hungup = ast_check_hangup(chan);
01318    for (;;) {
01319       /*
01320        * Process as many commands as we can.  Commands are added via
01321        * the manager or the cli threads.
01322        */
01323       while (!hungup && (cmd = get_agi_cmd(chan))) {
01324          /* OK, we have a command, let's call the command handler. */
01325          cmd_status = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
01326 
01327          /*
01328           * The command handler must have written to our fake AGI struct
01329           * fd (the pipe), let's read the response.
01330           */
01331          res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
01332          if (res <= 0) {
01333             ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
01334                chan->name, res < 0 ? strerror(errno) : "EOF");
01335             free_agi_cmd(cmd);
01336             returnstatus = AGI_RESULT_FAILURE;
01337             goto async_agi_done;
01338          }
01339          /*
01340           * We have a response, let's send the response thru the manager.
01341           * Include the CommandID if it was specified when the command
01342           * was added.
01343           */
01344          agi_buffer[res] = '\0';
01345          ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
01346          if (ast_strlen_zero(cmd->cmd_id)) {
01347             manager_event(EVENT_FLAG_AGI, "AsyncAGI",
01348                "SubEvent: Exec\r\n"
01349                "Channel: %s\r\n"
01350                "Result: %s\r\n", chan->name, ami_buffer);
01351          } else {
01352             manager_event(EVENT_FLAG_AGI, "AsyncAGI",
01353                "SubEvent: Exec\r\n"
01354                "Channel: %s\r\n"
01355                "CommandID: %s\r\n"
01356                "Result: %s\r\n", chan->name, cmd->cmd_id, ami_buffer);
01357          }
01358          free_agi_cmd(cmd);
01359 
01360          /*
01361           * Check the command status to determine if we should continue
01362           * executing more commands.
01363           */
01364          hungup = ast_check_hangup(chan);
01365          switch (cmd_status) {
01366          case AGI_RESULT_FAILURE:
01367             if (!hungup) {
01368                /* The failure was not because of a hangup. */
01369                returnstatus = AGI_RESULT_FAILURE;
01370                goto async_agi_done;
01371             }
01372             break;
01373          case AGI_RESULT_SUCCESS_ASYNC:
01374             /* Only the "asyncagi break" command does this. */
01375             returnstatus = AGI_RESULT_SUCCESS_ASYNC;
01376             goto async_agi_done;
01377          default:
01378             break;
01379          }
01380       }
01381 
01382       if (!hungup) {
01383          /* Wait a bit for a frame to read or to poll for a new command. */
01384          res = ast_waitfor(chan, timeout);
01385          if (res < 0) {
01386             ast_debug(1, "ast_waitfor returned <= 0 on chan %s\n", chan->name);
01387             returnstatus = AGI_RESULT_FAILURE;
01388             break;
01389          }
01390       } else {
01391          /*
01392           * Read the channel control queue until it is dry so we can
01393           * quit.
01394           */
01395          res = 1;
01396       }
01397       if (0 < res) {
01398          do {
01399             cmd_status = async_agi_read_frame(chan);
01400             if (cmd_status != AGI_RESULT_SUCCESS) {
01401                returnstatus = cmd_status;
01402                goto async_agi_done;
01403             }
01404             hungup = ast_check_hangup(chan);
01405          } while (hungup);
01406       } else {
01407          hungup = ast_check_hangup(chan);
01408       }
01409    }
01410 async_agi_done:
01411 
01412    if (async_agi.speech) {
01413       ast_speech_destroy(async_agi.speech);
01414    }
01415    /* notify manager users this channel cannot be
01416       controlled anymore by Async AGI */
01417    manager_event(EVENT_FLAG_AGI, "AsyncAGI",
01418       "SubEvent: End\r\n"
01419       "Channel: %s\r\n", chan->name);
01420 
01421 async_agi_abort:
01422    /* close the pipe */
01423    close(fds[0]);
01424    close(fds[1]);
01425 
01426    /*
01427     * Intentionally do not remove the datastore added with
01428     * add_to_agi() the from channel.  There might be commands still
01429     * in the queue or in-flight to us and AsyncAGI may get called
01430     * again.  The datastore destructor will be called on channel
01431     * destruction anyway.
01432     */
01433 
01434    if (returnstatus == AGI_RESULT_SUCCESS) {
01435       returnstatus = AGI_RESULT_SUCCESS_ASYNC;
01436    }
01437    return returnstatus;
01438 
01439 #undef AGI_BUF_SIZE
01440 #undef AMI_BUF_SIZE
01441 }
01442 
01443 /* launch_netscript: The fastagi handler.
01444    FastAGI defaults to port 4573 */
01445 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
01446 {
01447    int s, flags, res, port = AGI_PORT;
01448    struct pollfd pfds[1];
01449    char *host, *c, *script;
01450    struct sockaddr_in addr_in;
01451    struct hostent *hp;
01452    struct ast_hostent ahp;
01453 
01454    /* agiurl is "agi://host.domain[:port][/script/name]" */
01455    host = ast_strdupa(agiurl + 6);  /* Remove agi:// */
01456    /* Strip off any script name */
01457    if ((script = strchr(host, '/'))) {
01458       *script++ = '\0';
01459    } else {
01460       script = "";
01461    }
01462 
01463    if ((c = strchr(host, ':'))) {
01464       *c++ = '\0';
01465       port = atoi(c);
01466    }
01467    if (!(hp = ast_gethostbyname(host, &ahp))) {
01468       ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
01469       return AGI_RESULT_FAILURE;
01470    }
01471    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
01472       ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
01473       return AGI_RESULT_FAILURE;
01474    }
01475    if ((flags = fcntl(s, F_GETFL)) < 0) {
01476       ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
01477       close(s);
01478       return AGI_RESULT_FAILURE;
01479    }
01480    if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
01481       ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
01482       close(s);
01483       return AGI_RESULT_FAILURE;
01484    }
01485    memset(&addr_in, 0, sizeof(addr_in));
01486    addr_in.sin_family = AF_INET;
01487    addr_in.sin_port = htons(port);
01488    memcpy(&addr_in.sin_addr, hp->h_addr, sizeof(addr_in.sin_addr));
01489    if (connect(s, (struct sockaddr *)&addr_in, sizeof(addr_in)) && (errno != EINPROGRESS)) {
01490       ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
01491       close(s);
01492       return AGI_RESULT_FAILURE;
01493    }
01494 
01495    pfds[0].fd = s;
01496    pfds[0].events = POLLOUT;
01497    while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
01498       if (errno != EINTR) {
01499          if (!res) {
01500             ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
01501                agiurl, MAX_AGI_CONNECT);
01502          } else
01503             ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
01504          close(s);
01505          return AGI_RESULT_FAILURE;
01506       }
01507    }
01508 
01509    if (ast_agi_send(s, NULL, "agi_network: yes\n") < 0) {
01510       if (errno != EINTR) {
01511          ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
01512          close(s);
01513          return AGI_RESULT_FAILURE;
01514       }
01515    }
01516 
01517    /* If we have a script parameter, relay it to the fastagi server */
01518    /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
01519    if (!ast_strlen_zero(script))
01520       ast_agi_send(s, NULL, "agi_network_script: %s\n", script);
01521 
01522    ast_debug(4, "Wow, connected!\n");
01523    fds[0] = s;
01524    fds[1] = s;
01525    return AGI_RESULT_SUCCESS_FAST;
01526 }
01527 
01528 /*!
01529  * \internal
01530  * \brief The HA fastagi handler.
01531  * \param agiurl The request URL as passed to Agi() in the dial plan
01532  * \param argv The parameters after the URL passed to Agi() in the dial plan
01533  * \param fds Input/output file descriptors
01534  *
01535  * Uses SRV lookups to try to connect to a list of FastAGI servers. The hostname in
01536  * the URI is prefixed with _agi._tcp. prior to the DNS resolution. For
01537  * example, if you specify the URI \a hagi://agi.example.com/foo.agi the DNS
01538  * query would be for \a _agi._tcp.agi.example.com and you'll need to make sure
01539  * this resolves.
01540  *
01541  * This function parses the URI, resolves the SRV service name, forms new URIs
01542  * with the results of the DNS lookup, and then calls launch_netscript on the
01543  * new URIs until one succeeds.
01544  *
01545  * \return the result of the AGI operation.
01546  */
01547 static enum agi_result launch_ha_netscript(char *agiurl, char *argv[], int *fds)
01548 {
01549    char *host, *script;
01550    enum agi_result result;
01551    struct srv_context *context = NULL;
01552    int srv_ret;
01553    char service[256];
01554    char resolved_uri[1024];
01555    const char *srvhost;
01556    unsigned short srvport;
01557 
01558    /* format of agiurl is "hagi://host.domain[:port][/script/name]" */
01559    if (strlen(agiurl) < 7) { /* Remove hagi:// */
01560       ast_log(LOG_WARNING, "An error occurred parsing the AGI URI: %s", agiurl);
01561       return AGI_RESULT_FAILURE;
01562    }
01563    host = ast_strdupa(agiurl + 7);
01564 
01565    /* Strip off any script name */
01566    if ((script = strchr(host, '/'))) {
01567       *script++ = '\0';
01568    } else {
01569       script = "";
01570    }
01571 
01572    if (strchr(host, ':')) {
01573       ast_log(LOG_WARNING, "Specifying a port number disables SRV lookups: %s\n", agiurl);
01574       return launch_netscript(agiurl + 1, argv, fds); /* +1 to strip off leading h from hagi:// */
01575    }
01576 
01577    snprintf(service, sizeof(service), "%s%s", SRV_PREFIX, host);
01578 
01579    while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
01580       snprintf(resolved_uri, sizeof(resolved_uri), "agi://%s:%d/%s", srvhost, srvport, script);
01581       result = launch_netscript(resolved_uri, argv, fds);
01582       if (result == AGI_RESULT_FAILURE || result == AGI_RESULT_NOTFOUND) {
01583          ast_log(LOG_WARNING, "AGI request failed for host '%s' (%s:%d)\n", host, srvhost, srvport);
01584       } else {
01585          /* The script launched so we must cleanup the context. */
01586          ast_srv_cleanup(&context);
01587          return result;
01588       }
01589    }
01590    /*
01591     * The DNS SRV lookup failed or we ran out of servers to check.
01592     * ast_srv_lookup() has already cleaned up the context for us.
01593     */
01594    if (srv_ret < 0) {
01595       ast_log(LOG_WARNING, "SRV lookup failed for %s\n", agiurl);
01596    }
01597 
01598    return AGI_RESULT_FAILURE;
01599 }
01600 
01601 static enum agi_result launch_script(struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
01602 {
01603    char tmp[256];
01604    int pid, toast[2], fromast[2], audio[2], res;
01605    struct stat st;
01606 
01607    if (!strncasecmp(script, "agi://", 6)) {
01608       return (efd == NULL) ? launch_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
01609    }
01610    if (!strncasecmp(script, "hagi://", 7)) {
01611       return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
01612    }
01613    if (!strncasecmp(script, "agi:async", sizeof("agi:async") - 1)) {
01614       return launch_asyncagi(chan, argv, efd);
01615    }
01616 
01617    if (script[0] != '/') {
01618       snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
01619       script = tmp;
01620    }
01621 
01622    /* Before even trying let's see if the file actually exists */
01623    if (stat(script, &st)) {
01624       ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
01625       return AGI_RESULT_NOTFOUND;
01626    }
01627 
01628    if (pipe(toast)) {
01629       ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
01630       return AGI_RESULT_FAILURE;
01631    }
01632    if (pipe(fromast)) {
01633       ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
01634       close(toast[0]);
01635       close(toast[1]);
01636       return AGI_RESULT_FAILURE;
01637    }
01638    if (efd) {
01639       if (pipe(audio)) {
01640          ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
01641          close(fromast[0]);
01642          close(fromast[1]);
01643          close(toast[0]);
01644          close(toast[1]);
01645          return AGI_RESULT_FAILURE;
01646       }
01647       res = fcntl(audio[1], F_GETFL);
01648       if (res > -1)
01649          res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
01650       if (res < 0) {
01651          ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
01652          close(fromast[0]);
01653          close(fromast[1]);
01654          close(toast[0]);
01655          close(toast[1]);
01656          close(audio[0]);
01657          close(audio[1]);
01658          return AGI_RESULT_FAILURE;
01659       }
01660    }
01661 
01662    if ((pid = ast_safe_fork(1)) < 0) {
01663       ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
01664       return AGI_RESULT_FAILURE;
01665    }
01666    if (!pid) {
01667       /* Pass paths to AGI via environmental variables */
01668       setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
01669       setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
01670       setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
01671       setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
01672       setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
01673       setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
01674       setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
01675       setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
01676       setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
01677       setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
01678       setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
01679 
01680       /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
01681       ast_set_priority(0);
01682 
01683       /* Redirect stdin and out, provide enhanced audio channel if desired */
01684       dup2(fromast[0], STDIN_FILENO);
01685       dup2(toast[1], STDOUT_FILENO);
01686       if (efd)
01687          dup2(audio[0], STDERR_FILENO + 1);
01688       else
01689          close(STDERR_FILENO + 1);
01690 
01691       /* Close everything but stdin/out/error */
01692       ast_close_fds_above_n(STDERR_FILENO + 1);
01693 
01694       /* Execute script */
01695       /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
01696       execv(script, argv);
01697       /* Can't use ast_log since FD's are closed */
01698       ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
01699       /* Special case to set status of AGI to failure */
01700       fprintf(stdout, "failure\n");
01701       fflush(stdout);
01702       _exit(1);
01703    }
01704    ast_verb(3, "Launched AGI Script %s\n", script);
01705    fds[0] = toast[0];
01706    fds[1] = fromast[1];
01707    if (efd)
01708       *efd = audio[1];
01709    /* close what we're not using in the parent */
01710    close(toast[1]);
01711    close(fromast[0]);
01712 
01713    if (efd)
01714       close(audio[0]);
01715 
01716    *opid = pid;
01717    return AGI_RESULT_SUCCESS;
01718 }
01719 
01720 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
01721 {
01722    int count;
01723 
01724    /* Print initial environment, with agi_request always being the first
01725       thing */
01726    ast_agi_send(fd, chan, "agi_request: %s\n", request);
01727    ast_agi_send(fd, chan, "agi_channel: %s\n", chan->name);
01728    ast_agi_send(fd, chan, "agi_language: %s\n", chan->language);
01729    ast_agi_send(fd, chan, "agi_type: %s\n", chan->tech->type);
01730    ast_agi_send(fd, chan, "agi_uniqueid: %s\n", chan->uniqueid);
01731    ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version());
01732 
01733    /* ANI/DNIS */
01734    ast_agi_send(fd, chan, "agi_callerid: %s\n",
01735       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "unknown"));
01736    ast_agi_send(fd, chan, "agi_calleridname: %s\n",
01737       S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "unknown"));
01738    ast_agi_send(fd, chan, "agi_callingpres: %d\n",
01739       ast_party_id_presentation(&chan->caller.id));
01740    ast_agi_send(fd, chan, "agi_callingani2: %d\n", chan->caller.ani2);
01741    ast_agi_send(fd, chan, "agi_callington: %d\n", chan->caller.id.number.plan);
01742    ast_agi_send(fd, chan, "agi_callingtns: %d\n", chan->dialed.transit_network_select);
01743    ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(chan->dialed.number.str, "unknown"));
01744    ast_agi_send(fd, chan, "agi_rdnis: %s\n",
01745       S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, "unknown"));
01746 
01747    /* Context information */
01748    ast_agi_send(fd, chan, "agi_context: %s\n", chan->context);
01749    ast_agi_send(fd, chan, "agi_extension: %s\n", chan->exten);
01750    ast_agi_send(fd, chan, "agi_priority: %d\n", chan->priority);
01751    ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
01752 
01753    /* User information */
01754    ast_agi_send(fd, chan, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
01755    ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self());
01756 
01757    /* Send any parameters to the fastagi server that have been passed via the agi application */
01758    /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
01759    for(count = 1; count < argc; count++)
01760       ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]);
01761 
01762    /* End with empty return */
01763    ast_agi_send(fd, chan, "\n");
01764 }
01765 
01766 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01767 {
01768    int res = 0;
01769 
01770    /* Answer the channel */
01771    if (chan->_state != AST_STATE_UP)
01772       res = ast_answer(chan);
01773 
01774    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01775    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01776 }
01777 
01778 static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01779 {
01780    ast_agi_send(agi->fd, chan, "200 result=0\n");
01781    return ASYNC_AGI_BREAK;
01782 }
01783 
01784 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01785 {
01786    int res, to;
01787 
01788    if (argc != 4)
01789       return RESULT_SHOWUSAGE;
01790    if (sscanf(argv[3], "%30d", &to) != 1)
01791       return RESULT_SHOWUSAGE;
01792    res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
01793    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01794    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01795 }
01796 
01797 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01798 {
01799    int res;
01800 
01801    if (argc != 3)
01802       return RESULT_SHOWUSAGE;
01803 
01804    /* At the moment, the parser (perhaps broken) returns with
01805       the last argument PLUS the newline at the end of the input
01806       buffer. This probably needs to be fixed, but I wont do that
01807       because other stuff may break as a result. The right way
01808       would probably be to strip off the trailing newline before
01809       parsing, then here, add a newline at the end of the string
01810       before sending it to ast_sendtext --DUDE */
01811    res = ast_sendtext(chan, argv[2]);
01812    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01813    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01814 }
01815 
01816 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01817 {
01818    int res;
01819 
01820    if (argc != 3)
01821       return RESULT_SHOWUSAGE;
01822 
01823    res = ast_recvchar(chan,atoi(argv[2]));
01824    if (res == 0) {
01825       ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res);
01826       return RESULT_SUCCESS;
01827    }
01828    if (res > 0) {
01829       ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01830       return RESULT_SUCCESS;
01831    }
01832    ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res);
01833    return RESULT_FAILURE;
01834 }
01835 
01836 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01837 {
01838    char *buf;
01839 
01840    if (argc != 3)
01841       return RESULT_SHOWUSAGE;
01842 
01843    buf = ast_recvtext(chan, atoi(argv[2]));
01844    if (buf) {
01845       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf);
01846       ast_free(buf);
01847    } else {
01848       ast_agi_send(agi->fd, chan, "200 result=-1\n");
01849    }
01850    return RESULT_SUCCESS;
01851 }
01852 
01853 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01854 {
01855    int res, x;
01856 
01857    if (argc != 3)
01858       return RESULT_SHOWUSAGE;
01859 
01860    if (!strncasecmp(argv[2],"on",2)) {
01861       x = 1;
01862    } else  {
01863       x = 0;
01864    }
01865    if (!strncasecmp(argv[2],"mate",4))  {
01866       x = 2;
01867    }
01868    if (!strncasecmp(argv[2],"tdd",3)) {
01869       x = 1;
01870    }
01871    res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
01872    if (res) {
01873       /* Set channel option failed */
01874       ast_agi_send(agi->fd, chan, "200 result=0\n");
01875    } else {
01876       ast_agi_send(agi->fd, chan, "200 result=1\n");
01877    }
01878    return RESULT_SUCCESS;
01879 }
01880 
01881 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01882 {
01883    int res;
01884 
01885    if (argc != 3) {
01886       return RESULT_SHOWUSAGE;
01887    }
01888 
01889    res = ast_send_image(chan, argv[2]);
01890    if (!ast_check_hangup(chan)) {
01891       res = 0;
01892    }
01893    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01894    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01895 }
01896 
01897 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01898 {
01899    int res = 0, skipms = 3000;
01900    const char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */
01901 
01902    if (argc < 5 || argc > 9) {
01903       return RESULT_SHOWUSAGE;
01904    }
01905 
01906    if (!ast_strlen_zero(argv[4])) {
01907       stop = argv[4];
01908    }
01909 
01910    if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) {
01911       return RESULT_SHOWUSAGE;
01912    }
01913 
01914    if (argc > 6 && !ast_strlen_zero(argv[6])) {
01915       fwd = argv[6];
01916    }
01917 
01918    if (argc > 7 && !ast_strlen_zero(argv[7])) {
01919       rev = argv[7];
01920    }
01921 
01922    if (argc > 8 && !ast_strlen_zero(argv[8])) {
01923       suspend = argv[8];
01924    }
01925 
01926    res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, NULL);
01927 
01928    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01929 
01930    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01931 }
01932 
01933 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01934 {
01935    int res;
01936    struct ast_filestream *fs, *vfs;
01937    long sample_offset = 0, max_length;
01938    const char *edigits = "";
01939 
01940    if (argc < 4 || argc > 5)
01941       return RESULT_SHOWUSAGE;
01942 
01943    if (argv[3])
01944       edigits = argv[3];
01945 
01946    if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1))
01947       return RESULT_SHOWUSAGE;
01948 
01949    if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
01950       ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
01951       return RESULT_FAILURE;
01952    }
01953 
01954    if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
01955       ast_debug(1, "Ooh, found a video stream, too\n");
01956 
01957    ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
01958 
01959    ast_seekstream(fs, 0, SEEK_END);
01960    max_length = ast_tellstream(fs);
01961    ast_seekstream(fs, sample_offset, SEEK_SET);
01962    res = ast_applystream(chan, fs);
01963    if (vfs)
01964       ast_applystream(chan, vfs);
01965    ast_playstream(fs);
01966    if (vfs)
01967       ast_playstream(vfs);
01968 
01969    res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
01970    /* this is to check for if ast_waitstream closed the stream, we probably are at
01971     * the end of the stream, return that amount, else check for the amount */
01972    sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
01973    ast_stopstream(chan);
01974    if (res == 1) {
01975       /* Stop this command, don't print a result line, as there is a new command */
01976       return RESULT_SUCCESS;
01977    }
01978    ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
01979    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01980 }
01981 
01982 /*! \brief get option - really similar to the handle_streamfile, but with a timeout */
01983 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01984 {
01985    int res;
01986    struct ast_filestream *fs, *vfs;
01987    long sample_offset = 0, max_length;
01988    int timeout = 0;
01989    const char *edigits = "";
01990 
01991    if ( argc < 4 || argc > 5 )
01992       return RESULT_SHOWUSAGE;
01993 
01994    if ( argv[3] )
01995       edigits = argv[3];
01996 
01997    if ( argc == 5 )
01998       timeout = atoi(argv[4]);
01999    else if (chan->pbx->dtimeoutms) {
02000       /* by default dtimeout is set to 5sec */
02001       timeout = chan->pbx->dtimeoutms; /* in msec */
02002    }
02003 
02004    if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
02005       ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
02006       ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
02007       return RESULT_FAILURE;
02008    }
02009 
02010    if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
02011       ast_debug(1, "Ooh, found a video stream, too\n");
02012 
02013    ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
02014 
02015    ast_seekstream(fs, 0, SEEK_END);
02016    max_length = ast_tellstream(fs);
02017    ast_seekstream(fs, sample_offset, SEEK_SET);
02018    res = ast_applystream(chan, fs);
02019    if (vfs)
02020       ast_applystream(chan, vfs);
02021    ast_playstream(fs);
02022    if (vfs)
02023       ast_playstream(vfs);
02024 
02025    res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
02026    /* this is to check for if ast_waitstream closed the stream, we probably are at
02027     * the end of the stream, return that amount, else check for the amount */
02028    sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
02029    ast_stopstream(chan);
02030    if (res == 1) {
02031       /* Stop this command, don't print a result line, as there is a new command */
02032       return RESULT_SUCCESS;
02033    }
02034 
02035    /* If the user didnt press a key, wait for digitTimeout*/
02036    if (res == 0 ) {
02037       res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
02038       /* Make sure the new result is in the escape digits of the GET OPTION */
02039       if ( !strchr(edigits,res) )
02040          res=0;
02041    }
02042 
02043    ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
02044    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02045 }
02046 
02047 
02048 
02049 
02050 /*! \brief Say number in various language syntaxes */
02051 /* While waiting, we're sending a NULL.  */
02052 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02053 {
02054    int res, num;
02055 
02056    if (argc < 4 || argc > 5)
02057       return RESULT_SHOWUSAGE;
02058    if (sscanf(argv[2], "%30d", &num) != 1)
02059       return RESULT_SHOWUSAGE;
02060    res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
02061    if (res == 1)
02062       return RESULT_SUCCESS;
02063    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02064    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02065 }
02066 
02067 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02068 {
02069    int res, num;
02070 
02071    if (argc != 4)
02072       return RESULT_SHOWUSAGE;
02073    if (sscanf(argv[2], "%30d", &num) != 1)
02074       return RESULT_SHOWUSAGE;
02075 
02076    res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
02077    if (res == 1) /* New command */
02078       return RESULT_SUCCESS;
02079    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02080    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02081 }
02082 
02083 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02084 {
02085    int res;
02086 
02087    if (argc != 4)
02088       return RESULT_SHOWUSAGE;
02089 
02090    res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
02091    if (res == 1) /* New command */
02092       return RESULT_SUCCESS;
02093    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02094    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02095 }
02096 
02097 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02098 {
02099    int res, num;
02100 
02101    if (argc != 4)
02102       return RESULT_SHOWUSAGE;
02103    if (sscanf(argv[2], "%30d", &num) != 1)
02104       return RESULT_SHOWUSAGE;
02105    res = ast_say_date(chan, num, argv[3], chan->language);
02106    if (res == 1)
02107       return RESULT_SUCCESS;
02108    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02109    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02110 }
02111 
02112 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02113 {
02114    int res, num;
02115 
02116    if (argc != 4)
02117       return RESULT_SHOWUSAGE;
02118    if (sscanf(argv[2], "%30d", &num) != 1)
02119       return RESULT_SHOWUSAGE;
02120    res = ast_say_time(chan, num, argv[3], chan->language);
02121    if (res == 1)
02122       return RESULT_SUCCESS;
02123    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02124    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02125 }
02126 
02127 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02128 {
02129    int res = 0;
02130    time_t unixtime;
02131    const char *format, *zone = NULL;
02132 
02133    if (argc < 4)
02134       return RESULT_SHOWUSAGE;
02135 
02136    if (argc > 4) {
02137       format = argv[4];
02138    } else {
02139       /* XXX this doesn't belong here, but in the 'say' module */
02140       if (!strcasecmp(chan->language, "de")) {
02141          format = "A dBY HMS";
02142       } else {
02143          format = "ABdY 'digits/at' IMp";
02144       }
02145    }
02146 
02147    if (argc > 5 && !ast_strlen_zero(argv[5]))
02148       zone = argv[5];
02149 
02150    if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
02151       return RESULT_SHOWUSAGE;
02152 
02153    res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
02154    if (res == 1)
02155       return RESULT_SUCCESS;
02156 
02157    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02158    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02159 }
02160 
02161 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02162 {
02163    int res;
02164 
02165    if (argc != 4)
02166       return RESULT_SHOWUSAGE;
02167 
02168    res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
02169    if (res == 1) /* New command */
02170       return RESULT_SUCCESS;
02171    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02172    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02173 }
02174 
02175 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02176 {
02177    int res, max, timeout;
02178    char data[1024];
02179 
02180    if (argc < 3)
02181       return RESULT_SHOWUSAGE;
02182    if (argc >= 4)
02183       timeout = atoi(argv[3]);
02184    else
02185       timeout = 0;
02186    if (argc >= 5)
02187       max = atoi(argv[4]);
02188    else
02189       max = 1024;
02190    res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
02191    if (res == 2)        /* New command */
02192       return RESULT_SUCCESS;
02193    else if (res == 1)
02194       ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
02195    else if (res < 0 )
02196       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02197    else
02198       ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
02199    return RESULT_SUCCESS;
02200 }
02201 
02202 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02203 {
02204 
02205    if (argc != 3)
02206       return RESULT_SHOWUSAGE;
02207    ast_copy_string(chan->context, argv[2], sizeof(chan->context));
02208    ast_agi_send(agi->fd, chan, "200 result=0\n");
02209    return RESULT_SUCCESS;
02210 }
02211 
02212 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02213 {
02214    if (argc != 3)
02215       return RESULT_SHOWUSAGE;
02216    ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
02217    ast_agi_send(agi->fd, chan, "200 result=0\n");
02218    return RESULT_SUCCESS;
02219 }
02220 
02221 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02222 {
02223    int pri;
02224 
02225    if (argc != 3)
02226       return RESULT_SHOWUSAGE;
02227 
02228    if (sscanf(argv[2], "%30d", &pri) != 1) {
02229       pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2],
02230          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
02231       if (pri < 1)
02232          return RESULT_SHOWUSAGE;
02233    }
02234 
02235    ast_explicit_goto(chan, NULL, NULL, pri);
02236    ast_agi_send(agi->fd, chan, "200 result=0\n");
02237    return RESULT_SUCCESS;
02238 }
02239 
02240 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02241 {
02242    struct ast_filestream *fs;
02243    struct ast_frame *f;
02244    struct timeval start;
02245    long sample_offset = 0;
02246    int res = 0;
02247    int ms;
02248 
02249    struct ast_dsp *sildet=NULL;         /* silence detector dsp */
02250    int totalsilence = 0;
02251    int dspsilence = 0;
02252    int silence = 0;                /* amount of silence to allow */
02253    int gotsilence = 0;             /* did we timeout for silence? */
02254    char *silencestr = NULL;
02255    int rfmt = 0;
02256 
02257    /* XXX EAGI FIXME XXX */
02258 
02259    if (argc < 6)
02260       return RESULT_SHOWUSAGE;
02261    if (sscanf(argv[5], "%30d", &ms) != 1)
02262       return RESULT_SHOWUSAGE;
02263 
02264    if (argc > 6)
02265       silencestr = strchr(argv[6],'s');
02266    if ((argc > 7) && (!silencestr))
02267       silencestr = strchr(argv[7],'s');
02268    if ((argc > 8) && (!silencestr))
02269       silencestr = strchr(argv[8],'s');
02270 
02271    if (silencestr) {
02272       if (strlen(silencestr) > 2) {
02273          if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
02274             silencestr++;
02275             silencestr++;
02276             if (silencestr)
02277                silence = atoi(silencestr);
02278             if (silence > 0)
02279                silence *= 1000;
02280          }
02281       }
02282    }
02283 
02284    if (silence > 0) {
02285       rfmt = chan->readformat;
02286       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
02287       if (res < 0) {
02288          ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
02289          ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02290          return RESULT_FAILURE;
02291       }
02292       sildet = ast_dsp_new();
02293       if (!sildet) {
02294          ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
02295          ast_agi_send(agi->fd, chan, "200 result=-1\n");
02296          return RESULT_FAILURE;
02297       }
02298       ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
02299    }
02300    
02301    /* backward compatibility, if no offset given, arg[6] would have been
02302     * caught below and taken to be a beep, else if it is a digit then it is a
02303     * offset */
02304    if ((argc >6) && (sscanf(argv[6], "%30ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
02305       res = ast_streamfile(chan, "beep", chan->language);
02306 
02307    if ((argc > 7) && (!strchr(argv[7], '=')))
02308       res = ast_streamfile(chan, "beep", chan->language);
02309 
02310    if (!res)
02311       res = ast_waitstream(chan, argv[4]);
02312    if (res) {
02313       ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
02314    } else {
02315       fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
02316       if (!fs) {
02317          res = -1;
02318          ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
02319          if (sildet)
02320             ast_dsp_free(sildet);
02321          return RESULT_FAILURE;
02322       }
02323 
02324       /* Request a video update */
02325       ast_indicate(chan, AST_CONTROL_VIDUPDATE);
02326 
02327       chan->stream = fs;
02328       ast_applystream(chan,fs);
02329       /* really should have checks */
02330       ast_seekstream(fs, sample_offset, SEEK_SET);
02331       ast_truncstream(fs);
02332 
02333       start = ast_tvnow();
02334       while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
02335          res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start));
02336          if (res < 0) {
02337             ast_closestream(fs);
02338             ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
02339             if (sildet)
02340                ast_dsp_free(sildet);
02341             return RESULT_FAILURE;
02342          }
02343          f = ast_read(chan);
02344          if (!f) {
02345             ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
02346             ast_closestream(fs);
02347             if (sildet)
02348                ast_dsp_free(sildet);
02349             return RESULT_FAILURE;
02350          }
02351          switch(f->frametype) {
02352          case AST_FRAME_DTMF:
02353             if (strchr(argv[4], f->subclass.integer)) {
02354                /* This is an interrupting chracter, so rewind to chop off any small
02355                   amount of DTMF that may have been recorded
02356                */
02357                ast_stream_rewind(fs, 200);
02358                ast_truncstream(fs);
02359                sample_offset = ast_tellstream(fs);
02360                ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset);
02361                ast_closestream(fs);
02362                ast_frfree(f);
02363                if (sildet)
02364                   ast_dsp_free(sildet);
02365                return RESULT_SUCCESS;
02366             }
02367             break;
02368          case AST_FRAME_VOICE:
02369             ast_writestream(fs, f);
02370             /* this is a safe place to check progress since we know that fs
02371              * is valid after a write, and it will then have our current
02372              * location */
02373             sample_offset = ast_tellstream(fs);
02374             if (silence > 0) {
02375                dspsilence = 0;
02376                ast_dsp_silence(sildet, f, &dspsilence);
02377                if (dspsilence) {
02378                   totalsilence = dspsilence;
02379                } else {
02380                   totalsilence = 0;
02381                }
02382                if (totalsilence > silence) {
02383                   /* Ended happily with silence */
02384                   gotsilence = 1;
02385                   break;
02386                }
02387             }
02388             break;
02389          case AST_FRAME_VIDEO:
02390             ast_writestream(fs, f);
02391          default:
02392             /* Ignore all other frames */
02393             break;
02394          }
02395          ast_frfree(f);
02396          if (gotsilence)
02397             break;
02398       }
02399 
02400       if (gotsilence) {
02401          ast_stream_rewind(fs, silence-1000);
02402          ast_truncstream(fs);
02403          sample_offset = ast_tellstream(fs);
02404       }
02405       ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
02406       ast_closestream(fs);
02407    }
02408 
02409    if (silence > 0) {
02410       res = ast_set_read_format(chan, rfmt);
02411       if (res)
02412          ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
02413       ast_dsp_free(sildet);
02414    }
02415 
02416    return RESULT_SUCCESS;
02417 }
02418 
02419 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02420 {
02421    double timeout;
02422    struct timeval whentohangup = { 0, 0 };
02423 
02424    if (argc != 3)
02425       return RESULT_SHOWUSAGE;
02426    if (sscanf(argv[2], "%30lf", &timeout) != 1)
02427       return RESULT_SHOWUSAGE;
02428    if (timeout < 0)
02429       timeout = 0;
02430    if (timeout) {
02431       whentohangup.tv_sec = timeout;
02432       whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
02433    }
02434    ast_channel_setwhentohangup_tv(chan, whentohangup);
02435    ast_agi_send(agi->fd, chan, "200 result=0\n");
02436    return RESULT_SUCCESS;
02437 }
02438 
02439 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02440 {
02441    struct ast_channel *c;
02442 
02443    if (argc == 1) {
02444       /* no argument: hangup the current channel */
02445       ast_set_hangupsource(chan, "dialplan/agi", 0);
02446       ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
02447       ast_agi_send(agi->fd, chan, "200 result=1\n");
02448       return RESULT_SUCCESS;
02449    } else if (argc == 2) {
02450       /* one argument: look for info on the specified channel */
02451       if ((c = ast_channel_get_by_name(argv[1]))) {
02452          /* we have a matching channel */
02453          ast_set_hangupsource(c, "dialplan/agi", 0);
02454          ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
02455          c = ast_channel_unref(c);
02456          ast_agi_send(agi->fd, chan, "200 result=1\n");
02457          return RESULT_SUCCESS;
02458       }
02459       /* if we get this far no channel name matched the argument given */
02460       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02461       return RESULT_SUCCESS;
02462    } else {
02463       return RESULT_SHOWUSAGE;
02464    }
02465 }
02466 
02467 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02468 {
02469    int res, workaround;
02470    struct ast_app *app_to_exec;
02471 
02472    if (argc < 2)
02473       return RESULT_SHOWUSAGE;
02474 
02475    ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
02476 
02477    if ((app_to_exec = pbx_findapp(argv[1]))) {
02478       if (!(workaround = ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS))) {
02479          ast_set_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
02480       }
02481       if (ast_compat_res_agi && argc >= 3 && !ast_strlen_zero(argv[2])) {
02482          char *compat = ast_alloca(strlen(argv[2]) * 2 + 1), *cptr;
02483          const char *vptr;
02484          for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
02485             if (*vptr == ',') {
02486                *cptr++ = '\\';
02487                *cptr++ = ',';
02488             } else if (*vptr == '|') {
02489                *cptr++ = ',';
02490             } else {
02491                *cptr++ = *vptr;
02492             }
02493          }
02494          *cptr = '\0';
02495          res = pbx_exec(chan, app_to_exec, compat);
02496       } else {
02497          res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
02498       }
02499       if (!workaround) {
02500          ast_clear_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
02501       }
02502    } else {
02503       ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
02504       res = -2;
02505    }
02506    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02507 
02508    /* Even though this is wrong, users are depending upon this result. */
02509    return res;
02510 }
02511 
02512 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02513 {
02514    char tmp[256]="";
02515    char *l = NULL, *n = NULL;
02516 
02517    if (argv[2]) {
02518       ast_copy_string(tmp, argv[2], sizeof(tmp));
02519       ast_callerid_parse(tmp, &n, &l);
02520       if (l)
02521          ast_shrink_phone_number(l);
02522       else
02523          l = "";
02524       if (!n)
02525          n = "";
02526       ast_set_callerid(chan, l, n, NULL);
02527    }
02528 
02529    ast_agi_send(agi->fd, chan, "200 result=1\n");
02530    return RESULT_SUCCESS;
02531 }
02532 
02533 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02534 {
02535    struct ast_channel *c;
02536    if (argc == 2) {
02537       /* no argument: supply info on the current channel */
02538       ast_agi_send(agi->fd, chan, "200 result=%u\n", chan->_state);
02539       return RESULT_SUCCESS;
02540    } else if (argc == 3) {
02541       /* one argument: look for info on the specified channel */
02542       if ((c = ast_channel_get_by_name(argv[2]))) {
02543          ast_agi_send(agi->fd, chan, "200 result=%u\n", c->_state);
02544          c = ast_channel_unref(c);
02545          return RESULT_SUCCESS;
02546       }
02547       /* if we get this far no channel name matched the argument given */
02548       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02549       return RESULT_SUCCESS;
02550    } else {
02551       return RESULT_SHOWUSAGE;
02552    }
02553 }
02554 
02555 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02556 {
02557    if (argv[3])
02558       pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
02559 
02560    ast_agi_send(agi->fd, chan, "200 result=1\n");
02561    return RESULT_SUCCESS;
02562 }
02563 
02564 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02565 {
02566    char *ret;
02567    char tempstr[1024] = "";
02568 
02569    if (argc != 3)
02570       return RESULT_SHOWUSAGE;
02571 
02572    /* check if we want to execute an ast_custom_function */
02573    if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
02574       ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
02575    } else {
02576       pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
02577    }
02578 
02579    if (ret)
02580       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
02581    else
02582       ast_agi_send(agi->fd, chan, "200 result=0\n");
02583 
02584    return RESULT_SUCCESS;
02585 }
02586 
02587 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02588 {
02589    struct ast_channel *chan2 = NULL;
02590 
02591    if (argc != 4 && argc != 5) {
02592       return RESULT_SHOWUSAGE;
02593    }
02594 
02595    if (argc == 5) {
02596       chan2 = ast_channel_get_by_name(argv[4]);
02597    } else {
02598       chan2 = ast_channel_ref(chan);
02599    }
02600 
02601    if (chan2) {
02602       struct ast_str *str = ast_str_create(16);
02603       if (!str) {
02604          ast_agi_send(agi->fd, chan, "200 result=0\n");
02605          return RESULT_SUCCESS;
02606       }
02607       ast_str_substitute_variables(&str, 0, chan2, argv[3]);
02608       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(str));
02609       ast_free(str);
02610    } else {
02611       ast_agi_send(agi->fd, chan, "200 result=0\n");
02612    }
02613 
02614    if (chan2) {
02615       chan2 = ast_channel_unref(chan2);
02616    }
02617 
02618    return RESULT_SUCCESS;
02619 }
02620 
02621 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02622 {
02623    int level = 0;
02624 
02625    if (argc < 2)
02626       return RESULT_SHOWUSAGE;
02627 
02628    if (argv[2])
02629       sscanf(argv[2], "%30d", &level);
02630 
02631    ast_verb(level, "%s: %s\n", chan->data, argv[1]);
02632 
02633    ast_agi_send(agi->fd, chan, "200 result=1\n");
02634 
02635    return RESULT_SUCCESS;
02636 }
02637 
02638 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02639 {
02640    int res;
02641    struct ast_str *buf;
02642 
02643    if (argc != 4)
02644       return RESULT_SHOWUSAGE;
02645 
02646    if (!(buf = ast_str_create(16))) {
02647       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02648       return RESULT_SUCCESS;
02649    }
02650 
02651    do {
02652       res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
02653       ast_str_update(buf);
02654       if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
02655          break;
02656       }
02657       if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
02658          break;
02659       }
02660    } while (1);
02661    
02662    if (res)
02663       ast_agi_send(agi->fd, chan, "200 result=0\n");
02664    else
02665       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
02666 
02667    ast_free(buf);
02668    return RESULT_SUCCESS;
02669 }
02670 
02671 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02672 {
02673    int res;
02674 
02675    if (argc != 5)
02676       return RESULT_SHOWUSAGE;
02677    res = ast_db_put(argv[2], argv[3], argv[4]);
02678    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
02679    return RESULT_SUCCESS;
02680 }
02681 
02682 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02683 {
02684    int res;
02685 
02686    if (argc != 4)
02687       return RESULT_SHOWUSAGE;
02688    res = ast_db_del(argv[2], argv[3]);
02689    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
02690    return RESULT_SUCCESS;
02691 }
02692 
02693 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02694 {
02695    int num_deleted;
02696 
02697    if ((argc < 3) || (argc > 4)) {
02698       return RESULT_SHOWUSAGE;
02699    }
02700    if (argc == 4) {
02701       num_deleted = ast_db_deltree(argv[2], argv[3]);
02702    } else {
02703       num_deleted = ast_db_deltree(argv[2], NULL);
02704    }
02705 
02706    ast_agi_send(agi->fd, chan, "200 result=%c\n", num_deleted > 0 ? '0' : '1');
02707    return RESULT_SUCCESS;
02708 }
02709 
02710 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02711 {
02712    switch (cmd) {
02713    case CLI_INIT:
02714       e->command = "agi set debug [on|off]";
02715       e->usage =
02716          "Usage: agi set debug [on|off]\n"
02717          "       Enables/disables dumping of AGI transactions for\n"
02718          "       debugging purposes.\n";
02719       return NULL;
02720 
02721    case CLI_GENERATE:
02722       return NULL;
02723    }
02724 
02725    if (a->argc != e->args)
02726       return CLI_SHOWUSAGE;
02727 
02728    if (strncasecmp(a->argv[3], "off", 3) == 0) {
02729       agidebug = 0;
02730    } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
02731       agidebug = 1;
02732    } else {
02733       return CLI_SHOWUSAGE;
02734    }
02735    ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
02736    return CLI_SUCCESS;
02737 }
02738 
02739 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, const char * const argv[])
02740 {
02741    ast_agi_send(agi->fd, chan, "200 result=0\n");
02742    return RESULT_SUCCESS;
02743 }
02744 
02745 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02746 {
02747    if (argc < 3) {
02748       return RESULT_SHOWUSAGE;
02749    }
02750    if (!strncasecmp(argv[2], "on", 2))
02751       ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
02752    else if (!strncasecmp(argv[2], "off", 3))
02753       ast_moh_stop(chan);
02754    ast_agi_send(agi->fd, chan, "200 result=0\n");
02755    return RESULT_SUCCESS;
02756 }
02757 
02758 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02759 {
02760    /* If a structure already exists, return an error */
02761         if (agi->speech) {
02762       ast_agi_send(agi->fd, chan, "200 result=0\n");
02763       return RESULT_SUCCESS;
02764    }
02765 
02766    if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
02767       ast_agi_send(agi->fd, chan, "200 result=1\n");
02768    else
02769       ast_agi_send(agi->fd, chan, "200 result=0\n");
02770 
02771    return RESULT_SUCCESS;
02772 }
02773 
02774 static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02775 {
02776    /* Check for minimum arguments */
02777    if (argc != 4)
02778       return RESULT_SHOWUSAGE;
02779 
02780    /* Check to make sure speech structure exists */
02781    if (!agi->speech) {
02782       ast_agi_send(agi->fd, chan, "200 result=0\n");
02783       return RESULT_SUCCESS;
02784    }
02785 
02786    ast_speech_change(agi->speech, argv[2], argv[3]);
02787    ast_agi_send(agi->fd, chan, "200 result=1\n");
02788 
02789    return RESULT_SUCCESS;
02790 }
02791 
02792 static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02793 {
02794    if (agi->speech) {
02795       ast_speech_destroy(agi->speech);
02796       agi->speech = NULL;
02797       ast_agi_send(agi->fd, chan, "200 result=1\n");
02798    } else {
02799       ast_agi_send(agi->fd, chan, "200 result=0\n");
02800    }
02801 
02802    return RESULT_SUCCESS;
02803 }
02804 
02805 static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02806 {
02807    if (argc != 5)
02808       return RESULT_SHOWUSAGE;
02809 
02810    if (!agi->speech) {
02811       ast_agi_send(agi->fd, chan, "200 result=0\n");
02812       return RESULT_SUCCESS;
02813    }
02814 
02815    if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
02816       ast_agi_send(agi->fd, chan, "200 result=0\n");
02817    else
02818       ast_agi_send(agi->fd, chan, "200 result=1\n");
02819 
02820    return RESULT_SUCCESS;
02821 }
02822 
02823 static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02824 {
02825    if (argc != 4)
02826       return RESULT_SHOWUSAGE;
02827 
02828    if (!agi->speech) {
02829       ast_agi_send(agi->fd, chan, "200 result=0\n");
02830       return RESULT_SUCCESS;
02831    }
02832 
02833    if (ast_speech_grammar_unload(agi->speech, argv[3]))
02834       ast_agi_send(agi->fd, chan, "200 result=0\n");
02835    else
02836       ast_agi_send(agi->fd, chan, "200 result=1\n");
02837 
02838    return RESULT_SUCCESS;
02839 }
02840 
02841 static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02842 {
02843    if (argc != 4)
02844       return RESULT_SHOWUSAGE;
02845 
02846    if (!agi->speech) {
02847       ast_agi_send(agi->fd, chan, "200 result=0\n");
02848       return RESULT_SUCCESS;
02849    }
02850 
02851    if (ast_speech_grammar_activate(agi->speech, argv[3]))
02852       ast_agi_send(agi->fd, chan, "200 result=0\n");
02853    else
02854       ast_agi_send(agi->fd, chan, "200 result=1\n");
02855 
02856    return RESULT_SUCCESS;
02857 }
02858 
02859 static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02860 {
02861    if (argc != 4)
02862       return RESULT_SHOWUSAGE;
02863 
02864    if (!agi->speech) {
02865       ast_agi_send(agi->fd, chan, "200 result=0\n");
02866       return RESULT_SUCCESS;
02867    }
02868 
02869    if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
02870       ast_agi_send(agi->fd, chan, "200 result=0\n");
02871    else
02872       ast_agi_send(agi->fd, chan, "200 result=1\n");
02873 
02874    return RESULT_SUCCESS;
02875 }
02876 
02877 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
02878 {
02879    struct ast_filestream *fs = NULL;
02880 
02881    if (!(fs = ast_openstream(chan, filename, preflang)))
02882       return -1;
02883 
02884    if (offset)
02885       ast_seekstream(fs, offset, SEEK_SET);
02886 
02887    if (ast_applystream(chan, fs))
02888       return -1;
02889 
02890    if (ast_playstream(fs))
02891       return -1;
02892 
02893    return 0;
02894 }
02895 
02896 static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02897 {
02898    struct ast_speech *speech = agi->speech;
02899    const char *prompt;
02900    char dtmf = 0, tmp[4096] = "", *buf = tmp;
02901    int timeout = 0, offset = 0, res = 0, i = 0;
02902    long current_offset = 0;
02903    const char *reason = NULL;
02904    struct ast_frame *fr = NULL;
02905    struct ast_speech_result *result = NULL;
02906    size_t left = sizeof(tmp);
02907    time_t start = 0, current;
02908 
02909    if (argc < 4)
02910       return RESULT_SHOWUSAGE;
02911 
02912    if (!speech) {
02913       ast_agi_send(agi->fd, chan, "200 result=0\n");
02914       return RESULT_SUCCESS;
02915    }
02916 
02917    prompt = argv[2];
02918    timeout = atoi(argv[3]);
02919 
02920    /* If offset is specified then convert from text to integer */
02921    if (argc == 5)
02922       offset = atoi(argv[4]);
02923 
02924    /* We want frames coming in signed linear */
02925    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
02926       ast_agi_send(agi->fd, chan, "200 result=0\n");
02927       return RESULT_SUCCESS;
02928    }
02929 
02930    /* Setup speech structure */
02931    if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
02932       ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
02933       ast_speech_start(speech);
02934    }
02935 
02936    /* Start playing prompt */
02937    speech_streamfile(chan, prompt, chan->language, offset);
02938 
02939    /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
02940    while (ast_strlen_zero(reason)) {
02941       /* Run scheduled items */
02942                 ast_sched_runq(chan->sched);
02943 
02944       /* See maximum time of waiting */
02945       if ((res = ast_sched_wait(chan->sched)) < 0)
02946          res = 1000;
02947 
02948       /* Wait for frame */
02949       if (ast_waitfor(chan, res) > 0) {
02950          if (!(fr = ast_read(chan))) {
02951             reason = "hangup";
02952             break;
02953          }
02954       }
02955 
02956       /* Perform timeout check */
02957       if ((timeout > 0) && (start > 0)) {
02958          time(&current);
02959          if ((current - start) >= timeout) {
02960             reason = "timeout";
02961             if (fr)
02962                ast_frfree(fr);
02963             break;
02964          }
02965       }
02966 
02967       /* Check the speech structure for any changes */
02968       ast_mutex_lock(&speech->lock);
02969 
02970       /* See if we need to quiet the audio stream playback */
02971       if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
02972          current_offset = ast_tellstream(chan->stream);
02973          ast_stopstream(chan);
02974          ast_clear_flag(speech, AST_SPEECH_QUIET);
02975       }
02976 
02977       /* Check each state */
02978       switch (speech->state) {
02979       case AST_SPEECH_STATE_READY:
02980          /* If the stream is done, start timeout calculation */
02981          if ((timeout > 0) && start == 0 && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
02982             ast_stopstream(chan);
02983             time(&start);
02984          }
02985          /* Write audio frame data into speech engine if possible */
02986          if (fr && fr->frametype == AST_FRAME_VOICE)
02987             ast_speech_write(speech, fr->data.ptr, fr->datalen);
02988          break;
02989       case AST_SPEECH_STATE_WAIT:
02990          /* Cue waiting sound if not already playing */
02991          if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
02992             ast_stopstream(chan);
02993             /* If a processing sound exists, or is not none - play it */
02994             if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
02995                speech_streamfile(chan, speech->processing_sound, chan->language, 0);
02996          }
02997          break;
02998       case AST_SPEECH_STATE_DONE:
02999          /* Get the results */
03000          speech->results = ast_speech_results_get(speech);
03001          /* Change state to not ready */
03002          ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
03003          reason = "speech";
03004          break;
03005       default:
03006          break;
03007       }
03008       ast_mutex_unlock(&speech->lock);
03009 
03010       /* Check frame for DTMF or hangup */
03011       if (fr) {
03012          if (fr->frametype == AST_FRAME_DTMF) {
03013             reason = "dtmf";
03014             dtmf = fr->subclass.integer;
03015          } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_HANGUP) {
03016             reason = "hangup";
03017          }
03018          ast_frfree(fr);
03019       }
03020    }
03021 
03022    if (!strcasecmp(reason, "speech")) {
03023       /* Build string containing speech results */
03024                 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
03025          /* Build result string */
03026          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);
03027                         /* Increment result count */
03028          i++;
03029       }
03030                 /* Print out */
03031       ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
03032    } else if (!strcasecmp(reason, "dtmf")) {
03033       ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
03034    } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
03035       ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
03036    } else {
03037       ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
03038    }
03039 
03040    return RESULT_SUCCESS;
03041 }
03042 
03043 /*!
03044  * \brief AGI commands list
03045  */
03046 static struct agi_command commands[] = {
03047    { { "answer", NULL }, handle_answer, NULL, NULL, 0 },
03048    { { "asyncagi", "break", NULL }, handle_asyncagi_break, NULL, NULL, 1 },
03049    { { "channel", "status", NULL }, handle_channelstatus, NULL, NULL, 0 },
03050    { { "database", "del", NULL }, handle_dbdel, NULL, NULL, 1 },
03051    { { "database", "deltree", NULL }, handle_dbdeltree, NULL, NULL, 1 },
03052    { { "database", "get", NULL }, handle_dbget, NULL, NULL, 1 },
03053    { { "database", "put", NULL }, handle_dbput, NULL, NULL, 1 },
03054    { { "exec", NULL }, handle_exec, NULL, NULL, 1 },
03055    { { "get", "data", NULL }, handle_getdata, NULL, NULL, 0 },
03056    { { "get", "full", "variable", NULL }, handle_getvariablefull, NULL, NULL, 1 },
03057    { { "get", "option", NULL }, handle_getoption, NULL, NULL, 0 },
03058    { { "get", "variable", NULL }, handle_getvariable, NULL, NULL, 1 },
03059    { { "hangup", NULL }, handle_hangup, NULL, NULL, 0 },
03060    { { "noop", NULL }, handle_noop, NULL, NULL, 1 },
03061    { { "receive", "char", NULL }, handle_recvchar, NULL, NULL, 0 },
03062    { { "receive", "text", NULL }, handle_recvtext, NULL, NULL, 0 },
03063    { { "record", "file", NULL }, handle_recordfile, NULL, NULL, 0 }, 
03064    { { "say", "alpha", NULL }, handle_sayalpha, NULL, NULL, 0},
03065    { { "say", "digits", NULL }, handle_saydigits, NULL, NULL, 0 },
03066    { { "say", "number", NULL }, handle_saynumber, NULL, NULL, 0 },
03067    { { "say", "phonetic", NULL }, handle_sayphonetic, NULL, NULL, 0}, 
03068    { { "say", "date", NULL }, handle_saydate, NULL, NULL, 0}, 
03069    { { "say", "time", NULL }, handle_saytime, NULL, NULL, 0}, 
03070    { { "say", "datetime", NULL }, handle_saydatetime, NULL, NULL, 0},
03071    { { "send", "image", NULL }, handle_sendimage, NULL, NULL, 0}, 
03072    { { "send", "text", NULL }, handle_sendtext, NULL, NULL, 0},
03073    { { "set", "autohangup", NULL }, handle_autohangup, NULL, NULL, 0},
03074    { { "set", "callerid", NULL }, handle_setcallerid, NULL, NULL, 0},
03075    { { "set", "context", NULL }, handle_setcontext, NULL, NULL, 0},
03076    { { "set", "extension", NULL }, handle_setextension, NULL, NULL, 0},
03077    { { "set", "music", NULL }, handle_setmusic, NULL, NULL, 0 },
03078    { { "set", "priority", NULL }, handle_setpriority, NULL, NULL, 0 },
03079    { { "set", "variable", NULL }, handle_setvariable, NULL, NULL, 1 },
03080    { { "stream", "file", NULL }, handle_streamfile, NULL, NULL, 0 },
03081    { { "control", "stream", "file", NULL }, handle_controlstreamfile, NULL, NULL, 0 },
03082    { { "tdd", "mode", NULL }, handle_tddmode, NULL, NULL, 0 },
03083    { { "verbose", NULL }, handle_verbose, NULL, NULL, 1 },
03084    { { "wait", "for", "digit", NULL }, handle_waitfordigit, NULL, NULL, 0 },
03085    { { "speech", "create", NULL }, handle_speechcreate, NULL, NULL, 0 },
03086    { { "speech", "set", NULL }, handle_speechset, NULL, NULL, 0 },
03087    { { "speech", "destroy", NULL }, handle_speechdestroy, NULL, NULL, 1 },
03088    { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, NULL, NULL, 0 },
03089    { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, NULL, NULL, 1 },
03090    { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, NULL, NULL, 0 },
03091    { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, NULL, NULL, 0 },
03092    { { "speech", "recognize", NULL }, handle_speechrecognize, NULL, NULL, 0 },
03093 };
03094 
03095 static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
03096 
03097 static char *help_workhorse(int fd, const char * const match[])
03098 {
03099    char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
03100    struct agi_command *e;
03101 
03102    if (match)
03103       ast_join(matchstr, sizeof(matchstr), match);
03104 
03105    ast_cli(fd, "%5.5s %30.30s   %s\n","Dead","Command","Description");
03106    AST_RWLIST_RDLOCK(&agi_commands);
03107    AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
03108       if (!e->cmda[0])
03109          break;
03110       /* Hide commands that start with '_' */
03111       if ((e->cmda[0])[0] == '_')
03112          continue;
03113       ast_join(fullcmd, sizeof(fullcmd), e->cmda);
03114       if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
03115          continue;
03116       ast_cli(fd, "%5.5s %30.30s   %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
03117    }
03118    AST_RWLIST_UNLOCK(&agi_commands);
03119 
03120    return CLI_SUCCESS;
03121 }
03122 
03123 int AST_OPTIONAL_API_NAME(ast_agi_register)(struct ast_module *mod, agi_command *cmd)
03124 {
03125    char fullcmd[MAX_CMD_LEN];
03126 
03127    ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
03128 
03129    if (!find_command(cmd->cmda, 1)) {
03130       *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
03131       if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
03132 #ifdef AST_XML_DOCS
03133          *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd, NULL);
03134          *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd, NULL);
03135          *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd, NULL);
03136          *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd, NULL);
03137          *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
03138 #endif
03139 #ifndef HAVE_NULLSAFE_PRINTF
03140          if (!cmd->summary) {
03141             *((char **) &cmd->summary) = ast_strdup("");
03142          }
03143          if (!cmd->usage) {
03144             *((char **) &cmd->usage) = ast_strdup("");
03145          }
03146          if (!cmd->syntax) {
03147             *((char **) &cmd->syntax) = ast_strdup("");
03148          }
03149          if (!cmd->seealso) {
03150             *((char **) &cmd->seealso) = ast_strdup("");
03151          }
03152 #endif
03153       }
03154 
03155       cmd->mod = mod;
03156       AST_RWLIST_WRLOCK(&agi_commands);
03157       AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
03158       AST_RWLIST_UNLOCK(&agi_commands);
03159       if (mod != ast_module_info->self)
03160          ast_module_ref(ast_module_info->self);
03161       ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
03162       return 1;
03163    } else {
03164       ast_log(LOG_WARNING, "Command already registered!\n");
03165       return 0;
03166    }
03167 }
03168 
03169 int AST_OPTIONAL_API_NAME(ast_agi_unregister)(struct ast_module *mod, agi_command *cmd)
03170 {
03171    struct agi_command *e;
03172    int unregistered = 0;
03173    char fullcmd[MAX_CMD_LEN];
03174 
03175    ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
03176 
03177    AST_RWLIST_WRLOCK(&agi_commands);
03178    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
03179       if (cmd == e) {
03180          AST_RWLIST_REMOVE_CURRENT(list);
03181          if (mod != ast_module_info->self)
03182             ast_module_unref(ast_module_info->self);
03183 #ifdef AST_XML_DOCS
03184          if (e->docsrc == AST_XML_DOC) {
03185             ast_free((char *) e->summary);
03186             ast_free((char *) e->usage);
03187             ast_free((char *) e->syntax);
03188             ast_free((char *) e->seealso);
03189             *((char **) &e->summary) = NULL;
03190             *((char **) &e->usage) = NULL;
03191             *((char **) &e->syntax) = NULL;
03192             *((char **) &e->seealso) = NULL;
03193          }
03194 #endif
03195          unregistered=1;
03196          break;
03197       }
03198    }
03199    AST_RWLIST_TRAVERSE_SAFE_END;
03200    AST_RWLIST_UNLOCK(&agi_commands);
03201    if (unregistered)
03202       ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
03203    else
03204       ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
03205    return unregistered;
03206 }
03207 
03208 int AST_OPTIONAL_API_NAME(ast_agi_register_multiple)(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
03209 {
03210    unsigned int i, x = 0;
03211 
03212    for (i = 0; i < len; i++) {
03213       if (ast_agi_register(mod, cmd + i) == 1) {
03214          x++;
03215          continue;
03216       }
03217 
03218       /* registration failed, unregister everything
03219          that had been registered up to that point
03220       */
03221       for (; x > 0; x--) {
03222          /* we are intentionally ignoring the
03223             result of ast_agi_unregister() here,
03224             but it should be safe to do so since
03225             we just registered these commands and
03226             the only possible way for unregistration
03227             to fail is if the command is not
03228             registered
03229          */
03230          (void) ast_agi_unregister(mod, cmd + x - 1);
03231       }
03232       return -1;
03233    }
03234 
03235    return 0;
03236 }
03237 
03238 int AST_OPTIONAL_API_NAME(ast_agi_unregister_multiple)(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
03239 {
03240    unsigned int i;
03241    int res = 0;
03242 
03243    for (i = 0; i < len; i++) {
03244       /* remember whether any of the unregistration
03245          attempts failed... there is no recourse if
03246          any of them do
03247       */
03248       res |= ast_agi_unregister(mod, cmd + i);
03249    }
03250 
03251    return res;
03252 }
03253 
03254 static agi_command *find_command(const char * const cmds[], int exact)
03255 {
03256    int y, match;
03257    struct agi_command *e;
03258 
03259    AST_RWLIST_RDLOCK(&agi_commands);
03260    AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
03261       if (!e->cmda[0])
03262          break;
03263       /* start optimistic */
03264       match = 1;
03265       for (y = 0; match && cmds[y]; y++) {
03266          /* If there are no more words in the command (and we're looking for
03267             an exact match) or there is a difference between the two words,
03268             then this is not a match */
03269          if (!e->cmda[y] && !exact)
03270             break;
03271          /* don't segfault if the next part of a command doesn't exist */
03272          if (!e->cmda[y]) {
03273             AST_RWLIST_UNLOCK(&agi_commands);
03274             return NULL;
03275          }
03276          if (strcasecmp(e->cmda[y], cmds[y]))
03277             match = 0;
03278       }
03279       /* If more words are needed to complete the command then this is not
03280          a candidate (unless we're looking for a really inexact answer  */
03281       if ((exact > -1) && e->cmda[y])
03282          match = 0;
03283       if (match) {
03284          AST_RWLIST_UNLOCK(&agi_commands);
03285          return e;
03286       }
03287    }
03288    AST_RWLIST_UNLOCK(&agi_commands);
03289    return NULL;
03290 }
03291 
03292 static int parse_args(char *s, int *max, const char *argv[])
03293 {
03294    int x = 0, quoted = 0, escaped = 0, whitespace = 1;
03295    char *cur;
03296 
03297    cur = s;
03298    while(*s) {
03299       switch(*s) {
03300       case '"':
03301          /* If it's escaped, put a literal quote */
03302          if (escaped)
03303             goto normal;
03304          else
03305             quoted = !quoted;
03306          if (quoted && whitespace) {
03307             /* If we're starting a quote, coming off white space start a new word, too */
03308             argv[x++] = cur;
03309             whitespace=0;
03310          }
03311          escaped = 0;
03312       break;
03313       case ' ':
03314       case '\t':
03315          if (!quoted && !escaped) {
03316             /* If we're not quoted, mark this as whitespace, and
03317                end the previous argument */
03318             whitespace = 1;
03319             *(cur++) = '\0';
03320          } else
03321             /* Otherwise, just treat it as anything else */
03322             goto normal;
03323          break;
03324       case '\\':
03325          /* If we're escaped, print a literal, otherwise enable escaping */
03326          if (escaped) {
03327             goto normal;
03328          } else {
03329             escaped=1;
03330          }
03331          break;
03332       default:
03333 normal:
03334          if (whitespace) {
03335             if (x >= MAX_ARGS -1) {
03336                ast_log(LOG_WARNING, "Too many arguments, truncating\n");
03337                break;
03338             }
03339             /* Coming off of whitespace, start the next argument */
03340             argv[x++] = cur;
03341             whitespace=0;
03342          }
03343          *(cur++) = *s;
03344          escaped=0;
03345       }
03346       s++;
03347    }
03348    /* Null terminate */
03349    *(cur++) = '\0';
03350    argv[x] = NULL;
03351    *max = x;
03352    return 0;
03353 }
03354 
03355 static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
03356 {
03357    const char *argv[MAX_ARGS];
03358    int argc = MAX_ARGS;
03359    int res;
03360    agi_command *c;
03361    const char *ami_res;
03362    char *ami_cmd = ast_strdupa(buf);
03363    int command_id = ast_random();
03364    int resultcode;
03365 
03366    manager_event(EVENT_FLAG_AGI, "AGIExec",
03367          "SubEvent: Start\r\n"
03368          "Channel: %s\r\n"
03369          "CommandId: %d\r\n"
03370          "Command: %s\r\n", chan->name, command_id, ami_cmd);
03371    parse_args(buf, &argc, argv);
03372    c = find_command(argv, 0);
03373    if (c && (!dead || (dead && c->dead))) {
03374       /* if this command wasn't registered by res_agi, be sure to usecount
03375       the module we are using */
03376       if (c->mod != ast_module_info->self)
03377          ast_module_ref(c->mod);
03378       /* If the AGI command being executed is an actual application (using agi exec)
03379       the app field will be updated in pbx_exec via handle_exec */
03380       if (chan->cdr && !ast_check_hangup(chan) && strcasecmp(argv[0], "EXEC"))
03381          ast_cdr_setapp(chan->cdr, "AGI", buf);
03382 
03383       res = c->handler(chan, agi, argc, argv);
03384       if (c->mod != ast_module_info->self)
03385          ast_module_unref(c->mod);
03386       switch (res) {
03387       case RESULT_SHOWUSAGE:
03388          ami_res = "Usage";
03389          resultcode = 520;
03390          break;
03391       case RESULT_FAILURE:
03392          ami_res = "Failure";
03393          resultcode = -1;
03394          break;
03395       case ASYNC_AGI_BREAK:
03396       case RESULT_SUCCESS:
03397          ami_res = "Success";
03398          resultcode = 200;
03399          break;
03400       default:
03401          ami_res = "Unknown Result";
03402          resultcode = 200;
03403          break;
03404       }
03405       manager_event(EVENT_FLAG_AGI, "AGIExec",
03406             "SubEvent: End\r\n"
03407             "Channel: %s\r\n"
03408             "CommandId: %d\r\n"
03409             "Command: %s\r\n"
03410             "ResultCode: %d\r\n"
03411             "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
03412       switch (res) {
03413       case RESULT_SHOWUSAGE:
03414          if (ast_strlen_zero(c->usage)) {
03415             ast_agi_send(agi->fd, chan, "520 Invalid command syntax.  Proper usage not available.\n");
03416          } else {
03417             ast_agi_send(agi->fd, chan, "520-Invalid command syntax.  Proper usage follows:\n");
03418             ast_agi_send(agi->fd, chan, "%s", c->usage);
03419             ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
03420          }
03421          break;
03422       case ASYNC_AGI_BREAK:
03423          return AGI_RESULT_SUCCESS_ASYNC;
03424       case RESULT_FAILURE:
03425          /* The RESULT_FAILURE code is usually because the channel hungup. */
03426          return AGI_RESULT_FAILURE;
03427       default:
03428          break;
03429       }
03430    } else if (c) {
03431       ast_agi_send(agi->fd, chan, "511 Command Not Permitted on a dead channel\n");
03432       manager_event(EVENT_FLAG_AGI, "AGIExec",
03433             "SubEvent: End\r\n"
03434             "Channel: %s\r\n"
03435             "CommandId: %d\r\n"
03436             "Command: %s\r\n"
03437             "ResultCode: 511\r\n"
03438             "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
03439    } else {
03440       ast_agi_send(agi->fd, chan, "510 Invalid or unknown command\n");
03441       manager_event(EVENT_FLAG_AGI, "AGIExec",
03442             "SubEvent: End\r\n"
03443             "Channel: %s\r\n"
03444             "CommandId: %d\r\n"
03445             "Command: %s\r\n"
03446             "ResultCode: 510\r\n"
03447             "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
03448    }
03449    return AGI_RESULT_SUCCESS;
03450 }
03451 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
03452 {
03453    struct ast_channel *c;
03454    int outfd;
03455    int ms;
03456    int needhup = 0;
03457    enum agi_result returnstatus = AGI_RESULT_SUCCESS;
03458    struct ast_frame *f;
03459    char buf[AGI_BUF_LEN];
03460    char *res = NULL;
03461    FILE *readf;
03462    /* how many times we'll retry if ast_waitfor_nandfs will return without either
03463      channel or file descriptor in case select is interrupted by a system call (EINTR) */
03464    int retry = AGI_NANDFS_RETRY;
03465    int send_sighup;
03466    const char *sighup_str;
03467    
03468    ast_channel_lock(chan);
03469    sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
03470    send_sighup = ast_strlen_zero(sighup_str) || !ast_false(sighup_str);
03471    ast_channel_unlock(chan);
03472 
03473    if (!(readf = fdopen(agi->ctrl, "r"))) {
03474       ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
03475       if (send_sighup && pid > -1)
03476          kill(pid, SIGHUP);
03477       close(agi->ctrl);
03478       return AGI_RESULT_FAILURE;
03479    }
03480    
03481    setlinebuf(readf);
03482    setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
03483    for (;;) {
03484       if (needhup) {
03485          needhup = 0;
03486          dead = 1;
03487          if (send_sighup) {
03488             if (pid > -1) {
03489                kill(pid, SIGHUP);
03490             } else if (agi->fast) {
03491                ast_agi_send(agi->fd, chan, "HANGUP\n");
03492             }
03493          }
03494       }
03495       ms = -1;
03496       if (dead) {
03497          c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
03498       } else if (!ast_check_hangup(chan)) {
03499          c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
03500       } else {
03501          /*
03502           * Read the channel control queue until it is dry so we can
03503           * switch to dead mode.
03504           */
03505          c = chan;
03506       }
03507       if (c) {
03508          retry = AGI_NANDFS_RETRY;
03509          /* Idle the channel until we get a command */
03510          f = ast_read(c);
03511          if (!f) {
03512             ast_debug(1, "%s hungup\n", chan->name);
03513             needhup = 1;
03514             if (!returnstatus) {
03515                returnstatus = AGI_RESULT_HANGUP;
03516             }
03517          } else {
03518             /* If it's voice, write it to the audio pipe */
03519             if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
03520                /* Write, ignoring errors */
03521                if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
03522                }
03523             }
03524             ast_frfree(f);
03525          }
03526       } else if (outfd > -1) {
03527          size_t len = sizeof(buf);
03528          size_t buflen = 0;
03529          enum agi_result cmd_status;
03530 
03531          retry = AGI_NANDFS_RETRY;
03532          buf[0] = '\0';
03533 
03534          while (len > 1) {
03535             res = fgets(buf + buflen, len, readf);
03536             if (feof(readf))
03537                break;
03538             if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
03539                break;
03540             if (res != NULL && !agi->fast)
03541                break;
03542             buflen = strlen(buf);
03543             if (buflen && buf[buflen - 1] == '\n')
03544                break;
03545             len = sizeof(buf) - buflen;
03546             if (agidebug)
03547                ast_verbose("AGI Rx << temp buffer %s - errno %s\nNo \\n received, checking again.\n", buf, strerror(errno));
03548          }
03549 
03550          if (!buf[0]) {
03551             /* Program terminated */
03552             ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
03553             if (pid > 0)
03554                waitpid(pid, status, 0);
03555             /* No need to kill the pid anymore, since they closed us */
03556             pid = -1;
03557             break;
03558          }
03559 
03560          /* Special case for inability to execute child process */
03561          if (*buf && strncasecmp(buf, "failure", 7) == 0) {
03562             returnstatus = AGI_RESULT_FAILURE;
03563             break;
03564          }
03565 
03566          /* get rid of trailing newline, if any */
03567          buflen = strlen(buf);
03568          if (buflen && buf[buflen - 1] == '\n') {
03569             buf[buflen - 1] = '\0';
03570          }
03571 
03572          if (agidebug)
03573             ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
03574          cmd_status = agi_handle_command(chan, agi, buf, dead);
03575          switch (cmd_status) {
03576          case AGI_RESULT_FAILURE:
03577             if (dead || !ast_check_hangup(chan)) {
03578                /* The failure was not because of a hangup. */
03579                returnstatus = AGI_RESULT_FAILURE;
03580             }
03581             break;
03582          default:
03583             break;
03584          }
03585       } else {
03586          if (--retry <= 0) {
03587             ast_log(LOG_WARNING, "No channel, no fd?\n");
03588             returnstatus = AGI_RESULT_FAILURE;
03589             break;
03590          }
03591       }
03592    }
03593    if (agi->speech) {
03594       ast_speech_destroy(agi->speech);
03595    }
03596    /* Notify process */
03597    if (send_sighup) {
03598       if (pid > -1) {
03599          if (kill(pid, SIGHUP)) {
03600             ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
03601          } else { /* Give the process a chance to die */
03602             usleep(1);
03603          }
03604          waitpid(pid, status, WNOHANG);
03605       } else if (agi->fast) {
03606          ast_agi_send(agi->fd, chan, "HANGUP\n");
03607       }
03608    }
03609    fclose(readf);
03610    return returnstatus;
03611 }
03612 
03613 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03614 {
03615    struct agi_command *command;
03616    char fullcmd[MAX_CMD_LEN];
03617    int error = 0;
03618 
03619    switch (cmd) {
03620    case CLI_INIT:
03621       e->command = "agi show commands [topic]";
03622       e->usage =
03623          "Usage: agi show commands [topic] <topic>\n"
03624          "       When called with a topic as an argument, displays usage\n"
03625          "       information on the given command.  If called without a\n"
03626          "       topic, it provides a list of AGI commands.\n";
03627       return NULL;
03628    case CLI_GENERATE:
03629       return NULL;
03630    }
03631    if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
03632       return CLI_SHOWUSAGE;
03633    if (a->argc > e->args - 1) {
03634       command = find_command(a->argv + e->args, 1);
03635       if (command) {
03636          char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL;
03637          char info[30 + MAX_CMD_LEN];              /* '-= Info about...' */
03638          char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS];  /* '-= Info about...' with colors */
03639          char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS];        /* [Syntax]\n with colors */
03640          char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS];       /* [Description]\n with colors */
03641          char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS];       /* [Runs Dead]\n with colors */
03642          char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS];      /* 'Yes' or 'No' with colors */
03643          char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS];    /* [See Also]\n with colors */
03644          char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS];        /* [Syntax]\n with colors */
03645          size_t synlen, desclen, seealsolen, stxlen;
03646 
03647          term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle));
03648          term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle));
03649          term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle));
03650          term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle));
03651          term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle));
03652          term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent));
03653 
03654          ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03655          snprintf(info, sizeof(info), "\n  -= Info about agi '%s' =- ", fullcmd);
03656          term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle));
03657 #ifdef AST_XML_DOCS
03658          if (command->docsrc == AST_XML_DOC) {
03659             synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
03660             description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
03661             seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
03662             if (!seealso || !description || !synopsis) {
03663                error = 1;
03664                goto return_cleanup;
03665             }
03666          } else
03667 #endif
03668          {
03669             synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03670             synopsis = ast_malloc(synlen);
03671 
03672             desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03673             description = ast_malloc(desclen);
03674 
03675             seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03676             seealso = ast_malloc(seealsolen);
03677 
03678             if (!synopsis || !description || !seealso) {
03679                error = 1;
03680                goto return_cleanup;
03681             }
03682             term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen);
03683             term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen);
03684             term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen);
03685          }
03686 
03687          stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03688          syntax = ast_malloc(stxlen);
03689          if (!syntax) {
03690             error = 1;
03691             goto return_cleanup;
03692          }
03693          term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen);
03694 
03695          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,
03696                desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
03697                seealsotitle, seealso);
03698 return_cleanup:
03699          ast_free(synopsis);
03700          ast_free(description);
03701          ast_free(syntax);
03702          ast_free(seealso);
03703       } else {
03704          if (find_command(a->argv + e->args, -1)) {
03705             return help_workhorse(a->fd, a->argv + e->args);
03706          } else {
03707             ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03708             ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
03709          }
03710       }
03711    } else {
03712       return help_workhorse(a->fd, NULL);
03713    }
03714    return (error ? CLI_FAILURE : CLI_SUCCESS);
03715 }
03716 
03717 /*! \brief Convert string to use HTML escaped characters
03718    \note Maybe this should be a generic function?
03719 */
03720 static void write_html_escaped(FILE *htmlfile, char *str)
03721 {
03722    char *cur = str;
03723 
03724    while(*cur) {
03725       switch (*cur) {
03726       case '<':
03727          fprintf(htmlfile, "%s", "&lt;");
03728          break;
03729       case '>':
03730          fprintf(htmlfile, "%s", "&gt;");
03731          break;
03732       case '&':
03733          fprintf(htmlfile, "%s", "&amp;");
03734          break;
03735       case '"':
03736          fprintf(htmlfile, "%s", "&quot;");
03737          break;
03738       default:
03739          fprintf(htmlfile, "%c", *cur);
03740          break;
03741       }
03742       cur++;
03743    }
03744 
03745    return;
03746 }
03747 
03748 static int write_htmldump(const char *filename)
03749 {
03750    struct agi_command *command;
03751    char fullcmd[MAX_CMD_LEN];
03752    FILE *htmlfile;
03753 
03754    if (!(htmlfile = fopen(filename, "wt")))
03755       return -1;
03756 
03757    fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
03758    fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
03759    fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
03760 
03761    AST_RWLIST_RDLOCK(&agi_commands);
03762    AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
03763       char *tempstr, *stringp;
03764 
03765       if (!command->cmda[0])  /* end ? */
03766          break;
03767       /* Hide commands that start with '_' */
03768       if ((command->cmda[0])[0] == '_')
03769          continue;
03770       ast_join(fullcmd, sizeof(fullcmd), command->cmda);
03771 
03772       fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
03773       fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
03774 #ifdef AST_XML_DOCS
03775       stringp = ast_xmldoc_printable(command->usage, 0);
03776 #else
03777       stringp = ast_strdup(command->usage);
03778 #endif
03779       tempstr = strsep(&stringp, "\n");
03780 
03781       fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
03782       write_html_escaped(htmlfile, tempstr);
03783       fprintf(htmlfile, "</TD></TR>\n");
03784       fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
03785 
03786       while ((tempstr = strsep(&stringp, "\n")) != NULL) {
03787          write_html_escaped(htmlfile, tempstr);
03788          fprintf(htmlfile, "<BR>\n");
03789       }
03790       fprintf(htmlfile, "</TD></TR>\n");
03791       fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
03792       ast_free(stringp);
03793    }
03794    AST_RWLIST_UNLOCK(&agi_commands);
03795    fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
03796    fclose(htmlfile);
03797    return 0;
03798 }
03799 
03800 static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03801 {
03802    switch (cmd) {
03803    case CLI_INIT:
03804       e->command = "agi dump html";
03805       e->usage =
03806          "Usage: agi dump html <filename>\n"
03807          "       Dumps the AGI command list in HTML format to the given\n"
03808          "       file.\n";
03809       return NULL;
03810    case CLI_GENERATE:
03811       return NULL;
03812    }
03813    if (a->argc != e->args + 1)
03814       return CLI_SHOWUSAGE;
03815 
03816    if (write_htmldump(a->argv[e->args]) < 0) {
03817       ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
03818       return CLI_SHOWUSAGE;
03819    }
03820    ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
03821    return CLI_SUCCESS;
03822 }
03823 
03824 static int agi_exec_full(struct ast_channel *chan, const char *data, int enhanced, int dead)
03825 {
03826    enum agi_result res;
03827    char *buf;
03828    int fds[2], efd = -1, pid = -1;
03829    AST_DECLARE_APP_ARGS(args,
03830       AST_APP_ARG(arg)[MAX_ARGS];
03831    );
03832    AGI agi;
03833 
03834    if (ast_strlen_zero(data)) {
03835       ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
03836       return -1;
03837    }
03838    if (dead)
03839       ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
03840    memset(&agi, 0, sizeof(agi));
03841    buf = ast_strdupa(data);
03842    AST_STANDARD_APP_ARGS(args, buf);
03843    args.argv[args.argc] = NULL;
03844 #if 0
03845     /* Answer if need be */
03846    if (chan->_state != AST_STATE_UP) {
03847       if (ast_answer(chan))
03848          return -1;
03849    }
03850 #endif
03851    res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
03852    /* Async AGI do not require run_agi(), so just proceed if normal AGI
03853       or Fast AGI are setup with success. */
03854    if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
03855       int status = 0;
03856       agi.fd = fds[1];
03857       agi.ctrl = fds[0];
03858       agi.audio = efd;
03859       agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
03860       res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
03861       /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
03862       if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
03863          res = AGI_RESULT_FAILURE;
03864       if (fds[1] != fds[0])
03865          close(fds[1]);
03866       if (efd > -1)
03867          close(efd);
03868    }
03869    ast_safe_fork_cleanup();
03870 
03871    switch (res) {
03872    case AGI_RESULT_SUCCESS:
03873    case AGI_RESULT_SUCCESS_FAST:
03874    case AGI_RESULT_SUCCESS_ASYNC:
03875       pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
03876       break;
03877    case AGI_RESULT_FAILURE:
03878       pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
03879       break;
03880    case AGI_RESULT_NOTFOUND:
03881       pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
03882       break;
03883    case AGI_RESULT_HANGUP:
03884       pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
03885       return -1;
03886    }
03887 
03888    return 0;
03889 }
03890 
03891 static int agi_exec(struct ast_channel *chan, const char *data)
03892 {
03893    if (!ast_check_hangup(chan))
03894       return agi_exec_full(chan, data, 0, 0);
03895    else
03896       return agi_exec_full(chan, data, 0, 1);
03897 }
03898 
03899 static int eagi_exec(struct ast_channel *chan, const char *data)
03900 {
03901    int readformat, res;
03902 
03903    if (ast_check_hangup(chan)) {
03904       ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
03905       return 0;
03906    }
03907    readformat = chan->readformat;
03908    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
03909       ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
03910       return -1;
03911    }
03912    res = agi_exec_full(chan, data, 1, 0);
03913    if (!res) {
03914       if (ast_set_read_format(chan, readformat)) {
03915          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
03916       }
03917    }
03918    return res;
03919 }
03920 
03921 static int deadagi_exec(struct ast_channel *chan, const char *data)
03922 {
03923    ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
03924    return agi_exec(chan, data);
03925 }
03926 
03927 static struct ast_cli_entry cli_agi[] = {
03928    AST_CLI_DEFINE(handle_cli_agi_add_cmd,   "Add AGI command to a channel in Async AGI"),
03929    AST_CLI_DEFINE(handle_cli_agi_debug,     "Enable/Disable AGI debugging"),
03930    AST_CLI_DEFINE(handle_cli_agi_show,      "List AGI commands or specific help"),
03931    AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format")
03932 };
03933 
03934 #ifdef TEST_FRAMEWORK
03935 AST_TEST_DEFINE(test_agi_null_docs)
03936 {
03937    int res = AST_TEST_PASS;
03938    struct agi_command noop_command =
03939       { { "testnoop", NULL }, handle_noop, NULL, NULL, 0 };
03940 
03941    switch (cmd) {
03942    case TEST_INIT:
03943       info->name = "null_agi_docs";
03944       info->category = "/res/agi/";
03945       info->summary = "AGI command with no documentation";
03946       info->description = "Test whether an AGI command with no documentation will crash Asterisk";
03947       return AST_TEST_NOT_RUN;
03948    case TEST_EXECUTE:
03949       break;
03950    }
03951 
03952    if (ast_agi_register(ast_module_info->self, &noop_command) == 0) {
03953       ast_test_status_update(test, "Unable to register testnoop command, because res_agi is not loaded.\n");
03954       return AST_TEST_NOT_RUN;
03955    }
03956 
03957 #ifndef HAVE_NULLSAFE_PRINTF
03958    /* Test for condition without actually crashing Asterisk */
03959    if (noop_command.usage == NULL) {
03960       ast_test_status_update(test, "AGI testnoop usage was not updated properly.\n");
03961       res = AST_TEST_FAIL;
03962    }
03963    if (noop_command.syntax == NULL) {
03964       ast_test_status_update(test, "AGI testnoop syntax was not updated properly.\n");
03965       res = AST_TEST_FAIL;
03966    }
03967 #endif
03968 
03969    ast_agi_unregister(ast_module_info->self, &noop_command);
03970    return res;
03971 }
03972 #endif
03973 
03974 static int unload_module(void)
03975 {
03976    ast_cli_unregister_multiple(cli_agi, ARRAY_LEN(cli_agi));
03977    /* we can safely ignore the result of ast_agi_unregister_multiple() here, since it cannot fail, as
03978       we know that these commands were registered by this module and are still registered
03979    */
03980    (void) ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
03981    ast_unregister_application(eapp);
03982    ast_unregister_application(deadapp);
03983    ast_manager_unregister("AGI");
03984    AST_TEST_UNREGISTER(test_agi_null_docs);
03985    return ast_unregister_application(app);
03986 }
03987 
03988 static int load_module(void)
03989 {
03990    ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi));
03991    /* we can safely ignore the result of ast_agi_register_multiple() here, since it cannot fail, as
03992       no other commands have been registered yet
03993    */
03994    (void) ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
03995    ast_register_application_xml(deadapp, deadagi_exec);
03996    ast_register_application_xml(eapp, eagi_exec);
03997    ast_manager_register_xml("AGI", EVENT_FLAG_AGI, action_add_agi_cmd);
03998    AST_TEST_REGISTER(test_agi_null_docs);
03999    return ast_register_application_xml(app, agi_exec);
04000 }
04001 
04002 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Asterisk Gateway Interface (AGI)",
04003       .load = load_module,
04004       .unload = unload_module,
04005       .load_pri = AST_MODPRI_APP_DEPEND,
04006       );

Generated on 27 Jan 2016 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1