Sat Feb 11 06:33:20 2012

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

Generated on Sat Feb 11 06:33:20 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6